CVE-2026-97468
Patch Available.
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Apache CXF is an open-source services framework, maintained by the Apache Software Foundation, for building and consuming web services in Java. It implements the JAX-WS and JAX-RS APIs and supports SOAP, the WS-* standards, RESTful HTTP, and OAuth 2.0 over transports such as HTTP and JMS. Its modules are published as Maven artifacts under org.apache.cxf.
A weak authentication vulnerability (CVE-2026-97468) has been identified in the STSTokenValidator and the Security Token Service (STS) of Apache CXF, which allows attackers to authenticate as another user by presenting a crafted security token whose hash collides with a previously validated, cached token. Through STS token validation or renewal, the attacker can also obtain STS-signed tokens for that identity.
Per OWASP: When an attacker is able to trick a system into recognizing an invalid or incorrect user as legitimate, this vulnerability is present.
This issue affects multiple versions of Apache CXF.
Details
Module Info
- Product: Apache CXF
- Affected packages:
org.apache.cxf:cxf-rt-ws-security - Affected versions: <3.6.13, >=4.0.0 <4.1.9, >=4.2.0 <4.2.4
- GitHub repository: https://github.com/apache/cxf
- Published packages: https://central.sonatype.com/artifact/org.apache.cxf/cxf-rt-ws-security
- Package manager: Maven
- Fixed in:
- OSS Apache CXF 3.6.13, 4.1.9, 4.2.4
- NES for Apache CXF v3.4.13, v3.5.14
Vulnerability Info
This High-severity vulnerability is found in the org.apache.cxf:cxf-rt-ws-security package in multiple versions of Apache CXF. To avoid repeating expensive work, the STSTokenValidator and the STS token validators cache tokens they have already validated. The cache key is a non-cryptographic 32-bit Java hash of the presented token: Arrays.hashCode over a SAML Assertion's signature value, or hashCode() of a UsernameToken, BinarySecurityToken or SecurityContextToken. A later request whose token produces the same hash is treated as already validated.
In STSTokenValidator.validateWithSTS, a cache hit returns the cached transformed token and the credential is accepted without calling the STS:
int hash = 0;
if (credential.getSamlAssertion() != null) {
SamlAssertionWrapper assertion = credential.getSamlAssertion();
byte[] signatureValue = assertion.getSignatureValue();
if (signatureValue != null && signatureValue.length > 0) {
hash = Arrays.hashCode(signatureValue);
}
tokenElement = credential.getSamlAssertion().getElement();
} else if (credential.getUsernametoken() != null) {
tokenElement = credential.getUsernametoken().getElement();
hash = credential.getUsernametoken().hashCode();
}
...
if (ts != null && hash != 0) {
SecurityToken transformedToken = getTransformedToken(ts, hash);
if (transformedToken != null && !transformedToken.isExpired()) {
SamlAssertionWrapper assertion = new SamlAssertionWrapper(transformedToken.getToken());
credential.setPrincipal(new SAMLTokenPrincipalImpl(assertion));
credential.setTransformedToken(assertion);
return credential;
}
}
The lookup in getTransformedToken only checks that the stored hash equals the computed one:
SecurityToken recoveredToken = ts.getToken(Integer.toString(hash));
if (recoveredToken != null && recoveredToken.getTokenHash() == hash) {
The STS UsernameTokenValidator follows the same pattern. When the token store holds an entry under ut.hashCode(), the password check in validator.validate is skipped entirely:
int hash = ut.hashCode();
SecurityToken secToken = null;
if (tokenParameters.getTokenStore() != null) {
secToken = tokenParameters.getTokenStore().getToken(Integer.toString(hash));
if (secToken != null && (secToken.getTokenHash() != hash || secToken.isExpired())) {
secToken = null;
}
}
The SAML token validator, the SAML token renewer and the STS cache utilities key their entries on Arrays.hashCode of the signature value in the same way. Because a 32-bit hash can be collided by an attacker who controls the token contents, a crafted UsernameToken or self-signed SAML Assertion that hashes to the same value as a cached token from a legitimate user is accepted without password validation, signature trust verification or a call to the STS. The attacker is then authenticated as that user and can use STS validation or renewal to obtain STS-signed tokens for the same identity.
Mitigation
Only recent versions of Apache CXF are community-supported. Older lines are End-of-Life and will not receive public updates to address this issue.
Users of the affected components should apply one of the following mitigations:
- Upgrade to a currently supported Apache CXF release line (3.6.x or later) that contains the fix.
- Leverage a commercial support partner like HeroDevs for post-EOL security support.
Credits
- MopMonk-AI (finder)