CVE-2026-34486: Verified Repro With Script Download
CVE-2026-34486: Apache Tomcat EncryptInterceptor Bypass via CVE-2026-29146 Fix Error - Missing Encryption of Sensitive Data
CVE-2026-34486 is verified against the affected target. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00131.
What Is CVE-2026-34486?
CVE-2026-34486 is a high-severity Missing Encryption of Sensitive Data vulnerability in Apache Tomcat's EncryptInterceptor (tomcat-tribes clustering subsystem) that lets an attacker bypass encryption entirely. Pruva reproduced it (reproduction REPRO-2026-00131).
CVE-2026-34486 Severity & CVSS Score
CVE-2026-34486 is rated high severity, with a CVSS base score of 7.5 out of 10.
High — serious impact or readily exploitable. Prioritize remediation.
How to Reproduce CVE-2026-34486
pruva-verify REPRO-2026-00131 curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00131/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-34486
Reproduced by Pruva's autonomous agents — 176 tool calls over 20 min. Full root-cause analysis and the complete transcript are below.
How the agent worked
Root Cause and Exploit Chain for CVE-2026-34486
Summary
CVE-2026-34486 is a Missing Encryption of Sensitive Data vulnerability in Apache Tomcat's EncryptInterceptor component within the tomcat-tribes clustering subsystem. The vulnerability allows an attacker to bypass encryption entirely by sending malformed or corrupted ciphertext that causes decryption to fail. Due to a code refactoring error introduced in the fix for CVE-2026-29146 (a padding oracle vulnerability), the super.messageReceived(msg) call was placed outside the try-catch block that handles decryption. As a result, when decryption throws a GeneralSecurityException (or any exception), the exception is caught and logged but the unprocessed (encrypted/corrupted) message is still forwarded downstream as if it were legitimate, effectively bypassing the encryption layer.
Impact
- Package/Component affected:
org.apache.catalina.tribes.group.interceptors.EncryptInterceptor(tomcat-tribes module) - Affected versions: Apache Tomcat 11.0.20, 10.1.53, 9.0.116
- Risk level: HIGH (CVSS: 7.5)
- CVSS Vector:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Consequences:
- Encrypted cluster messages can be processed without proper decryption
- Session replication data may be exposed or corrupted
- Attackers with network access to Tomcat cluster can send arbitrary malformed messages that bypass encryption checks
- Confidentiality impact: HIGH — sensitive session/cluster data may leak in plaintext or corrupted form
Root Cause
The vulnerability stems from a refactoring error in the patch for CVE-2026-29146. In the vulnerable versions, the EncryptInterceptor.messageReceived() method has the following flawed structure:
public void messageReceived(ChannelMessage msg) {
try {
// Decryption logic
xbb.clear();
xbb.append(data, 0, data.length);
} catch (GeneralSecurityException gse) {
log.error(sm.getString("encryptInterceptor.decrypt.failed"), gse);
}
super.messageReceived(msg); // BUG: Outside try-catch — executes regardless of decryption failure!
}
The super.messageReceived(msg) call is outside the try-catch block, meaning it executes even when decryption fails and throws an exception. The correct behavior would be to only forward the message downstream if decryption succeeded, or to drop/abort processing on failure.
This is a classic exception handling bug: the catch block swallows the exception but doesn't prevent the downstream code path from executing.
Reproduction Steps
- Reference:
repro/reproduction_steps.shin this repository - What the script does:
- Downloads Apache Tomcat tomcat-tribes 11.0.20 JARs (vulnerable version)
- Compiles a Java test class (
TestEncryptInterceptorBypass.java) that:- Creates an
EncryptInterceptorwith a known encryption key - Chains a
ValueCaptureInterceptordownstream to observe forwarded messages - Step 1: Sends a valid plaintext message and confirms normal encryption/decryption works (baseline)
- Step 2: Sends malformed ciphertext (random bytes, wrong length) that triggers
IllegalBlockSizeExceptionduring decryption - Asserts that the malformed ciphertext was forwarded downstream unchanged (bypass confirmed)
- Creates an
- Runs the test and exits 0 on success, 1 on failure
- Expected evidence:
- Log output showing "Failed to decrypt message" with
IllegalBlockSizeException - Captured downstream bytes matching the input malformed ciphertext exactly
- Final message: ">>> VULNERABILITY CONFIRMED <<<"
- Log output showing "Failed to decrypt message" with
Evidence
- Log output:
logs/reproduction.log(generated by runningrepro/reproduction_steps.sh) - Key excerpts proving reproduction:
Apr 14, 2026 12:41:17 PM org.apache.catalina.tribes.group.interceptors.EncryptInterceptor messageReceived SEVERE: Failed to decrypt message javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher ... Captured downstream: 000102030405060708090a0b0c0d0e0ffffefdfc4142434445464748 >>> VULNERABILITY CONFIRMED <<< The malformed ciphertext was forwarded downstream UNCHANGED! Decrypt failed but super.messageReceived() was still called. CVE-2026-34486 is REPRODUCED. - Environment: Java 17 (OpenJDK), tomcat-tribes 11.0.20, tomcat-juli 11.0.20
- Script exit code: 0 (confirmed)
- Reproducibility: Verified twice consecutively with consistent results
Recommendations / Next Steps
Immediate fix: Move
super.messageReceived(msg)inside the try block so it only executes on successful decryption. If decryption fails, the method should return early or propagate the exception.Upgrade guidance: Upgrade to a patched version of Apache Tomcat once available. The fixed versions should ensure that
super.messageReceived()is only called within the try block, or that an explicit return/throw follows exception handling.Testing recommendations:
- Add unit tests that verify malformed ciphertext does NOT reach downstream interceptors
- Test with various malformed inputs: wrong key, truncated ciphertext, invalid padding, wrong block size
- Verify that legitimate encrypted messages still decrypt and forward correctly after the fix
- Test the CVE-2026-29146 fix did not regress the padding oracle protection
Additional Notes
- Idempotency: The reproduction script is fully idempotent — it uses a temporary directory and downloads dependencies fresh each run. Running it twice produces identical results.
- Edge cases:
- The bug manifests with any input that causes decryption to fail, including wrong key, wrong block size, invalid padding, or corrupted ciphertext.
- The exception type observed was
IllegalBlockSizeException(a subclass ofGeneralSecurityException), but otherGeneralSecurityExceptionsubclasses would trigger the same bypass. - The downstream interceptor receives the raw unprocessed bytes, not any form of decrypted output.
- Limitations: This reproduction tests the library-level
EncryptInterceptorvia a Java harness. A full cluster-level test with running Tomcat instances would further demonstrate real-world impact but is not required to confirm the bug.
CVE-2026-34486 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
curl -sL "https://github.com/apache/tomcat/commit/1fab40ccc752e22639eccfe290d5624afad7eccd.patch" 2>/dev/null | head -200{"cwd":"/data/pruva/runs/0332447d-9fce-49c0-953d-e7a8666d57cb","duration_ms":382,"exit_code":0,"stderr":"","stdout":"From 1fab40ccc752e22639eccfe290d5624afad7eccd Mon Sep 17 00:00:00 2001\nFrom: Mark Thomas <markt@apache.org>\nDate: Mon, 30 Mar 2026 09:01:48 +0100\nSubject: [PATCH] Better error handling - partial revert of 6d955cc\n\n---\n .../catalina/tribes/group/interceptors/EncryptInterceptor.java | 2 +-\n webapps/docs/changelog.xml | 3 +++\n 2 files changed, 4 insertions(+), 1 deletion(-)\n\ndiff --git a/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptor.java b/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptor.java\nindex 31866f254cd1..291f46724c8f 100644\n--- a/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptor.java\n+++ b/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptor.java\n@@ -140,10 +140,10 @@ public void messageReceived(ChannelMessage msg) {\n xbb.clear();\n xbb.append(data, 0, data.length);\n \n+ super.messageReceived(msg);\n } catch (GeneralSecurityException gse) {\n log.error(sm.getString(\"encryptIn… [truncated]curl -sL "https://github.com/apache/tomcat/commit/6d955cc.patch" 2>/dev/null | head -200{"cwd":"/data/pruva/runs/0332447d-9fce-49c0-953d-e7a8666d57cb","duration_ms":439,"exit_code":0,"stderr":"","stdout":"From 6d955cceca841f2eabf2d6c46b59a8c7e1cd6eaa Mon Sep 17 00:00:00 2001\nFrom: Mark Thomas <markt@apache.org>\nDate: Fri, 13 Mar 2026 13:18:39 +0000\nSubject: [PATCH] Add support for new algorithms provided by JPA providers\n\n---\n .../interceptors/EncryptInterceptor.java | 64 +++++--\n .../interceptors/LocalStrings.properties | 5 +-\n .../interceptors/LocalStrings_fr.properties | 1 -\n .../interceptors/LocalStrings_ja.properties | 1 -\n .../interceptors/LocalStrings_ko.properties | 1 -\n .../LocalStrings_zh_CN.properties | 1 -\n .../interceptors/TestEncryptInterceptor.java | 58 -------\n .../TestEncryptInterceptorAlgorithms.java | 162 ++++++++++++++++++\n webapps/docs/changelog.xml | 4 +\n webapps/docs/config/cluster-interceptor.xml | 19 +-\n 10 files changed, 231 insertions(+), 85 deletions(-)\n create mode 100644 test/org/apache/catalina/tribes/group/interceptors/TestEncryptInterceptorAlgorithms.java\n\ndiff --git a/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptor.java b/java… [truncated]curl -sL "https://raw.githubusercontent.com/apache/tomcat/refs/tags/11.0.20/java/org/apache/catalina/tribes/group/interceptors/EncryptInterceptor.java" 2>/dev/null | head -180{"cwd":"/data/pruva/runs/0332447d-9fce-49c0-953d-e7a8666d57cb","duration_ms":267,"exit_code":0,"stderr":"","stdout":"/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements. See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License. You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.catalina.tribes.group.interceptors;\n\nimport java.io.Serial;\nimport java.security.GeneralSecurityException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.NoSuchProviderException;\nimport java.security.SecureRandom;\… [truncated]which mvn && mvn --version 2>/dev/null || echo "Maven not found"Maven not found
apt-get update -qq && apt-get install -y -qq maven openjdk-17-jdk-headless 2>&1 | tail -5E: List directory /var/lib/apt/lists/partial is missing. - Acquire (13: Permission denied)
whoami && which java && java -version 2>&1vscode
sudo apt-get update -qq 2>&1 | tail -3 && sudo apt-get install -y -qq maven openjdk-17-jdk-headless 2>&1 | tail -10{"cwd":"/data/pruva/runs/0332447d-9fce-49c0-953d-e7a8666d57cb","duration_ms":13018,"exit_code":0,"stderr":"","stdout":"update-alternatives: using /usr/lib/jvm/java-17-openjdk-arm64/bin/jmap to provide /usr/bin/jmap (jmap) in auto mode\r\nupdate-alternatives: using /usr/lib/jvm/java-17-openjdk-arm64/bin/jmod to provide /usr/bin/jmod (jmod) in auto mode\r\nupdate-alternatives: using /usr/lib/jvm/java-17-openjdk-arm64/bin/jps to provide /usr/bin/jps (jps) in auto mode\r\nupdate-alternatives: using /usr/lib/jvm/java-17-openjdk-arm64/bin/jrunscript to provide /usr/bin/jrunscript (jrunscript) in auto mode\r\nupdate-alternatives: using /usr/lib/jvm/java-17-openjdk-arm64/bin/jshell to provide /usr/bin/jshell (jshell) in auto mode\r\nupdate-alternatives: using /usr/lib/jvm/java-17-openjdk-arm64/bin/jstack to provide /usr/bin/jstack (jstack) in auto mode\r\nupdate-alternatives: using /usr/lib/jvm/java-17-openjdk-arm64/bin/jstat to provide /usr/bin/jstat (jstat) in auto mode\r\nupdate-alternatives: using /usr/lib/jvm/java-17-openjdk-arm64/bin/jstatd to provide /usr/bin/jstatd (jstatd) in auto mode\r\nupdate-alternatives: using /usr/lib/jvm/java-17-openjdk-arm64/bin/serialver to provide /usr/b… [truncated]which mvn && mvn --version 2>&1 | head -3/usr/bin/mvn [1mApache Maven 3.8.7[m Maven home: /usr/share/maven Java version: 21.0.10, vendor: Ubuntu, runtime: /usr/lib/jvm/java-21-openjdk-arm64
Artifacts and Evidence for CVE-2026-34486
Scripts, logs, diffs, and output captured during the reproduction.
No artifacts available
How to Fix CVE-2026-34486
FAQ: CVE-2026-34486
How does the CVE-2026-34486 encryption-bypass attack work?
EncryptInterceptor. Decryption fails and throws an exception, but because messageReceived() was refactored to call super.messageReceived(msg) outside the catch block, the interceptor still forwards the message downstream unencrypted/unvalidated, bypassing the intended encryption layer for session replication and cluster data.Which Apache Tomcat versions are affected by CVE-2026-34486?
How severe is CVE-2026-34486?
How can I reproduce CVE-2026-34486?
EncryptInterceptor, then confirms the corrupted message is still processed downstream rather than dropped.References for CVE-2026-34486
Authoritative sources for CVE-2026-34486 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.