
CVE-2026-23552 - camel-keycloak의 교차 영역 토큰 수용
Apache Camel의 KeycloakSecurityPolicy는 JWT 토큰의 iss(발급자) 클레임을 구성된 렐름에 대해 검증하지 않습니다. 즉, 한 Keycloak 렐름에서 발급된 토큰이 완전히 다른 렐름을 위해 구성된 정책에 의해 조용히 수락되어 테넌트 격리가 깨집니다.
영향을 받는 버전: 4.15.0, 4.16.0, 4.17.0
추적: https://issues.apache.org/jira/browse/CAMEL-22854
KeycloakSecurityHelper.parseAccessToken()에서 공개 키가 명시적으로 제공되지 않으면(기본 구성), 토큰은 Base64에서 디코딩만 될 뿐이며 검증되지는 않습니다:
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();
}
}
기본 코드 경로가 else 분기에 도달하므로 세 가지가 확인되지 않습니다:
iss 클레임이 예상되는 {serverUrl}/realms/{realm}와 비교되지 않습니다역할 검사는 토큰 페이로드 안의 역할 이름만 확인하므로 여전히 통과합니다. 역할 이름(tenant-user)이 여러 렐름에 걸쳐 우연히 일치하면(멀티 테넌트 구성에서 흔한 경우) 요청이 통과됩니다.
각 테넌트가 별도의 Keycloak 렐름에 매핑되는 멀티 테넌트 애플리케이션에서 테넌트 A의 사용자가 테넌트 B를 위해 보호되는 라우트에 접근할 수 있습니다. 구체적으로:
이 프로젝트는 Apache Camel 4.17.0과 로컬 Keycloak 인스턴스를 사용하여 취약점을 시연합니다.
jbang app install camel@apache/camel)camel infra가 사용)로컬 Keycloak을 시작합니다:
camel infra run keycloak
이 명령은 localhost:8080에서 관리자 자격 증명 admin/admin으로 Keycloak을 시작합니다.
mvn verify
통합 테스트(CrossRealmTokenBypassIT)는 다음을 수행합니다:
acme 및 globex라는 두 개의 렐름을 생성합니다tenant-user 렐름 역할을 생성합니다acme 렐름에 사용자 alice(비밀번호 alice123)를 생성하고 tenant-user 역할을 할당합니다globex 렐름에 바인딩된 KeycloakSecurityPolicy로 보호되는 Camel 라우트(direct:globex-protected)를 설정합니다acme 렐름에서 alice의 JWT 토큰을 획득합니다(발급자: http://localhost:8080/realms/acme)요청은 성공합니다. acme 토큰은 오류 없이 globex 정책을 통과합니다.
| 테스트 | 결과 | 의미 |
|---|---|---|
testAcmeTokenIsObtainable | PASS | 기본 확인 -- 토큰 획득이 정상 동작함 |
패치된 버전(4.18.0+)에서는 두 번째 테스트가 실패하고 세 번째 테스트가 통과할 것입니다.
camel infra stop keycloak
테스트는 또한 @AfterAll에서 acme 및 globex 렐름을 제거합니다.
KeycloakSecurityPolicy는 iss 클레임이 {serverUrl}/realms/{realm}와 일치하지 않는 토큰을 거부해야 합니다. 수정 사항은 CAMEL-22854에서 추적되며 Camel 4.18.0(다음 LTS 릴리스)에 포함될 예정입니다.
testCrossRealmTokenAccepted | PASS | 취약점이 존재함을 확인함 |
testCrossRealmTokenShouldBeRejected | FAIL | 올바른 동작을 문서화함 -- 4.17.0에서는 예외가 발생하지 않음 |