
CVE-2026-23552 - Cross-Realm Token Acceptance in camel-keycloak
Le KeycloakSecurityPolicy d'Apache Camel ne valide pas la revendication iss (émetteur) des tokens JWT par rapport au realm configuré. Cela signifie qu'un token émis par un realm Keycloak est silencieusement accepté par une politique configurée pour un realm complètement différent, brisant l'isolation des locataires.
Versions affectées : 4.15.0, 4.16.0, 4.17.0
Suivi sur : https://issues.apache.org/jira/browse/CAMEL-22854
Dans KeycloakSecurityHelper.parseAccessToken(), lorsqu'aucune clé publique n'est explicitement fournie (ce qui est la configuration par défaut), le token est seulement décodé depuis le Base64 -- il n'est jamais vérifié :
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();
}
}
Comme le chemin de code par défaut emprunte la branche else, trois choses ne sont pas vérifiées :
iss n'est jamais comparée à l'attendu {serverUrl}/realms/{realm}La vérification du rôle réussit toujours car elle ne regarde que les noms de rôles dans le payload du token. Si le nom du rôle (tenant-user) correspond entre les realms -- ce qui est courant dans les configurations multi-locataires -- la requête passe.
Dans une application multi-locataire où chaque locataire correspond à un realm Keycloak distinct, un utilisateur du locataire A peut accéder à des routes protégées pour le locataire B. Concrètement :
Ce projet démontre la vulnérabilité en utilisant Apache Camel 4.17.0 et une instance Keycloak locale.
jbang app install camel@apache/camel)camel infra en coulisses)Démarrer un Keycloak local :
camel infra run keycloak
Cela démarre Keycloak sur localhost:8080 avec les identifiants admin admin/admin.
mvn verify
Le test d'intégration (CrossRealmTokenBypassIT) effectue ce qui suit :
acme et globextenant-user dans les deux realmsalice (mot de passe alice123) dans le realm acme et lui attribue le rôle tenant-userdirect:globex-protected) protégée par un KeycloakSecurityPolicy lié au realm globexalice depuis le realm acme (émetteur : http://localhost:8080/realms/acme)La requête réussit. Le token acme passe la politique globex sans erreur.
| Test | Result | Meaning |
|---|
Sur une version patchée (4.18.0+), le deuxième test échouerait et le troisième réussirait.
camel infra stop keycloak
Le test supprime également les realms acme et globex dans @AfterAll.
Le KeycloakSecurityPolicy devrait rejeter les tokens dont la revendication iss ne correspond pas à {serverUrl}/realms/{realm}. Le correctif est suivi dans CAMEL-22854 et sera livré avec Camel 4.18.0 (la prochaine version LTS).
testAcmeTokenIsObtainable | RÉUSSI | Vérification de base -- l'acquisition du token fonctionne |
testCrossRealmTokenAccepted | RÉUSSI | Confirme que la vulnérabilité est présente |
testCrossRealmTokenShouldBeRejected | ÉCHEC | Documente le comportement correct -- sur 4.17.0 aucune exception n'est levée |