Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

FluxContactConfidentialité© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
Outils/GitHubGitHub/dylan-chainguard/
cve-2026-22732-poc
Outils DéfensifsAnalyse des VulnérabilitésExploitationVirtualisation de SécuritéSécurité WebApprentissage et Éducation
GitHubdylan-chainguard/cve-2026-22732-poc

cve-2026-22732-poc

Preuve de concept démontrant CVE-2026-22732, une faille de Spring Security où setIntHeader("Content-Length") supprime tous les en-têtes de sécurité, avec des builds vulnérables et corrigés.

Voir le dépôt
116il y a 20 joursPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2026-22732 — Preuve de concept

Spring Security supprime silencieusement les en-têtes de sécurité des réponses HTTP. Démo / usage éducatif uniquement ; ne l'exécutez contre rien d'autre que cette application locale.

CVECVE-2026-22732 (CWE-425), publiée le 2026-03-19
CVSS 3.19.1 CRITIQUE — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
Dépendance directespring-boot-starter-web + spring-boot-starter-security 2.7.18
Composant vulnérablespring-security-web / -config / -core 5.7.11 — transitif uniquement, jamais nommé dans pom.xml
Composant corrigéspring-security-web 5.7.14-0.cgr.2, atteint par un seul changement de <version> — voir la transition
Vérifié surTomcat 9.0.118, JDK 17.0.18, macOS arm64

Plages affectées : 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. Spring Boot 2.7.18 épingle Spring Security 5.7.11, en plein dans la première plage :

$ 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

L'exécuter

./run.sh        # terminal 1 — builds and starts on :8080 (pins JDK 17)
./exploit.sh    # terminal 2 — drives every endpoint, diffs the headers

run.sh épingle JAVA_HOME car Spring Boot 2.7.x ne peut pas s'exécuter sur le JDK 25 que mvn résout par défaut sur cette machine. Remplacez avec JAVA_HOME_17=/path/to/jdk17.

Il compile aussi avec -s settings-chainguard.xml par défaut, car le parent corrigé n'est pas sur Maven Central. Définissez MAVEN_SETTINGS=/path/to/your/settings.xml pour pointer ailleurs, ou MAVEN_SETTINGS= pour compiler uniquement depuis Central — ce qui ne fonctionne que pour le 2.7.18 d'origine.

exploit.sh lit les versions réelles de spring-security-web et spring-boot depuis target/*.jar, donc sa bannière rapporte toujours ce qui s'exécute réellement plutôt qu'une chaîne codée en dur.

La configuration

SecurityConfig n'applique aucune personnalisation d'en-tête — les valeurs par défaut de Spring Security sont en vigueur, ce qui est exactement ce sur quoi une application soucieuse de la sécurité s'appuie. Chaque endpoint renvoie le même corps sensible :

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

La seule chose qui varie est la façon dont le contrôleur écrit la réponse.

Résultats mesurés

BASELINE  standard Spring MVC return value
  /safe/account                    OK        all 6 headers delivered

CONTROL   getOutputStream(), body > 8 KB buffer
  /vuln/stream/account             OK        all 6 headers delivered

CONTROL   explicit response.flushBuffer()
  /vuln/flush/account              OK        all 6 headers delivered

EXPLOIT   setIntHeader("Content-Length", n)  <-- CVE-2026-22732
  /vuln/content-length/account     BYPASSED  ALL 6 security headers dropped

BY DESIGN application sets its own Expires header (NOT this CVE)
  /vuln/cache/account              PARTIAL   Cache-Control + Pragma dropped

Seul /vuln/content-length/account change d'état lorsque la CVE est corrigée, c'est donc le seul endpoint dont exploit.sh tire son verdict. Les autres sont des contrôles.

La CVE — setIntHeader("Content-Length", n) → contournement total

Trois lignes de code de contrôleur d'apparence ordinaire suppriment tous les en-têtes que Spring Security promettait :

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

Pas de X-Frame-Options, pas de X-Content-Type-Options, pas de Cache-Control, pas de Pragma, pas d'Expires, pas de X-XSS-Protection. Comparez avec /safe/account, qui porte les six. La réponse est encadrable par n'importe quelle origine, sensible au reniflage MIME et cachable — tout en servant un numéro de carte.

Le cas par conception — en-tête de cache défini par l'application → suppression du cache

Corrigé : une version antérieure de ce README appelait cela « exploit 2 » et affirmait qu'il s'agissait de la condition documentée par l'avis. Cela ne fait pas partie de CVE-2026-22732 et aucune mise à niveau ne le corrige. CacheControlHeadersWriter est identique octet pour octet en 5.7.11, 5.7.14-0.cgr.2, 6.5.8 (dernière vulnérable) et 6.5.9 (première corrigée) — vérifié en comparant les jars de sources. Sa Javadoc énonce le comportement sans détour : « Insère des en-têtes pour empêcher la mise en cache si aucun en-tête de contrôle du cache n'a été spécifié. »

Cela vaut quand même la peine d'être démontré, car la fuite est réelle et le risque résiduel survit au correctif. CacheControlHeadersWriter abandonne si Cache-Control, Expires ou Pragma est déjà présent, donc définir l'un des trois supprime toutes les directives no-store de Spring Security. Une seule ligne bien intentionnée suffit :

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 compte comme « présent » dans le tableau ci-dessus, mais avec une valeur favorable à l'attaquant choisie par l'application — l'Expires: 0 de Spring Security a été remplacé, pas simplement supprimé. Les données du porteur de carte sont désormais stockables par chaque navigateur et proxy partagé sur le chemin jusqu'en 2099.

Sur la version corrigée, /vuln/content-length/account bascule vers NOT cacheable, tandis que /vuln/cache/account reste exactement comme ci-dessus. Seul le code applicatif ou un reverse proxy le corrige — ce qui est la chose utile à dire à voix haute dans une démo : mettre à niveau la bibliothèque ferme la CVE et laisse ceci intact.

Deux résultats négatifs, conservés à dessein

Plusieurs articles largement diffusés — y compris un dépôt de reproduction public — listent response.getOutputStream() et response.flushBuffer() comme déclencheurs, expliquant que « la réponse est validée avant que Spring Security puisse injecter ses en-têtes ». Sur Spring Security 5.7.11, c'est faux. Les deux endpoints délivrent les six en-têtes.

/diag/committed montre pourquoi l'explication ne tient pas. Après une écriture de 12 Ko, la réponse est réellement validée à l'intérieur du contrôleur, et pourtant les en-têtes arrivent toujours :

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

OnCommittedResponseWrapper redéfinit flushBuffer() et les écritures du flux de sortie, donc il obtient ses en-têtes avant ces validations. L'ordre de validation seul n'est pas le bug ; le chemin avec Content-Length déclaré l'est. L'avis Spring lui-même ne cautionne jamais l'histoire de l'ordre de validation.

Conserver ces deux endpoints rend la PoC falsifiable : elle montre ce qui ne se reproduit pas aussi clairement que ce qui se reproduit, et les deux restent verts à travers le correctif, ce qui rend le seul endpoint qui bascule significatif.

La transition vulnérable → corrigée

Une ligne dans pom.xml, rien d'autre. Aucun changement de source, aucun changement de propriété, aucune montée de version majeure de Spring Boot :

Télécharger l’outil