Respuesta rápida
Hay bugs que no requieren fuzzing ni cadenas: solo leer lo que la app entrega al cliente. Una plataforma de productividad y notas inyectaba en su HTML un token de un CMS de terceros con permisos de lectura sobre todo el contenido de marketing — incluyendo URLs de descarga de templates de pago. Una sola petición HTTP autenticada, cero bypasses, $2.000 de bounty.
El objeto window.CONFIG
La aplicación afectada está construida en React (envuelta en Electron para escritorio). Como en la mayoría de SPAs, al cargar la página el servidor inyectaba un objeto de configuración global en el HTML:
window.CONFIG = {
googleCaptchaSiteKey: "...",
facebookPixelId: "...",
contentful: {
spaceId: "XXXXXXXXXXXXXX",
ACCESS_TOKEN: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" // esto no debería estar aquí
},
...
}
Este objeto era completamente visible en el código fuente de la página. Sin autenticación, sin herramientas especiales. Ctrl+U y está ahí.
Entre las claves de terceros que viajaban en este objeto había una de Contentful — el CMS que la plataforma usaba para gestionar contenido de marketing, incluyendo el marketplace de templates.
Qué permite una API key de Contentful expuesta
Contentful expone una API REST. Con spaceId + ACCESS_TOKEN se puede consultar cualquier contenido del espacio sin más restricciones que el propio token:
window.CONFIG en el HTML público
↓
Extraer spaceId + ACCESS_TOKEN
↓
GET /spaces/{SPACE_ID}/environments/master/content_types?access_token=TOKEN
↓
Enumerar todos los content types del espacio
↓
Identificar content type "template" con campos price y url
↓
GET entries filtradas por fields.price >= 100
↓
Lista completa de templates de pago con URL directa de descarga
Las peticiones concretas
Paso 1 — Enumerar content types disponibles:
GET https://cdn.contentful.com/spaces/{SPACE_ID}/environments/master/content_types
?access_token={ACCESS_TOKEN}
La respuesta devuelve todos los tipos de contenido definidos. Entre ellos: person, category, template.
Paso 2 — Filtrar templates con precio ≥ $100:
GET https://cdn.contentful.com/spaces/{SPACE_ID}/environments/master/entries
?access_token={ACCESS_TOKEN}
&content_type=template
&fields.price[gte]=100
La respuesta incluía para cada template: título, categoría, precio y URL directa de descarga, independientemente de si el template era de pago.
Sin ningún paso adicional. Sin exploit. Solo leer la respuesta de la API con credenciales que la propia aplicación entregaba.
Root cause
El token de Contentful debería ser una clave de solo backend: el servidor la usa para construir el contenido que sirve al cliente, nunca debería llegar al cliente directamente. Al incluirla en window.CONFIG, cualquier usuario podía hacer las mismas consultas que el servidor, sin restricciones.
Build / Deploy
↓ ACCESS_TOKEN inyectado en window.CONFIG
Navegador / cliente
↓ HTML público accesible sin autenticación
↓ Token visible en cualquier DevTools
API Contentful
↓ Sin restricción de origen ni scope
↓ Acceso de lectura a todo el espacio
Dónde buscar este patrón
window.CONFIG, window.__INITIAL_STATE__, window.__NEXT_DATA__, window.APP_CONFIG — son los nombres más comunes. Cualquier app React, Vue o Next.js que hidrate estado en el cliente es candidata.
Lo que buscar dentro:
- Claves de APIs de terceros: Contentful, Algolia, Sanity, Cloudinary, Firebase, Mapbox, Stripe (publishable vs secret key, ojo)...
- Tokens con permisos de lectura amplios sobre recursos que no deberían ser públicos.
- Parámetros internos que revelen estructura de datos, IDs, o endpoints no documentados.
El flujo es siempre el mismo: Ctrl+U o DevTools → buscar CONFIG, TOKEN, API_KEY, SECRET → evaluar qué permite hacer cada clave encontrada contra la API del servicio correspondiente.
Impacto
Descarga gratuita de cualquier template de pago del marketplace. En el caso concreto del reporte, templates con precios desde $100 hasta varios cientos. Acceso sin cuenta de pago, sin bypasses, con una sola petición HTTP autenticada con las credenciales que la propia app entregaba.
Reportado en mayo de 2024. Resuelto en menos de 24 horas. $2.000 de bounty.
Labs relacionados
Practica recon de tokens en código cliente y abuso de APIs de terceros mal restringidas: labs de Information Disclosure.
Practica esto en un lab
Information Disclosure
Sigue aprendiendo · cuenta gratis
Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.
Artículos relacionados
Information Disclosure — los 12 patrones que más se pagan
API keys en HTML, debug endpoints, error verbose, JS bundles con secretos, .git expuesto, headers leak. Cómo encontrarlo y por qué se cierra rápido y se paga.
IP leak vía GIF en chat — Client-Side Request Forgery + Information Disclosure
Una red social no validaba la URL del GIF enviado en el chat. Mandar un GIF revelaba IP, sistema operativo, modelo de teléfono y device ID de la víctima.
Acortador de URL como PII leak masivo — extracción de ~300 personas/hora
Códigos de baja entropía + sin rate limiting + ticket sin auth = enumeración de teléfonos, tarjetas (BIN+últimos 4) y compras de clientes reales.