SvelteKit é um popular framework JavaScript full-stack, e Vercel é sua plataforma de implantação mais comum. E se disséssemos que todos os aplicativos construídos usando essa combinação estavam vulneráveis a invasores lendo respostas de qualquer rota de outros usuários logados?
Bem, é verdade. Este vetor de ataque, chamado cache deception, é exatamente o que um dos agentes de IA encontrou e nos reportou enquanto testávamos Aikido Attack. E embora inicialmente céticos, refizemos seus passos e descobrimos que poderíamos reproduzir a vulnerabilidade perfeitamente. Notificamos rapidamente a Vercel, e a vulnerabilidade foi agora corrigida automaticamente para todos os usuários.
Nota: O problema pode ser visualizado no banco de dados Intel do Aikido e tem o número CVE reservado de: CVE-2026-27118. Também encontramos um problema separado que permite a Negação de Serviço em um recurso experimental no SvelteKit. Isso também foi divulgado e corrigido.
Resumo Rápido
O __pathname parâmetro de consulta no adaptador Vercel do SvelteKit pode sobrescrever o caminho de qualquer lugar. Na Vercel, cada arquivo em /_app/immutable/ tem diferentes Cache-Control: cabeçalhos para que possa ser armazenado em cache. Ao prefixar isso com um caminho falso e reescrevê-lo para conter conteúdo sensível, a resposta será forçosamente armazenada em cache, permitindo que um invasor a recupere visitando a mesma URL sem cookies.
URL de Prova de Conceito:
https://example.vercel.app/_app/immutable/x?__pathname=/api/session
Descoberta
Contaremos esta história da perspectiva do agente de pentest de IA que encontrou a vulnerabilidade, começando do gadget inicial até a exploração completa, e falaremos sobre algumas ideias interessantes ao longo do caminho. Abrace seu robô interior e vamos pesquisar!
Se você ler o código-fonte do SvelteKit, você encontrará alguns “adapters”, que são o middleware entre uma plataforma de hospedagem como a Vercel e o framework SvelteKit. Isso possibilita aplicar algumas regras especiais à requisição e resposta exigidas para os internos da plataforma. A Vercel implementou o seguinte em 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'));
}
});
}
Podemos ler “Se esta for uma requisição ISR, o pathname requisitado é codificado como um parâmetro de busca.” O código pega esta variável pathname (do ?__pathname= parâmetro de query) e reescreve o url.pathname com ele. A requisição ignora a URL original e simplesmente usa este __pathname em vez disso.
Mas não parece haver nenhuma verificação em relação a estas requisições de Incremental Static Regeneration (ISR), então todas as requisições suportam este parâmetro?
A resposta é sim, e é exatamente aí que reside a vulnerabilidade! Qualquer caminho pode ser sobrescrito para qualquer outro caminho com apenas um parâmetro de query. Um teste simples como /?__pathname=/404 realmente mostraria um erro 404 em vez da página inicial.

Isso pode parecer apenas um recurso estranho. Por que seria perigoso? Bem, não é, até que o caching seja envolvido.
Envenenamento de Cache?
Se pudermos reescrever qualquer caminho para apontar para qualquer outro recurso, o que acontece se esse recurso envenenado for armazenado em cache? Esta também foi nossa primeira ideia. Se verificarmos o código-fonte de qualquer aplicativo SvelteKit, você verá algo como:
import("./_app/immutable/entry/start.CLO1Dlt2.js"),
import("./_app/immutable/entry/app.kQF6jJr8.js")
O caminho /_app/immutable/entry/start.CLO1Dlt2.js retorna algum JavaScript para executar, e, olhando a resposta, Cache-Control: os cabeçalhos nos dizem que ele está de fato em cache. Isso é esperado para recursos estáticos:
Age: 618
Cache-Control: public, immutable, max-age=31536000
X-Vercel-Cache: HIT
Se pudéssemos usar nosso ?__pathname= parâmetro para reescrever a requisição para apontar para algum caminho controlado por um atacante, como um upload de arquivo, e ainda seria armazenado em cache sob o mesmo /_app/immutable/entry/start.CLO1Dlt2.js que todo usuário carrega, teríamos XSS em todo usuário. Vamos ver o que acontece quando adicionamos este parâmetro de query à nossa requisição:
GET /_app/immutable/start.CLO1Dlt2.js?__pathname=/ HTTP/2
Host: example.vercel.app
Na resposta, recebemos boas e más notícias dos cabeçalhos:
Age: 935
Cache-Control: public, immutable, max-age=31536000
X-Vercel-Cache: HIT
O Idade: aumentou pelo tempo que levou para escrever o parágrafo acima, e o HIT significa que com nosso parâmetro de consulta adicionado, a mesma entrada de cache é atingida que aquela que todos carregam. Mas, ao mesmo tempo, isso significa que o conteúdo JavaScript antigo também é retornado, e não o conteúdo do nosso caminho reescrito. Se for esse o caso, poderíamos esvaziar o cache e então ser os primeiros a solicitá-lo para que nossa payload possa ser armazenado em cache?
Infelizmente não. A plataforma Vercel é mais complicada devido à sua arquitetura serverless, e ela nem sequer atinge o código do adaptador para tal recurso estático. Isso ocorre porque os ativos estáticos são armazenados em cache e retornados em uma camada superior, então nunca seremos capazes de envenená-los.
Neste caso, a própria Vercel é a única plataforma vulnerável, então não conseguimos encontrar outros cenários exploráveis. Chegamos a um beco sem saída.
Engano de Cache!
Passando para o próximo problema com o cache web: cache deception. Nesta técnica menos conhecida, um atacante redireciona uma vítima para uma página sensível que pode ser recuperada com seus cookies. Se o cache armazena esta página sem considerar qual usuário a solicitou, o atacante pode posteriormente visitar a mesma URL e ver os dados privados da vítima a partir do cache. O problema é que o cache salva as respostas com base apenas na URL, ignorando que usuários diferentes com cookies de login diferentes deveriam ver conteúdos diferentes.
Aplicando essa ideia ao nosso ?__pathname= gadget, podemos fazer com que nossa URL pareça apontar para um caminho estático, mas na verdade aponta para conteúdo sensível. A camada de cache pode ser acionada por esse caminho com aparência estática e adicionar cabeçalhos explícitos Cache-Control: e sobrescrever a resposta privada.
Embora alguns critérios de cache estejam documentados, nossa investigação revelou mais regras. Uma com a qual já estamos familiarizados: caminhos que começam com /_app/immutable/. Acontece que não apenas os arquivos estáticos esperados são armazenáveis em cache sob este prefixo, mas qualquer resposta 200 OK. Para evitar os assets já gerados, podemos inicialmente apontar para um asset falso. Em seguida, reescrevê-lo para qualquer caminho sensível, digamos /api/session:
https://example.vercel.app/_app/immutable/x?__pathname=/api/session
E aí temos nosso payload final. Visitar este link como uma vítima logada enviará uma requisição como a seguinte:
GET /_app/immutable/x?__pathname=/api/session HTTP/2
Host: example.vercel.app
Cookie: auth=...
O adaptador Vercel do SvelteKit reescreve o pathname para /api/session, e é tratado pelo aplicativo. O auth= cookie é verificado, e seu token de sessão é retornado:
HTTP/2 200 OK
Age: 0
Cache-Control: public, immutable, max-age=31536000
...
Server: Vercel
X-Vercel-Cache: MISS
Content-Length: 16
{"token":"1337"}Enquanto o Cache-Control: cabeçalho normalmente diria max-age=0 para este endpoint, a camada de cache da Vercel força a habilitação do cache por causa do /_app/immutable/ prefixo.
Assim que o atacante sabe que uma vítima foi redirecionada, ele pode solicitar a mesma URL, sem nenhum cookie:
GET /_app/immutable/x?__pathname=/api/session HTTP/2
HostEles recebem a mesma resposta que um HIT agora, e podem ler o token da vítima.
HTTP/2 200 OK
Age: 22
Cache-Control: public, immutable, max-age=31536000
...
Server: Vercel
X-Vercel-Cache: HIT
Content-Length: 16
{"token":"1337"}
Usando cache busters (caminhos fictícios únicos) e verificando após o redirecionamento, isso poderia ter sido explorado em larga escala. Como esta vulnerabilidade faz parte apenas do SvelteKit base, qualquer site SvelteKit na Vercel que utilize cookies para autenticação permitiria que respostas arbitrárias fossem recuperadas.
O desfecho
Rapidamente reportamos o problema à Vercel, que desenvolveu uma correção para retornar 404 forçadamente em qualquer /_app/immutable/ caminho, e para remover o __pathname parâmetro. Como eles controlam toda a sua plataforma, isso resolve o problema automaticamente para todos os usuários, sem a necessidade de um patch manual.
Uma grande lição desta vulnerabilidade é que o cache é sempre complicado. Regras simples, como uma correspondência de prefixo, podem ser exploradas por recursos inesperados da plataforma que você nem mesmo implementou.
É por isso que o pentesting pode ser tão útil. Problemas como este seriam difíceis de descobrir apenas pelo código, mas através de uma implantação real, regras ocultas podem ser encontradas e exploradas. O AI pentest da Aikido pode detectar ataques de cache poisoning e cache deception automaticamente, assim como encontrou este problema.
Principais Pontos
- Em 20 de janeiro de 2026, o sistema de AI pentest da Aikido sinalizou algo interessante em aplicações SvelteKit implantadas na Vercel.
- Confirmamos que era uma vulnerabilidade de cache deception afetando configurações padrão.
- Nenhuma má configuração necessária. Apenas SvelteKit + Vercel fazendo o que deveriam fazer.
- Impacto: Respostas autenticadas podem ser armazenadas em cache e expostas a outros usuários.
- Qualquer aplicativo SvelteKit rodando na Vercel com endpoints protegidos pode ser afetado.
Como verificar se você foi afetado
Usando Aikido:
Se você é um usuário Aikido, verifique seu feed central. Você pode ver o problema no Aikido Intel aqui. Dica: O Aikido faz rescans dos seus repositórios todas as noites, embora recomendemos também acionar um rescan completo.
Se você ainda não é um usuário Aikido, crie uma conta e conecte seus repositórios. Nossa cobertura proprietária de malware está incluída no plano gratuito (não é necessário cartão de crédito).
O pentest de IA e a varredura de segurança web da Aikido detectam automaticamente fluxos de engano de cache e comportamento de reescrita inseguro.
Status da correção
Divulgamos isso à Vercel em 21 de janeiro de 2026.
Cronograma
- 20 de janeiro de 2026: A Aikido Security identificou a vulnerabilidade, desenvolveu um PoC funcional
- 21 de janeiro de 2026: Divulgação responsável à Vercel
- 23 de janeiro de 2026: Relatório triado
- 9 de fevereiro de 2026: A Vercel confirma o relatório e começa a trabalhar em uma correção
- 19 de fevereiro de 2026: A Vercel corrigiu a vulnerabilidade para todos os usuários, e o aviso foi publicado (GHSA-9pq4-5hcf-288c). O problema pode ser visualizado no banco de dados Intel do Aikido e tem o número CVE reservado de: CVE-2026-27118.
Também encontramos um problema separado que permite a Negação de Serviço em um recurso experimental no SvelteKit. Isso também foi divulgado e corrigido.

