
CVE-2026-88900(camel-jgroups의 안전하지 않은 Java 역직렬화 취약점)을 재현하는 실행 가능한 Spring Boot 개념 증명으로, 취약한 동작과 패치된 동작을 비교해 보여줍니다.
jgroups consumer가 필터 없이 클러스터 메시지를 Java 역직렬화하는 Apache Camel 취약점에 대한 실행 가능한 개념 증명(PoC) 재현기입니다. JGroupsEndpoint.createExchange(Message) — consumer가 수신하는 모든 메시지에 대해 호출됨 — 는 org.jgroups.Message.getObject()로부터 exchange body를 설정했습니다. ObjectMessage(Camel jgroups producer가 전송하는 유형)의 경우, JGroups는 메시지가 도착할 때 ObjectInputStream을 통해 페이로드를 Java 역직렬화하며, getObject()는 그 결과를 반환합니다. java.io.ObjectInputFilter가 적용되지 않았으므로, 클러스터로부터 수신된 애플리케이션 클래스패스상의 모든 직렬화 가능 클래스가 인스턴스화되고 그 역직렬화 콜백이 실행되었습니다 — 사용 가능한 gadget chain이 존재할 경우 원격 코드 실행으로 이어집니다. 기본 new JChannel() 스택(UDP 멀티캐스트, AUTH 없음, 암호화 없음)에서는 클러스터에 접근할 수 있는 모든 호스트가 자격 증명 없이 이러한 메시지를 전송할 수 있습니다(CWE-502).
Spring Boot 전용. 이 재현기는 단일 Camel Spring Boot 모듈을 제공합니다.
camel-jgroups에는camel-quarkus-jgroups확장이 없으므로 재현할 Quarkus 대응물이 없습니다. Spring Boot 모듈은 영향을 받는 동작 및 수정된 동작을 모두 보여줍니다.
| 런타임 | 디렉터리 | 스택 |
|---|---|---|
| Camel Spring Boot | camel-spring-boot/ | Spring Boot 3.5.13 + camel-jgroups 4.22.0 (영향 받음; 4.22.1에서 수정) |
무해한 공격자 객체 — com.example.Marker는 수정 사항의 기본 허용 목록(java.**, javax.**, org.apache.camel.**)에 없는 일반 애플리케이션 클래스입니다 — 가 JGroups 전송 형식으로 직렬화되어 실제 JGroupsEndpoint.createExchange(...)에 전달되며, 이 메서드는 Message.getObject()로 이를 읽습니다(consumer가 수신하는 모든 메시지에 대해 수행하는 것과 동일한 호출). 채널이나 멀티캐스트가 필요 없으므로 검사는 결정적입니다. Marker.readObject는 플래그를 뒤집어 역직렬화 콜백이 실행됨을 보여줍니다 — 실제 gadget chain은 바로 그 지점에서 유해한 코드를 실행할 것입니다; 이 재현기에는 gadget이 포함되어 있지 않습니다.
com.example.Marker를 거부하고 createExchange가 JGroupsException을 발생시킵니다; 객체는 라우트에 도달하지 않습니다.솔직한 주의 사항(권고문에 명시된 대로): 4.22.1 / 4.18.5의 클래스 검사는 JGroups가 페이로드를 역직렬화한 후에 실행되므로,
readObject콜백은 수정된 빌드에서도 여전히 실행됩니다 — 이는 **심층 방어(defense-in-depth)**입니다. 역직렬화 중에 실행되는 코드를 막으려면 JVM 전역-Djdk.serialFilter를 설정하고AUTH+ 암호화로 채널을 보호해야 합니다; 4.23.0은 추가로 이러한 제어 중 하나가 구성되지 않으면 consumer 시작을 거부합니다. 이 재현기는 클래스 검사 차이를 보여주며, 콜백 실행 플래그를 통해 주의 사항을 가시화합니다.
cd camel-spring-boot
mvn clean package
docker compose up -d --build
curl -s http://localhost:8080/exploit/attack # affected: Marker deserialized + routed; >>> PROVEN
docker compose down
# Patched control
mvn clean package -Dcamel.version=4.22.1
java -jar target/cve-2026-88900-jgroups-deserialization-0.0.1-SNAPSHOT.jar &
curl -s http://localhost:8080/exploit/attack # fixed: JGroupsException rejects com.example.Marker; >>> Not exploited
| 속성 | 값 |
|---|---|
| 구성 요소 | camel-jgroups (JGroupsEndpoint.createExchange) |
| CWE | CWE-502 (신뢰할 수 없는 데이터의 역직렬화) |
| 심각도 | HIGH |
| 공격 벡터 | 클러스터의 멀티캐스트 그룹 / 바인드 포트에 접근할 수 있는 호스트가 조작된 ObjectMessage를 전송하며, 컨슈머는 필터 없이 이를 역직렬화함 |
| 영향 | 클래스패스에 가젯 체인이 존재할 경우 Camel 프로세스에서 원격 코드 실행 가능, 그렇지 않으면 임의 클래스 인스턴스화 |
| 영향받는 버전 | 4.0.0 이상 4.18.5 미만, 4.19.0 이상 4.22.1 미만 |
| 수정된 버전 | 4.18.5, 4.22.1, 4.23.0 |
| JIRA | CAMEL-24676, CAMEL-25223 |
| 보고자 | h1ei1 |
권고문: https://camel.apache.org/security/CVE-2026-88900.html
JGroupsEndpoint는 이제 새로운 deserializationFilter 옵션(jdk.serialFilter
구문)을 통해 익스체인지가 라우팅되기 전에 Message.getObject()가 반환한 본문의 클래스를 검사합니다. 이 옵션이
설정되지 않은 경우, JVM 전역 jdk.serialFilter가 존재하면 이를 따르고, 그렇지 않으면 보수적인 기본 허용 목록이
java.**/javax.**/org.apache.camel.**을 허용하고 java.net.**을 거부하며 그 외의 모든 것은 거부합니다. 거부된
메시지는 컨슈머의 ExceptionHandler에 보고되며 라우팅되지 않습니다. 4.23.0(CAMEL-25223)에서는 역직렬화 이전에
작동하는 제어 수단(JVM 전역 필터, jgroups.deserialization.filter 시스템 속성, 또는 AUTH+암호화 채널)이 구성되지
않으면 컨슈머가 시작을 거부합니다. acceptAllObjects=true는 이전 동작을 복원하며 안전하지 않은 설정으로
표시됩니다.
컨슈머를 실행하는 JVM에 -Djdk.serialFilter를 설정하고(라우트가 클러스터를 통해 교환하는 클래스만 허용),
channelProperties 옵션을 통해 AUTH와 SYM_ENCRYPT/ASYM_ENCRYPT로 채널을 보호하며, 클러스터의 멀티캐스트
그룹이나 바인드 포트를 신뢰할 수 없는 네트워크에 노출하지 마십시오.
이 저장소는 교육 및 방어 목적으로 게시되었습니다. 즉, Apache Camel 사용자가 취약점을 이해하고, 영향을 받는지 확인하며, 업그레이드가 문제를 해결하는지 검증할 수 있도록 돕기 위한 것입니다. 역직렬화되는 객체는 이 저장소에 정의된 무해한 마커 클래스이며, 가젯 체인을 포함하지 않고 유해한 동작도 수행하지 않습니다. 소유하거나 운영하지 않는 시스템에 이 자료를 사용하지 마십시오.