
CVE Reproduction: cve-2026-34486-tomcat_encrypt_bypass_reproduction
| Field | Value |
|---|---|
| CVE | CVE-2026-34486 |
| CVSS | 7.5 HIGH |
| Type | Missing Encryption of Sensitive Data |
| Component | Apache Tomcat Cluster EncryptInterceptor |
| Published | 2026 |
CVE-2026-34486 is a regression introduced by the incomplete fix for CVE-2026-29146. In Apache Tomcat's cluster replication, the EncryptInterceptor is responsible for encrypting and authenticating cluster messages. A refactoring in the fix for CVE-2026-29146 inadvertently moved the super.messageReceived(msg) call outside the try-catch block that handles decryption failures. As a result, when a message fails decryption (i.e., it is received in plaintext but the interceptor expects encrypted data), the raw unencrypted message is still passed up the handler chain instead of being discarded.
The EncryptInterceptor.messageReceived() method is invoked when a cluster message arrives. The expected flow is:
super.messageReceived(msg) to forward the decrypted messageIn the vulnerable versions, the decryption/validation logic remains wrapped in a try-catch, but the call chain was restructured so that super.messageReceived(msg) executes outside the try-catch block that guards the decryption. The variable msg is declared before the try-catch and assigned within it. When decryption throws an exception, msg retains its initial (unencrypted/raw) value, and the catch block only logs the error — it does not return early. Execution continues to super.messageReceived(msg) with the unprocessed raw data.
This means an attacker who can reach the Tomcat cluster port can inject arbitrary unencrypted messages that the interceptor will accept and process.
public void messageReceived(Message msg) {
// msg arrives raw
try {
// decrypt and populate msg fields
decrypt(msg);
} catch (Exception e) {
log.error("Decryption failed", e);
// BUG: no return statement here
}
// msg is still the original unencrypted object when catch is hit
super.messageReceived(msg); // outside try-catch → passes raw data
}
The fix must ensure that either:
super.messageReceived(msg) is called only inside the try block after successful decryption, or| Product | Versions |
|---|---|
| Apache Tomcat 11 | 11.0.20 |
| Apache Tomcat 10 | 10.1.53 |
| Apache Tomcat 9 | 9.0.116 |
EncryptInterceptor<Receiver>)EncryptInterceptor configured in server.xml.The exploit.py script in this directory demonstrates the bypass. It constructs a minimal Tomcat cluster message (based on the ClusterMessage serialization format) and sends it directly to the receiver port without any encryption. A vulnerable interceptor will accept and forward the message despite the missing encryption.
Upgrade to a patched version of Apache Tomcat:
| Product | Patched Version |
|---|---|
| Apache Tomcat 11 | 11.0.21+ |
| Apache Tomcat 10 | 10.1.54+ |
| Apache Tomcat 9 | 9.0.117+ |
If upgrading immediately is not possible, restrict network access to the Tomcat cluster port to trusted hosts only (e.g., via firewall rules or binding the receiver to a loopback or private interface).