Nuevos labs cada semana — Accede a todos desde 5€/mes

Nivel IntermedioCon cuenta

Open Redirect vía Backslash Bypass en redirect_url del Login OAuth

El validador del cliente comprueba //, : y /. El backslash pasa. Los navegadores lo normalizan a slash y la víctima acaba en evil.tld con la cookie de sesión activa.

Gorka El Bochi9 de mayo de 202612 min

Respuesta rápida

Una plataforma de IA conversacional validaba el parámetro redirect_url del login OAuth comprobando que empezara por /, no por // y no contuviera :. El backslash pasaba esos tres checks. El navegador normaliza /\evil.tld a //evil.tld → https://evil.tld, y el servidor emitía la redirección post-login al dominio del atacante con la cookie de sesión ya establecida.


1. Contexto — el flujo de redirect post-login

El endpoint https://main.target.tld/login aceptaba un parámetro redirect_url que indicaba a dónde enviar al usuario tras completar el login. Este parámetro se embebía en el estado OAuth (googleOauthState / appleOauthState) como el campo next_url. Después de que el proveedor OAuth (Google o Apple) completaba la autenticación y redirigía de vuelta, el servidor leía next_url del estado y emitía la redirección final.

El estado OAuth se podía ver en el __NEXT_DATA__ decodificando el base64 de googleOauthState:

json
{
  "csrf": "6d7f9f064956d71d4f89a20b987e589d",
  "platform": "web",
  "next_url": "/\\evil.tld",
  "current_url": "/login"
}

2. El bypass — backslash no filtrado

La validación vulnerable

El código de validación del redirect_url en cliente comprueba tres condiciones:

typescript
if (
  redirectUrl.startsWith("/") &&     // debe ser path relativo
  !redirectUrl.startsWith("//") &&   // bloquea protocol-relative URLs
  !redirectUrl.includes(":")         // bloquea javascript: y esquemas externos
)

Por qué el backslash lo bypassa

El input del atacante es /\evil.tld (URL-encoded como /%5Cevil.tld):

CheckResultadoMotivo
startsWith("/")✅ pasaEmpieza por /
!startsWith("//")✅ pasaEs /\, no //
!includes(":")✅ pasaNo hay dos puntos
ResultadoACEPTADOEl validador lo trata como path relativo

Pero los navegadores normalizan el backslash a slash según la URL spec:

bash
/\evil.tld  →  //evil.tld  →  https://evil.tld

El servidor embebe el valor sin normalizar en next_url del estado OAuth. Al emitir la redirección post-login, el navegador recibe /\evil.tld y lo resuelve como URL externa.


3. La URL de ataque

ini
https://main.target.tld/login?redirect_url=/%5Cevil.tld

%5C es la codificación URL del backslash \. Al decodificarse, el parámetro queda como /\evil.tld.


4. Flujo del ataque base

bash
Atacante envía link: target.tld/login?redirect_url=/%5Cevil.tld
   ↓
Víctima abre el link (página de login real)
   ↓
redirect_url pasa validación (/\ no es //)
   ↓
Servidor embebe next_url: "/\evil.tld" en googleOauthState
   ↓
Víctima hace click "Continue with Google" → autenticación
   ↓
OAuth callback con código válido
   ↓
Servidor lee next_url del estado → "/\evil.tld"
   ↓
Redirect a /\evil.tld (cookie de sesión ya establecida)
   ↓
Navegador normaliza /\ a // → https://evil.tld
   ↓
Víctima llega al dominio del atacante con sesión activa
<!-- PAYWALL -->

5. Cadena de escalación — Open Redirect vía Canvas + postMessage

En la escalación del reporte se documenta una segunda cadena que combina este open redirect con el handler openUrl del sistema de canvas de la plataforma, convirtiéndolo en un vector stored y zero-click.

Cómo funciona openUrl en el canvas

El canvas de un bot puede enviar un postMessage al parent con type: "openUrl". Normalmente, cuando la URL de destino es externa, la plataforma muestra al usuario un overlay de confirmación antes de abrir la URL. La función shouldAutoOpen decide si mostrar ese overlay o no.

El bypass del overlay

shouldAutoOpen whitelist el dominio principal como origen de confianza y omite el overlay de confirmación para URLs de ese dominio:

ini
openUrl → https://main.target.tld/login?redirect_url=/%5Cevil.tld
                ↓
shouldAutoOpen: hostname === "main.target.tld"true → window.open() sin confirmación
                ↓
La plataforma procesa el login con next_url = /\evil.tld
                ↓
Redirect a evil.tld

Como la URL que se pasa al handler es del dominio whitelisted, pasa como URL de confianza. El overlay no se muestra. La ventana se abre directamente y la cadena de redirect se ejecuta automáticamente.

Resultado de la cadena completa

  • El bot aparece en la homepage y sugerencias de la plataforma de forma orgánica.
  • El usuario hace click en el bot (comportamiento normal de la plataforma).
  • El canvas ejecuta el postMessage con openUrl.
  • shouldAutoOpen lo trata como URL de confianza → no hay overlay.
  • El redirect hacia el dominio externo se dispara sin ninguna confirmación adicional.

6. Comportamiento con usuario ya autenticado

Si el usuario ya tiene sesión activa, el endpoint de login no le pide credenciales — lo redirige directamente a next_url. Esto significa que el open redirect funciona también sobre usuarios ya logueados que abran el link, sin necesidad de pasar por el flujo OAuth.


7. Clasificación técnica

CampoValor
Tipo de vulnerabilidadOpen Redirect — Incomplete URL Validation (Backslash Normalization)
CWECWE-601 — URL Redirection to Untrusted Site
Endpoint afectadohttps://main.target.tld/login?redirect_url=
Parámetro vulnerableredirect_url → embebido en next_url del estado OAuth
Navegadores afectadosFirefox 149, Chrome 146 (normalización estándar)
Interacción requerida (base)Víctima abre el link y completa login
Interacción requerida (cadena canvas)Un click en el bot

8. Notas técnicas

  • La normalización de \ a / en paths de URL es comportamiento estándar del parser de URLs (WHATWG URL spec). No es específico de ningún navegador — todos los navegadores modernos lo hacen.
  • El validador del cliente comprueba // pero no \ — el fix es añadir !redirectUrl.includes("\\") al conjunto de checks.
  • La validación solo se aplica en el cliente. El servidor no re-valida next_url antes de emitir la redirección post-OAuth, que es donde ocurre el redirect real.
  • En la cadena de canvas, el bypass del overlay de confirmación es independiente del open redirect — es un fallo de lógica en el whitelist que no contempla que URLs en ese dominio puedan redirigir externamente.

Labs relacionados

Practica chains de open redirect, parser quirks (backslash, dot, @) y bypasses de validación URL: labs de Open Redirect.

Practica esto en un lab

Open Redirect

Resolver

Sigue aprendiendo · cuenta gratis

Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.

Crear cuenta

Artículos relacionados