LangChain GraphCypherQAChain 的 Cypher 查询注入
一句话
据 NVD 与 GHSA,LangChain GraphCypherQAChain 可在 prompt injection 影响下让 LLM 生成的 Cypher 查询进入图数据库执行,属于 ToLO-SQL(广义查询执行子类)。
公开事实与待核验
| 项 | 本页采用的读法 |
|---|---|
| 公开来源明确支持 | CVE-2024-8309、GraphCypherQAChain、prompt injection、LLM 生成 Cypher 查询、图数据库执行。 |
| ToLO 解释 | S_LLM^{framework} 生成查询结构,进入数据库查询执行 sink;按广义 ToLO-SQL 读。 |
| 版本状态 | NVD 与 GHSA 对 affected/fixed 版本口径不同。 |
为什么 pending | 本页保留 NVD 与 GHSA 差异;commit/release 可解释 repair pattern,但不把版本冲突合并成单一结论。 |
怎么读这个案例
这个案例适合用来理解:ToLO-SQL 不只指 SQL 方言,也包括 LLM 生成数据库查询结构并执行的场景。
- Cypher = Neo4j 图数据库的查询语言
- GraphQL = 另一种查询语言
- SPARQL = RDF / 知识图谱查询语言
- SQL = 关系型数据库
它们都属于”应用让 LLM 生成查询语句,然后数据库引擎执行”的同一种 ToLO 模式。ToLO-SQL 这个名字按 sink 语义(数据库查询)分组,不按方言分组。
为什么不新建 ToLO-Cypher?
因为:
- sink 语义相同:数据库执行 LLM 控制的查询字符串。
- 修复方向相同:文件 sandbox 在 BI 类工具里都没用,关键都是最小权限账号 + 表/列 allowlist + 模板化查询。
- 检测规则相似:CodeQL
python/sql-injection库扩展到包含 Cypher driver 就够了。
如果未来发现某种查询语言的修复方式完全不同于 SQL,再考虑新建子类。
影响组件
影响组件是 GraphCypherQAChain 图数据库问答链(对应 Neo4j、Memgraph 等图数据库)。
| 来源 | affected_versions | fixed_in |
|---|---|---|
| NVD | langchain 0.2.5 | — |
| GHSA | langchain <0.2.0,langchain-community >=0.2.0, <0.2.19 | langchain 0.2.0,langchain-community 0.2.19 |
版本口径不一致,因此本站保持 verification: pending。
ToLO 路径
| 列 | 内容 |
|---|---|
| Source | S_LLM^{framework} —— 链内 LLM 为用户问题生成的 Cypher 查询文本 |
| Transform | 用户输入经 prompt 进入查询生成链,输出被传递给 graph QA 执行逻辑 |
| Sink | 图数据库查询执行接口(session.run(cypher_query) 等;ToLO-SQL,广义查询;公开来源按 CWE-89 归类) |
| Guard 缺失 | 缺少与数据库 sink 匹配的 C_SAFE^{capability} 与最小权限约束;单纯类型检查不能证明查询安全 |
| Impact | 公开来源描述为 prompt injection 可导致未授权、数据相关的数据库操作风险;具体后果取决于数据库账号权限 |
| Repair pattern | 默认拒绝危险链初始化,要求显式确认,并提示使用受限数据库凭据 |
虽然 Cypher 不是 SQL,但安全语义接近:LLM 输出决定数据库查询结构,并由数据库引擎执行。本站把它归入 ToLO-SQL 的广义查询执行子类。
教学骨架
from langchain.chains import GraphCypherQAChainfrom langchain_community.graphs import Neo4jGraph
graph = Neo4jGraph(url="bolt://localhost:7687", username="neo4j", password="...")chain = GraphCypherQAChain.from_llm(llm=ChatOpenAI(), graph=graph)
# 修复前的关键风险形态:模型生成查询后,框架把查询交给图数据库执行。result = chain.invoke({"query": "我们公司有几个员工?"})
# 内部:# prompt 引导 LLM 生成 Cypher:# MATCH (e:Employee) RETURN COUNT(e)# graph.query(cypher) → session.run(cypher) → Neo4j 执行## 风险点不是某条具体 Cypher,而是 LLM 可能影响查询结构,# 而图数据库会按当前账号权限执行该查询。修复方式
据 langchain-community==0.2.19 release note 与 commit 64c317eba05fbac0c6a6fc5aa192bc0d7130972e,上游为 graph QA chains 增加 allow_dangerous_requests: bool = False,默认拒绝初始化,要求调用方显式确认风险,并提示数据库凭据必须窄权限化。
伪代码示意修复后的 chain 初始化:
class GraphCypherQAChain: def __init__(self, llm, graph, allow_dangerous_requests: bool = False): if not allow_dangerous_requests: raise ValueError( "GraphCypherQAChain is not safe to use without " "additional safeguards. Set allow_dangerous_requests=True " "to proceed. Make sure your DB user has restricted permissions." ) ...修复属于哪一类 C_SAFE?
主要属于 C_SAFE^{capability} —— 但是最弱形式:explicit approval(显式批准)。
显式批准 (explicit approval) ⊂ C_SAFE^{capability}它的作用:
- 把风险知情责任从框架转给调用方。
- 让调用方在
=True前必须读 doc,看到”DB 凭据必须窄权限化”的提示。
它的局限:
- 调用方常常无视提示直接
=True,实际部署仍然危险。 - 不强制配数据库最小权限。
- 不收窄LLM 可生成的查询语言。
这个修复更接近 capability / explicit approval,而不是传统 SQL 参数化。原因是:text-to-query 功能让 LLM 生成整条查询语句,参数化不能完整解决结构级风险,只能依赖权限收缩、显式启用和查询能力限制。
为什么仍保持 pending
- NVD 写法与 GHSA 写法覆盖的包名和版本范围不同,本页保留两者。
allow_dangerous_requests能改变默认使用边界,但它不是查询 parser,也不强制数据库账号只读。- 数据影响取决于 Neo4j/Memgraph 等实际账号权限;公开 advisory 不足以替所有部署推断最终后果。
更彻底的修复方向
| 防御层 | 具体做法 |
|---|---|
C_SAFE^{capability}(数据库) | 用专门的 read-only 账号,DELETE / DETACH 在数据库层就被拒绝 |
C_SAFE^{allowlist}(查询能力) | 在执行前用 Cypher parser 检查 query,只允许 MATCH / RETURN / WHERE |
C_SAFE^{schema}(查询结构) | 不让 LLM 写完整 Cypher,只让它选预制查询模板 + 填参数 |
| 监控 + audit log | 记录所有 LLM-driven query,事后追溯 |
allow_dangerous_requests=False 本身只是第一步。
对 ToLO 分类的启发
该案例支持 ToLO-SQL 的广义子类(数据库查询 sink)。
危险点不在传统 HTTP 参数拼接,而在框架把 LLM 生成查询视为可执行数据库指令。修复没有引入新 sink 子类,重点转向工具/执行边界处的能力门控与数据库权限收缩。
它也提示 ToLO-SQL 名称应按 “数据库查询 sink” 理解,而不是只覆盖 SQL 方言。Cypher、GraphQL resolver、ORM raw query、SPARQL 等只要让 LLM 控制查询结构,都可以按同一类先分析。
学习者要带走什么
- 查询语言不同,信任问题相同:LLM 是否能控制查询结构。
- Text-to-query 场景很难只靠传统参数化解决,因为结构本身由模型生成。
allow_dangerous_requests这类显式开关更像风险确认和 capability 提示,不能替代数据库最小权限。- 写检测规则时,sink 集合应包含所有”数据库查询执行 API”,不只是
cursor.execute。
读完检查
为什么这个案例更适合放进 ToLO-SQL,而不是新建 ToLO-Cypher?
→ 因为两者共享 “LLM 输出进入数据库查询执行” 这一 sink 语义。开新子类需要新的 sink 语义和新的 sanitizer 适配,这里都没有 —— 修复策略(只读账号 + allowlist + 模板化)对 SQL 和 Cypher 都成立。
另一个问题:如果应用配置了 read-only 数据库账号,这个案例还构成 ToLO 吗?
→ 部分构成。Read-only 阻止了 DELETE / UPDATE,但 SELECT 仍可被攻击者影响 —— 例如让模型生成”用 IN 子句枚举所有 user_id 让数据库 timeout”(DoS),或”通过 Cypher 的 patterns 偷其他用户的数据”。所以最小权限只是一层,还需要表/列 allowlist。
公开来源
- https://nvd.nist.gov/vuln/detail/CVE-2024-8309
- https://github.com/advisories/GHSA-45pg-36p6-83v9
- https://github.com/langchain-ai/langchain/releases/tag/langchain-community%3D%3D0.2.19
- https://github.com/langchain-ai/langchain/commit/64c317eba05fbac0c6a6fc5aa192bc0d7130972e
下一步阅读
- Core ToLO Patterns §ToLO-SQL:text-to-SQL 的通用防御要点。
- CVE-2024-5826 Vanna AI:同样 text-to-SQL 链路 + 可视化 Exec,典型多路径案例。
- Defensive Patterns §
C_SAFE^{capability}:capability 五种形态,explicit approval 是其中最弱的。