# 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.
