编程 text-to-SQL agent 先选表、后鉴权,是这个安全 bug 的根源

2026-09-08 03:08:18

text-to-SQL agent 先选表、后鉴权,是这个安全 bug 的根源

作者专职做 Oracle 和 Postgres 的 text-to-SQL agent,每一个都有同一个 bug,而且不在自己的代码里——在操作顺序里

Bug

schema 在查询运行前就进了 prompt,而行级安全(row-level security)在查询运行时才生效。于是:模型看到用户读不了的表,写出完全合法的 SQL,数据库返回零行,agent 说"查无记录"——一个带着自信给出的错误答案。Vanna(23k stars,2026 年 3 月归档)就是典型:身份在模型看过一切之后的执行阶段才应用。

Fix:在选表阶段应用身份

决定模型看到哪些表这件事,要在任何 SQL 存在之前、按调用者完成。受限表不是排得低——是干脆缺席

from schemagate import Catalog, Principal

cat = Catalog().bootstrap("postgresql://localhost/app")
cat.restrict("hr_compensation", roles=["payroll"])

analyst = Principal("okta:jdoe", roles={"analyst"})
cat.select("salary by employee", principal=analyst).table_names
# 结果里没有 hr_compensation

schemagate:一个依赖、无 API key、支持任意 SQLAlchemy 数据库。

顺带的收益

现在发的是约 6 张表而不是整个 schema dump。测试 schema 上:小库 prompt token 减 65–79%,260 对象的库减 97%(每问题 16,095 → 444)。选择器从不调模型——BM25 + 哈希嵌入,离线、毫秒级。

构建中发现的坑

六个虚构 schema 在发布前揪出十个 bug。最典型:一张三列的 orders_bkp 在相关性排序里压过了真正的业务表——列名匹配不能替代业务语义判断。

实践建议

  • 权限要在表选择阶段生效:被限制的表对模型不可见,而不是"排名降低";
  • 用轻量选择器(BM25/哈希嵌入)而不是把 schema 全量塞进 prompt,顺带省 65%+ tokens;
  • 表选择器的排序规则要防"同名备份表压过真表"这类误选。

来源:Your text-to-SQL agent picks tables before security runs. Here's the fix. - DEV Community

复制全文 生成海报 AI SQL 安全 开源

推荐文章

程序员茄子在线接单