Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

FeedsContatoPrivacidade© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
cve-2026-22732-poc — Prova de conceito demonstrando a CVE-2026-22732, uma falha do Spring Security em que setIntHeader("Content-Length") remove todos os cabeçalhos de segurança, com builds vulneráveis e corrigidos. | Kitploit
Ferramentas/GitHubGitHub/dylan-chainguard/cve-2026-22732-poc
Ferramentas DefensivasAnálise de VulnerabilidadesExploraçãoVirtualização para SegurançaSegurança WebAprendizado e Educação
GitHubdylan-chainguard/cve-2026-22732-poc

cve-2026-22732-poc

Prova de conceito demonstrando a CVE-2026-22732, uma falha do Spring Security em que setIntHeader("Content-Length") remove todos os cabeçalhos de segurança, com builds vulneráveis e corrigidos.

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Ver Repositório
116há 20 diasAinda não revisado
Compartilhar

CVE-2026-22732 — Prova de Conceito

O Spring Security descarta silenciosamente os cabeçalhos de segurança da resposta HTTP. Apenas para fins de demonstração / educacionais; execute-o apenas contra este aplicativo local.

CVECVE-2026-22732 (CWE-425), publicado em 2026-03-19
CVSS 3.19.1 CRÍTICO — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Dependência diretaspring-boot-starter-web + spring-boot-starter-security 2.7.18
Componente vulnerávelspring-security-web / -config / -core 5.7.11 — apenas transitivo, nunca nomeado no pom.xml
Componente corrigidospring-security-web 5.7.14-0.cgr.2, alcançado por uma única alteração de <version> — veja a transição
Verificado emTomcat 9.0.118, JDK 17.0.18, macOS arm64

Intervalos afetados: 5.7.0–5.7.21, 5.8.0–5.8.23, 6.3.0–6.3.14, 6.4.0–6.4.14, 6.5.0–6.5.8, 7.0.0–7.0.3. O Spring Boot 2.7.18 fixa o Spring Security 5.7.11, exatamente dentro do primeiro intervalo:

$ mvn dependency:tree -Dincludes=org.springframework.security
+- org.springframework.security:spring-security-config:jar:5.7.11:compile
|  \- org.springframework.security:spring-security-core:jar:5.7.11:compile
\- org.springframework.security:spring-security-web:jar:5.7.11:compile

Executando

./run.sh        # terminal 1 — compila e inicia na :8080 (fixa o JDK 17)
./exploit.sh    # terminal 2 — aciona todos os endpoints, compara os cabeçalhos

O run.sh fixa o JAVA_HOME porque o Spring Boot 2.7.x não consegue rodar no JDK 25 que o mvn resolve por padrão nesta máquina. Substitua com JAVA_HOME_17=/path/to/jdk17.

Ele também compila com -s settings-chainguard.xml por padrão, porque o parent corrigido não está no Maven Central. Defina MAVEN_SETTINGS=/path/to/your/settings.xml para apontar para outro local, ou MAVEN_SETTINGS= para compilar puramente a partir do Central — o que funciona apenas para o 2.7.18 original.

O exploit.sh lê as versões reais de spring-security-web e spring-boot de dentro de target/*.jar, então seu banner sempre reporta o que está realmente em execução em vez de uma string fixa.

A configuração

O SecurityConfig não aplica nenhuma customização de cabeçalho — os padrões do Spring Security estão em vigor, que é exatamente com o que um aplicativo consciente de segurança conta. Todo endpoint retorna o mesmo corpo sensível:

{"account":"4111-1111-1111-1111","holder":"D. Havelock","balance":"82914.55"}

A única coisa que varia é como o controller escreve a resposta.

Resultados medidos

BASELINE  valor de retorno padrão do Spring MVC
  /safe/account                    OK        todos os 6 cabeçalhos entregues

CONTROL   getOutputStream(), corpo > buffer de 8 KB
  /vuln/stream/account             OK        todos os 6 cabeçalhos entregues

CONTROL   response.flushBuffer() explícito
  /vuln/flush/account              OK        todos os 6 cabeçalhos entregues

EXPLOIT   setIntHeader("Content-Length", n)  <-- CVE-2026-22732
  /vuln/content-length/account     BYPASSED  TODOS os 6 cabeçalhos de segurança descartados

BY DESIGN aplicação define seu próprio cabeçalho Expires (NÃO é este CVE)
  /vuln/cache/account              PARTIAL   Cache-Control + Pragma descartados

Apenas /vuln/content-length/account muda de estado quando o CVE é corrigido, então é o único endpoint do qual o exploit.sh deriva seu veredito. Os demais são controles.

O CVE — setIntHeader("Content-Length", n) → bypass total

Três linhas de código de controller aparentemente comum removem todos os cabeçalhos que o Spring Security prometeu:

response.setContentType("application/json");
response.setIntHeader("Content-Length", body.length);
response.getOutputStream().write(body);
$ curl -sD - -o /dev/null http://localhost:8080/vuln/content-length/account
HTTP/1.1 200
Content-Type: application/json
Content-Length: 77
Date: Tue, 01 Sep 2026 00:53:18 GMT

Sem X-Frame-Options, sem X-Content-Type-Options, sem Cache-Control, sem Pragma, sem Expires, sem X-XSS-Protection. Compare com /safe/account, que carrega todos os seis. A resposta é enquadrável por qualquer origem, sujeita a MIME-sniffing e cacheável — enquanto serve um número de cartão.

O caso by-design — cabeçalho de cache definido pela aplicação → supressão de cache

Corrigido: uma versão anterior deste README chamava isso de "exploit 2" e afirmava ser a condição documentada pelo advisory. Não faz parte do CVE-2026-22732 e nenhuma atualização o corrige. O CacheControlHeadersWriter é byte a byte idêntico em 5.7.11, 5.7.14-0.cgr.2, 6.5.8 (último vulnerável) e 6.5.9 (primeiro corrigido) — verificado comparando os jars de código-fonte. Seu Javadoc declara o comportamento explicitamente: "Inserts headers to prevent caching if no cache control headers have been specified."

Ainda vale a pena demonstrar, porque o vazamento é real e o risco residual sobrevive à correção. O CacheControlHeadersWriter desiste se Cache-Control, Expires ou Pragma já estiver presente, então definir qualquer um dos três suprime todas as diretivas no-store do Spring Security. Uma linha bem-intencionada basta:

response.setHeader("Expires", "Thu, 01 Jan 2099 00:00:00 GMT");
/safe/account                  NOT cacheable  (Cache-Control: no-cache, no-store, max-age=0, must-revalidate)
/vuln/cache/account            CACHEABLE      (Cache-Control: absent / Expires: Thu, 01 Jan 2099 00:00:00 GMT)
/vuln/content-length/account   CACHEABLE      (Cache-Control: absent / Expires absent)

Expires conta como "presente" na tabela acima, mas com um valor amigável ao atacante escolhido pela aplicação — o Expires: 0 do Spring Security foi substituído, não apenas descartado. Dados de portador de cartão agora são armazenáveis por todo navegador e proxy compartilhado no caminho até 2099.

Na build corrigida, /vuln/content-length/account muda para NOT cacheable, enquanto /vuln/cache/account permanece exatamente como acima. Apenas código da aplicação ou um proxy reverso o corrige — o que é a coisa útil a dizer em voz alta numa demonstração: atualizar a biblioteca fecha o CVE e deixa isso intacto.

Dois resultados negativos, mantidos de propósito

Vários write-ups amplamente divulgados — incluindo um repositório público de reprodução — listam response.getOutputStream() e response.flushBuffer() como gatilhos, explicando que "a resposta é commitada antes que o Spring Security possa injetar seus cabeçalhos". No Spring Security 5.7.11 isso está errado. Ambos os endpoints entregam todos os seis cabeçalhos.

/diag/committed mostra por que a explicação não se sustenta. Após uma escrita de 12 KB, a resposta realmente é commitada dentro do controller, mas os cabeçalhos ainda chegam:

>>> DIAG response.isCommitted() after 12048 byte write = true
    | wrapper class = org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterResponse

O OnCommittedResponseWrapper sobrescreve flushBuffer() e as escritas do output-stream, então ele emite seus cabeçalhos antes desses commits. A ordenação de commit por si só não é o bug; o caminho do Content-Length declarado é. O próprio advisory do Spring nunca endossa a história da ordenação de commit.

Manter esses dois endpoints torna a PoC falseável: mostra o que não se reproduz tão claramente quanto o que se reproduz, e ambos permanecem verdes ao longo da correção, o que é o que torna o único endpoint que de fato muda significativo.

A transição vulnerável → corrigida

Uma linha no pom.xml, nada mais. Sem alteração de código-fonte, sem alteração de propriedade, sem salto de versão major do Spring Boot:

Baixar ferramenta