Aikido

SvelteSpill : Une vulnérabilité de tromperie de cache dans SvelteKit + Vercel

Écrit par
Jorian Woltjer

SvelteKit est un framework JavaScript full-stack populaire, et Vercel est sa plateforme de déploiement la plus courante. Et si nous vous disions que toutes les applications construites avec cette combinaison étaient vulnérables aux attaquants lisant les réponses de n'importe quelle route d'autres utilisateurs connectés ?

Eh bien, c'est vrai. Ce vecteur d'attaque, appelé cache deception, est exactement ce qu'un de nos agents IA a trouvé et nous a signalé lors de nos tests d'Aikido Attack. Et bien que sceptiques au départ, nous avons retracé ses étapes et avons constaté que nous pouvions reproduire parfaitement la vulnérabilité. Nous avons rapidement informé Vercel, et la vulnérabilité a maintenant été automatiquement corrigée pour tous les utilisateurs.

Note : La faille peut être consultée dans la base de données Intel d'Aikido et porte le numéro CVE réservé : CVE-2026-27118. Nous avons également découvert une faille distincte permettant un déni de service dans une fonctionnalité expérimentale de SvelteKit. Celle-ci a également été divulguée et corrigée.

Résumé rapide

Le __pathname Le paramètre de requête dans l'adaptateur Vercel de SvelteKit peut outrepasser le chemin depuis n'importe où. Sur Vercel, chaque fichier sous /_app/immutable/ a des Cache-Control: en-têtes différents afin qu'il puisse être mis en cache. En le préfixant avec un faux chemin et en le réécrivant pour qu'il contienne du contenu sensible, la réponse sera mise en cache de force, permettant à un attaquant de la récupérer en visitant la même URL sans cookies.

URL de preuve de concept:

https://example.vercel.app/_app/immutable/x?__pathname=/api/session

Découverte

Nous allons raconter cette histoire du point de vue de l'agent de pentest IA qui a découvert la vulnérabilité, en partant du gadget initial jusqu'à l'exploitation complète, et nous aborderons quelques idées intéressantes en chemin. Adoptez votre robot intérieur et lançons-nous dans la recherche !

Si vous lisez le code source de SvelteKit, vous tomberez sur des « adaptateurs », qui sont les middlewares entre une plateforme d'hébergement comme Vercel et le framework SvelteKit. Cela permet d'appliquer des règles spéciales à la requête et à la réponse, nécessaires au fonctionnement interne de la plateforme. Vercel a implémenté ce qui suit dans serverless.js:

const DATA_SUFFIX = '/__data.json';

fetch(request) {
    // If this is an ISR request, the requested pathname is encoded
    // as a search parameter, so we need to extract it
    const url = new URL(request.url);
    let pathname = url.searchParams.get('__pathname');

    if (pathname) {
        // Optional routes' pathname replacements look like `/foo/$1/bar` which means we could end up with an url like /foo//bar
        pathname = pathname.replace(/\/+/g, '/');

        url.pathname = pathname + (url.pathname.endsWith(DATA_SUFFIX) ? DATA_SUFFIX : '');
        url.searchParams.delete('__pathname');

        request = new Request(url, request);
    }

    return server.respond(request, {
        getClientAddress() {
            return /** @type {string} */ (request.headers.get('x-forwarded-for'));
        }
    });
}

Nous pouvons lire « S'il s'agit d'une requête ISR, le chemin d'accès demandé est encodé comme paramètre de recherche. » Le code prend cette variable de chemin (provenant du ?__pathname= paramètre de requête) et réécrit le url.pathname avec elle. La requête ignore l'URL originale et utilise simplement ce __pathname à la place.

Mais il ne semble pas y avoir de vérifications concernant ces requêtes Incremental Static Regeneration (ISR), alors toutes les requêtes supportent-elles ce paramètre ?

La réponse est oui, et c'est exactement là que réside la vulnérabilité ! N'importe quel chemin peut être outrepassé par n'importe quel autre chemin avec juste un paramètre de requête. Un simple test comme /?__pathname=/404 afficherait en effet une erreur 404 au lieu de la page d'accueil.

Cela peut sembler être une fonctionnalité étrange. Pourquoi serait-ce dangereux ? Eh bien, ça ne l'est pas, jusqu'à ce que la mise en cache entre en jeu.

Empoisonnement de cache ?

Si nous pouvons réécrire n'importe quel chemin pour qu'il pointe vers n'importe quelle autre ressource, que se passe-t-il si cette ressource empoisonnée est mise en cache ? C'était aussi notre première idée. Si nous vérifions le code source de n'importe quelle application SvelteKit, vous verrez quelque chose comme :


import("./_app/immutable/entry/start.CLO1Dlt2.js"),	
import("./_app/immutable/entry/app.kQF6jJr8.js")

Le chemin /_app/immutable/entry/start.CLO1Dlt2.js renvoie du JavaScript à exécuter, et en regardant la réponse, Cache-Control: les en-têtes nous indiquent qu'il est bien mis en cache. C'est attendu pour les ressources statiques :

Age: 618
Cache-Control: public, immutable, max-age=31536000
X-Vercel-Cache: HIT

Si nous pouvions utiliser notre ?__pathname= paramètre pour réécrire la requête afin de pointer vers un chemin contrôlé par un attaquant, comme un téléchargement de fichier, et il serait toujours mis en cache sous le même simple /_app/immutable/entry/start.CLO1Dlt2.js chemin que chaque utilisateur charge, nous aurions une XSS sur chaque utilisateur. Voyons ce qui se passe lorsque nous ajoutons ce paramètre de requête à notre demande :

GET /_app/immutable/start.CLO1Dlt2.js?__pathname=/ HTTP/2
Host: example.vercel.app

Dans la réponse, nous recevons de bonnes et de mauvaises nouvelles des en-têtes :

Age: 935
Cache-Control: public, immutable, max-age=31536000
X-Vercel-Cache: HIT

Le Âge : a augmenté de la durée qu'il a fallu pour écrire le paragraphe ci-dessus, et le HIT signifie que avec notre paramètre de requête ajouté, la même entrée de cache est atteinte que celle que tout le monde charge. Mais en même temps, cela signifie que l'ancien contenu JavaScript est également renvoyé, et non le contenu de notre chemin réécrit. Si tel est le cas, pourrions-nous vider le cache et être les premiers à le demander afin que notre payload puisse être mis en cache à la place ?

Malheureusement non. La plateforme Vercel est plus complexe en raison de son architecture serverless, et elle n'atteint même pas le code de l'adaptateur pour une telle ressource statique. Ceci est dû au fait que les ressources statiques sont mises en cache et renvoyées à une couche supérieure, nous ne pourrons donc jamais les empoisonner.

Dans ce cas, Vercel est la seule plateforme vulnérable, nous ne pouvons donc pas trouver d'autres scénarios exploitables. Nous sommes arrivés à une impasse.

Cache Deception !

Passons au problème suivant avec la mise en cache web : la cache deception. Dans cette technique moins connue, un attaquant redirige une victime vers une page sensible qu'elle peut récupérer avec ses cookies. Si le cache stocke cette page sans tenir compte de l'utilisateur qui l'a demandée, l'attaquant peut ensuite visiter la même URL et voir les données privées de la victime à partir du cache. Le problème est que le cache enregistre les réponses uniquement en fonction de l'URL, ignorant que différents utilisateurs avec différents cookies de connexion devraient voir un contenu différent.

En appliquant cette idée à notre ?__pathname= gadget, nous pouvons faire en sorte que notre URL ressemble à elle pointe vers un chemin statique, mais pointe en réalité vers un contenu sensible. La couche de mise en cache peut se déclencher sur ce chemin d'apparence statique et ajouter des Cache-Control: headers explicites et écraser la réponse privée.

Bien que certains critères de cache soient documentés, notre enquête a révélé davantage de règles. Une que nous connaissons déjà : les chemins commençant par /_app/immutable/. Il s'avère que non seulement les fichiers statiques attendus sont cachables sous ce préfixe, mais aussi tout une réponse 200 OK. Pour éviter les assets déjà générés, nous pouvons initialement pointer vers un faux asset. Ensuite, le réécrire vers n'importe quel chemin sensible, disons /api/session:

https://example.vercel.app/_app/immutable/x?__pathname=/api/session

Et voici notre charge utile finale. Visiter ce lien en tant que victime connectée enverra une requête similaire à la suivante :

GET /_app/immutable/x?__pathname=/api/session HTTP/2
Host: example.vercel.app
Cookie: auth=...

L'adaptateur Vercel de SvelteKit réécrit le chemin d'accès en /api/session, et est géré par l'application. Le auth= cookie est vérifié, et leur jeton de session est renvoyé :

HTTP/2 200 OK
Age: 0
Cache-Control: public, immutable, max-age=31536000
...
Server: Vercel
X-Vercel-Cache: MISS
Content-Length: 16

{"token":"1337"}

Alors que l' Cache-Control: header dirait normalement max-age=0 pour ce endpoint, la couche de mise en cache de Vercel active de force la mise en cache en raison du /_app/immutable/ préfixe.

Une fois que l'attaquant sait qu'une victime a été redirigée, il peut demander la même URL lui-même, sans aucun cookie :

GET /_app/immutable/x?__pathname=/api/session HTTP/2
Host: example.vercel.app

Ils reçoivent la même réponse qu'un HIT maintenant, et peuvent lire le token de la victime.

HTTP/2 200 OK
Age: 22
Cache-Control: public, immutable, max-age=31536000
...
Server: Vercel
X-Vercel-Cache: HIT
Content-Length: 16

{"token":"1337"}

En utilisant des cache busters (chemins factices uniques) et en vérifiant après la redirection, cela aurait pu être exploité à grande échelle. Puisque cette vulnérabilité fait partie de la base SvelteKit, tout site web SvelteKit sur Vercel qui utilise des cookies pour l'authentification permettrait de récupérer des réponses arbitraires.

Les conséquences

Nous avons rapidement signalé le problème à Vercel, qui a proposé un correctif pour renvoyer de force un 404 sur tout /_app/immutable/ chemin, et pour supprimer le __pathname paramètre. Puisqu'ils contrôlent l'ensemble de leur plateforme, cela résout le problème automatiquement pour tous les utilisateurs, sans nécessiter de correctif manuel.

Une leçon majeure à retenir de cette vulnérabilité est que le caching est toujours délicat. Des règles simples, comme une correspondance de préfixe, peuvent être exploitées par des fonctionnalités de plateforme inattendues que vous n'avez même pas implémentées.

C'est pourquoi le pentest peut être si utile. Des problèmes comme celui-ci seraient difficiles à découvrir par le code seul, mais grâce à un déploiement réel, des règles cachées peuvent être trouvées et exploitées. L'AI pentest d'Aikido peut détecter automatiquement les attaques de cache poisoning et de cache deception, comme il a trouvé ce problème.

Points clés à retenir

  • Le 20 janvier 2026, le système d'AI pentest d'Aikido a signalé quelque chose d'intéressant dans les applications SvelteKit déployées sur Vercel. 
  • Nous avons confirmé qu'il s'agissait d'une vulnérabilité de cache deception affectant les configurations par défaut. 
  • Aucune mauvaise configuration requise. Juste SvelteKit + Vercel faisant ce qu'ils sont censés faire.
  • Impact : Les réponses authentifiées peuvent être mises en cache et exposées à d'autres utilisateurs.
  • Toute application SvelteKit exécutée sur Vercel avec des endpoints protégés peut être affectée.

Comment vérifier si vous êtes affecté

En utilisant Aikido :

Si vous êtes un utilisateur Aikido, consultez votre flux central. Vous pouvez voir la faille dans Aikido Intel ici. Conseil : Aikido réanalyse vos dépôts chaque nuit, mais nous vous recommandons également de déclencher une réanalyse complète.

Si vous n'êtes pas encore un utilisateur Aikido, créez un compte et connectez vos dépôts. Notre couverture propriétaire des malwares est incluse dans le plan gratuit (aucune carte de crédit requise).

L'AI pentest et le scanning de sécurité web d'Aikido détectent automatiquement les flux de cache deception et les comportements de réécriture non sécurisés.

Statut de la correction

Nous avons divulgué cela à Vercel le 21 janvier 2026.

Chronologie

  • 20 janvier 2026 : Aikido Security a identifié la vulnérabilité, a construit un PoC fonctionnel.
  • 21 janvier 2026 : Divulgation responsable à Vercel.
  • 23 janvier 2026 : Rapport trié.
  • 9 février 2026 : Vercel confirme le rapport et commence à travailler sur une correction.
  • 19 février 2026 : Vercel a corrigé la vulnérabilité pour tous les utilisateurs, et l'avis est publié (GHSA-9pq4-5hcf-288c). La faille peut être consultée dans la base de données Intel d'Aikido et porte le numéro CVE réservé : CVE-2026-27118.

Nous avons également découvert une faille distincte permettant un déni de service dans une fonctionnalité expérimentale de SvelteKit. Celle-ci a également été divulguée et corrigée.

Partager :

https://www.aikido.dev/blog/sveltespill-cache-deception-sveltekit-vercel

Abonnez-vous pour les actualités sur les menaces.

Démarrez gratuitement dès aujourd'hui.

Commencer gratuitement
Sans carte bancaire
4,7/5
Fatigué des faux positifs ?
Essayez Aikido, comme 100 000 autres.
Commencez maintenant
Obtenez une démonstration personnalisée

Approuvé par plus de 100 000 équipes

Réserver maintenant
Analysez votre application à la recherche d'IDORs et de chemins d'attaque réels

Approuvé par plus de 100 000 équipes

Démarrer l'analyse
Découvrez comment le pentest IA teste votre application

Approuvé par plus de 100 000 équipes

Démarrer les tests

Sécurisez votre environnement dès maintenant.

Sécurisez votre code, votre cloud et votre environnement d’exécution dans un système centralisé unique.
Détectez et corrigez les vulnérabilités rapidement et automatiquement.

Aucune carte de crédit requise | Résultats en 32 secondes.