CVE
CVE-2026-34486
CWE
CWE-311
Affected Surface
- Apache Tomcat `9.0.116`, `10.1.53`, and `11.0.20`
- Clustered Tomcat deployments using Tribes with `EncryptInterceptor` enabled and a reachable cluster receiver, typically TCP `4000`
- Java application stacks whose Tomcat classpath contains usable deserialization gadgets reachable from the Tribes message path
- Linux and enterprise downstream packages that ship the vulnerable Tomcat lines, including Red Hat and JBoss Web Server builds listed by NVD and Red Hat advisories
CVE-2026-34486 is the kind of bug AppSec teams should keep in their mental playbook because the dangerous part is not a giant parser rewrite or a new feature. It is one line of control flow. In vulnerable Tomcat releases, EncryptInterceptor.messageReceived() logs a decryption failure and still forwards the original message into the rest of the Tribes receive path. CISA’s 4 August KEV addition matters because it changes prioritization, but the underlying engineering lesson is older and more general: once a security boundary is implemented as “decrypt, then dispatch,” moving dispatch outside the success path turns the boundary into a fail-open parser.
For clustered Tomcat deployments that expose the Tribes receiver beyond a tightly controlled segment, this is not just “missing encryption.” It is a path from attacker-supplied network bytes to the Java object-deserialization surface that the cluster stack expects to consume only after successful decryption.
Confirmed affected versions and fix boundary
The public record is consistent across Apache, NVD, and the machine-readable vulnerability metadata:
| Project | Affected version | Fixed version |
|---|---|---|
| Apache Tomcat 9.x | 9.0.116 | 9.0.117 |
| Apache Tomcat 10.1.x | 10.1.53 | 10.1.54 |
| Apache Tomcat 11.0.x | 11.0.20 | 11.0.21 |
The deployment boundary matters as much as the version boundary. Public analysis and exploit writeups agree that practical exposure requires all of the following:
- Tomcat Tribes clustering is enabled
EncryptInterceptoris configured in the interceptor chain- the cluster receiver is reachable over the network, commonly on TCP
4000 - the target classpath contains a usable deserialization gadget path
That is why this is both narrower and more dangerous than the average “Tomcat vulnerability” headline suggests. It does not hit every servlet container. It hits the subset that deliberately turned on clustered message encryption and therefore expected decryption failure to be the gate.
The regression is visible in the diff
The heart of the bug is easiest to understand as a before-and-after control-flow problem.
The vulnerable pattern looked like this:
public void messageReceived(ChannelMessage msg) {
try {
byte[] data = msg.getMessage().getBytes();
data = encryptionManager.decrypt(data);
XByteBuffer xbb = msg.getMessage();
xbb.clear();
xbb.append(data, 0, data.length);
} catch (GeneralSecurityException gse) {
log.error(sm.getString("encryptInterceptor.decrypt.failed"), gse);
}
super.messageReceived(msg);
}
That last call is the entire problem. If decrypt() throws, the code logs the failure and then still executes:
super.messageReceived(msg);
The 9.0.117 fix commit makes the intended security property explicit by moving that call back into the success path:
xbb.clear();
xbb.append(data, 0, data.length);
+
+ super.messageReceived(msg);
} catch (GeneralSecurityException gse) {
log.error(sm.getString("encryptInterceptor.decrypt.failed"), gse);
}
- super.messageReceived(msg);
That is the whole boundary restoration:
- vulnerable state: “decrypt if possible, otherwise continue”
- fixed state: “decrypt successfully or drop the message”
For defenders, it is a useful example of why code review should treat exception placement as security logic rather than style.
Why decryption failure becomes a deserialization problem
Tomcat’s current EncryptInterceptor implementation shows the intended safe path clearly:
byte[] data = msg.getMessage().getBytes();
data = encryptionManager.decrypt(data);
XByteBuffer xbb = msg.getMessage();
xbb.clear();
xbb.append(data, 0, data.length);
super.messageReceived(msg);
The contract is: encrypted network bytes come in, decrypted bytes replace the original message buffer, and only then does the rest of the channel process the message.
CVE-2026-34486 breaks that contract. On decrypt failure, the raw network bytes remain in msg, but the receive pipeline still advances. Public exploit analyses describe the downstream path as reaching the Tribes message-deserialization flow, where attacker-controlled bytes can become Java object input.
Reduced to its essential form, the vulnerable path is:
attacker reaches Tribes receiver
-> EncryptInterceptor.decrypt(...) throws
-> error is logged
-> original message buffer is left intact
-> super.messageReceived(msg) still runs
-> downstream Tribes code deserializes bytes it should never have accepted
That is why the NVD label of “Missing Encryption of Sensitive Data” understates the operational risk. The exploitability story is not just confidentiality failure. The encryption gate becomes a parser gate bypass.
This bug was introduced while fixing another EncryptInterceptor issue
Apache’s own advisory is explicit that CVE-2026-34486 came from the fix for CVE-2026-29146. That earlier issue addressed a padding-oracle problem in the same component. In other words:
security fix in a security boundary
-> small refactor in receive-side error handling
-> boundary changes from fail-closed to fail-open
That sequence deserves attention well beyond Tomcat:
- the original component was already security-sensitive
- the regression occurred in exception-handling structure, not in a new feature
- the runtime symptom is easy to misread as “just a logged decrypt failure”
Teams reviewing patch trains should treat “fix for previous CVE” releases as potentially risky even when they sound purely defensive.
Why the 4 August KEV addition changes urgency
The vendor advisory has been public since April, but CISA added the issue to the Known Exploited Vulnerabilities catalog on 4 August 2026. That changes the decision-making frame.
Before KEV, many organizations could have reasonably triaged this as:
- important but configuration-dependent
- relevant mainly to clustered Tomcat estates
- patch during the next application-platform window
After KEV, the relevant question becomes:
Do we have any exposed or semi-exposed Tribes receivers on vulnerable versions,
and can we prove they are segmented well enough that exploitation is impossible?
If the answer is not an immediate, evidence-backed yes, this belongs near the top of the queue.
Detection and scoping
Start by determining whether you actually use the affected cluster path:
rg -n "EncryptInterceptor|SimpleTcpCluster|NioReceiver|Receiver className|TcpFailureDetector" \
conf server.xml webapps "$CATALINA_BASE" "$CATALINA_HOME"
Then confirm whether the cluster receiver is reachable:
ss -ltnp | rg ":4000\\b"
Review logs for the message that the vulnerable code emits on failure:
rg -n "encryptInterceptor\\.decrypt\\.failed|Failed to decrypt message" \
logs "$CATALINA_BASE/logs" /var/log/tomcat* /var/log
For packaged Linux estates, inventory downstream Tomcat packages as well as application deployments. Red Hat and NVD both list downstream affected products, so platform teams should not stop at “our application pom.xml does not mention Tomcat directly.”
The most important scoping question is:
Do we run clustered Tomcat with EncryptInterceptor enabled anywhere that a hostile
network peer, compromised internal host, or untrusted tenant can reach the receiver?
If yes, treat the exposure as real even if you have not yet proved a gadget chain in your specific application. The safe assumption is that the attack surface is unacceptable until patched or isolated.
Remediation
Patch to the fixed line for your branch:
9.0.117+10.1.54+11.0.21+
If immediate patching is blocked, reduce the attack surface while the upgrade is in flight:
- restrict the Tribes receiver port to trusted cluster members only
- disable clustering where it is not required
- confirm
EncryptInterceptorconfiguration but do not mistake its presence for protection on vulnerable versions - review whether vulnerable gadget-heavy libraries are present on the same classpath
If you have evidence of exposure or suspicious decrypt-failure activity, the incident-response path should include log review and host/application triage rather than treating the event as a routine patch-only issue.
The AppSec lesson
CVE-2026-34486 is a good reminder that “secure by wrapper” designs live or die on post-condition enforcement. EncryptInterceptor was supposed to guarantee:
only successfully decrypted bytes are dispatched
Once that invariant became:
try to decrypt, then dispatch anyway
the security boundary collapsed.
That is why this Tomcat issue belongs in the same mental category as package-manager trust bugs, provenance-validation gaps, and parser hardening regressions. The failure is not flashy. The boundary simply stops enforcing the thing operators believed they had turned on.
From research to remediation
Check whether this pattern exists in your codebase
Turn this research into a remediation workflow. Scan dependencies and package manifests for similar supply-chain risk, then prioritize fixes with reachability context.