
CVE-2026-23552 - Cross-Realm Token Acceptance in camel-keycloak
Apache Camel's KeycloakSecurityPolicy does not validate the iss (issuer) claim of JWT tokens against the configured realm. This means a token issued by one Keycloak realm is silently accepted by a policy configured for a completely different realm, breaking tenant isolation.
Affected versions: 4.15.0, 4.16.0, 4.17.0
Tracked at: https://issues.apache.org/jira/browse/CAMEL-22854
In KeycloakSecurityHelper.parseAccessToken(), when no public key is explicitly provided (which is the default configuration), the token is only decoded from Base64 -- it is never verified:
public static AccessToken parseAccessToken(String tokenString, PublicKey publicKey)
throws VerificationException {
if (publicKey != null) {
return TokenVerifier.create(tokenString, AccessToken.class)
.publicKey(publicKey)
.verify()
.getToken();
} else {
// no signature verification, no issuer check
return TokenVerifier.create(tokenString, AccessToken.class).getToken();
}
}
Since the default code path hits the else branch, three things go unchecked:
iss claim is never compared to the expected {serverUrl}/realms/{realm}The role check still passes because it only looks at role names inside the token payload. If the role name (tenant-user) happens to match across realms -- which is common in multi-tenant setups -- the request goes through.
In a multi-tenant application where each tenant maps to a separate Keycloak realm, a user from tenant A can access routes protected for tenant B. Concretely:
This project demonstrates the vulnerability using Apache Camel 4.17.0 and a local Keycloak instance.
jbang app install camel@apache/camel)camel infra under the hood)Start a local Keycloak:
camel infra run keycloak
This starts Keycloak on localhost:8080 with admin credentials admin/admin.
mvn verify
The integration test (CrossRealmTokenBypassIT) does the following:
acme and globextenant-user realm role in both realmsalice (password alice123) in the acme realm and assigns her the tenant-user roledirect:globex-protected) guarded by a KeycloakSecurityPolicy bound to the globex realmalice from the acme realm (issuer: http://localhost:8080/realms/acme)The request succeeds. The acme token passes the globex policy without any error.
| Test | Result | Meaning |
|---|---|---|
testAcmeTokenIsObtainable | PASS | Sanity check -- token acquisition works |
testCrossRealmTokenAccepted | PASS | Confirms the vulnerability is present |
testCrossRealmTokenShouldBeRejected | FAIL | Documents correct behavior -- on 4.17.0 no exception is thrown |
On a patched version (4.18.0+), the second test would fail and the third would pass.
camel infra stop keycloak
The test also removes the acme and globex realms in @AfterAll.
The KeycloakSecurityPolicy should reject tokens where the iss claim does not match {serverUrl}/realms/{realm}. The fix is tracked in CAMEL-22854 and will ship with Camel 4.18.0 (the next LTS release).