# REPRO-2026-00131: Apache Tomcat EncryptInterceptor Bypass via CVE-2026-29146 Fix Error - Missing Encryption of Sensitive Data ## Summary Status: published Severity: high Type: security Confidence: Unknown ## Identifiers REPRO ID: REPRO-2026-00131 CVE: CVE-2026-34486 ## Package Name: Unknown Ecosystem: Unknown Affected: Unknown Fixed: Unknown ## Root Cause # CVE-2026-34486: Root Cause Analysis ## 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: ```java 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 1. **Reference**: `repro/reproduction_steps.sh` in this repository 2. **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 `EncryptInterceptor` with a known encryption key - Chains a `ValueCaptureInterceptor` downstream 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 `IllegalBlockSizeException` during decryption - Asserts that the malformed ciphertext was forwarded downstream **unchanged** (bypass confirmed) - Runs the test and exits 0 on success, 1 on failure 3. **Expected evidence**: - Log output showing "Failed to decrypt message" with `IllegalBlockSizeException` - Captured downstream bytes matching the input malformed ciphertext exactly - Final message: ">>> VULNERABILITY CONFIRMED <<<" ## Evidence - **Log output**: `logs/reproduction.log` (generated by running `repro/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 1. **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. 2. **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. 3. **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 of `GeneralSecurityException`), but other `GeneralSecurityException` subclasses 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 `EncryptInterceptor` via 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. ## Reproduction Details Reproduced: 2026-04-14T14:13:23.522Z Duration: 1178 seconds Tool calls: 176 Turns: Unknown Handoffs: 1 ## Quick Verification Run one of these commands to verify locally: pruva-verify REPRO-2026-00131 pruva-verify CVE-2026-34486 Or open in GitHub Codespaces (zero-friction, auto-runs): https://github.com/codespaces/new?ref=repro/REPRO-2026-00131&repo=N3mes1s/pruva-sandbox Or download and run the script manually: curl -O https://api.pruva.dev/v1/reproductions/REPRO-2026-00131/artifacts/repro/reproduction_steps.sh chmod +x reproduction_steps.sh ./reproduction_steps.sh WARNING: Run in a sandboxed environment. This exploits a real vulnerability. ## References - NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-34486 ## Artifacts - repro/rca_report.md (analysis, 6358 bytes) - repro/reproduction_steps.sh (reproduction_script, 7551 bytes) - vuln_variant/rca_report.md (analysis, 8615 bytes) - vuln_variant/reproduction_steps.sh (reproduction_script, 7657 bytes) - bundle/ticket.json (other, 4098 bytes) - bundle/repro/judge_review.json (other, 1181 bytes) - bundle/AGENTS.repro.md (documentation, 824 bytes) - bundle/ticket.md (ticket, 3598 bytes) - repro/runtime_manifest.json (other, 546 bytes) - repro/validation_verdict.json (other, 783 bytes) - vuln_variant/variant_manifest.json (other, 2564 bytes) - vuln_variant/patch_analysis.md (documentation, 5386 bytes) - vuln_variant/validation_verdict.json (other, 1611 bytes) - logs/variant_compile.log (log, 0 bytes) - logs/variant_test.log (log, 3607 bytes) - logs/vuln_compile.log (log, 0 bytes) - logs/fixed_compile.log (log, 0 bytes) - logs/vuln_test.log (log, 1189 bytes) - logs/fixed_test.log (log, 1175 bytes) ## API Access - JSON: https://api.pruva.dev/v1/reproductions/REPRO-2026-00131 - Script: https://api.pruva.dev/v1/reproductions/REPRO-2026-00131/artifacts/repro/reproduction_steps.sh - Web: https://pruva.dev/r/REPRO-2026-00131 ## For AI Assistants To help users with this reproduction: 1. The `pruva-verify` command is the simplest way to run the reproduction 2. The script downloads and runs automatically in an isolated temp directory 3. Always recommend running in a VM, container, or disposable environment 4. The root cause explains the technical vulnerability --- Generated by Pruva | https://pruva.dev