Skip to content

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?

因为:

  1. sink 语义相同:数据库执行 LLM 控制的查询字符串。
  2. 修复方向相同:文件 sandbox 在 BI 类工具里都没用,关键都是最小权限账号 + 表/列 allowlist + 模板化查询
  3. 检测规则相似:CodeQL python/sql-injection 库扩展到包含 Cypher driver 就够了。

如果未来发现某种查询语言的修复方式完全不同于 SQL,再考虑新建子类。

影响组件

影响组件是 GraphCypherQAChain 图数据库问答链(对应 Neo4j、Memgraph 等图数据库)。

来源affected_versionsfixed_in
NVDlangchain 0.2.5
GHSAlangchain <0.2.0,langchain-community >=0.2.0, <0.2.19langchain 0.2.0,langchain-community 0.2.19

版本口径不一致,因此本站保持 verification: pending

ToLO 路径

内容
SourceS_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 GraphCypherQAChain
from 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 控制查询结构,都可以按同一类先分析

学习者要带走什么

  1. 查询语言不同,信任问题相同:LLM 是否能控制查询结构。
  2. Text-to-query 场景很难只靠传统参数化解决,因为结构本身由模型生成。
  3. allow_dangerous_requests 这类显式开关更像风险确认和 capability 提示,不能替代数据库最小权限
  4. 写检测规则时,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。

公开来源

下一步阅读