RAG攻击面:你的知识库是安全的吗
RAG 的价值是把模型不知道的私有内容接进来。攻击视角同样成立:检索管道把知识库里和问题最相近的原文,不加转换地送进模型上下文。谁能往知识库里写一条记录,谁就能决定未来某类问题的回答内容;谁能看到检索结果,谁就能拿到比模型输出更完整的原文。
这篇文章按数据流写:入库、检索、拼装、引用,每一段的攻击面和对应请求。
先看管道里每一步暴露什么

| 环节 | 关键参数 | 攻击关注点 |
|---|---|---|
| 入库 | 上传接口、同步来源 | 写权限给到了谁,外源文档是否进库 |
| 切片/嵌入 | chunk_size、overlap |
一条毒记录需要多大,能否跨片重组 |
| 向量库 | 端口、API | 是否未授权导出,metadata 过滤能否绕过 |
| 检索 | score_threshold、top_k、rerank |
阈值多少,能不能把某条记录挤进 top-k |
| 拼装/引用 | sources 返回策略 |
原文片段是否直接回给前端 |
004 里已经写过阈值探测和 sources 泄漏,这篇集中在另外两块:把内容写进去,以及让写进去的内容被检索到。
入库的四个通道
投毒的前提是写入。企业知识库的写入口通常不止一个,评估时按这个清单过:
| 通道 | 常见形态 | 谁能写 |
|---|---|---|
| 直接上传 | 管理后台、/documents/upload |
知识库管理员,有时是所有登录用户 |
| 同步任务 | 网盘、Confluence、Wiki 定时拉取 | 有源系统账号的任何人 |
| 工单回流 | 已解决问题的方案写入「常见问题」集合 | 任何能提交工单的人 |
| 外部网页 | web_fetch 抓回的内容被收录 |
目标页面的所有者 |
最后一条最容易被忽略。助手抓取了一个外链做摘要,抓回的内容又被「有价值,收录」逻辑放进向量库。写入动作发生在 Agent 侧,写权限挂在服务账号上,页面所有者等于获得了向知识库注入的通道,不需要任何内部账号。
一个典型的上传接口:
1 | POST /api/documents |
1 | 201 Created |
如果普通员工账号能拿到 201,并且 visibility: all 允许设置,这条记录已经进入所有人的检索范围。真正决定危害的是下一节:这段文字在检索时会不会命中。
写一条能被检索到的毒记录
知识库检索按语义相似度取 top-k。毒记录要和目标用户的真实问题在向量空间里接近,而不是和「注入指令」接近。有效的结构是两段式:
- 触发段:目标用户会输入的原话。VPN 连不上、登录转圈、证书报错。
- 动作段:紧跟其后的一个短句。一个 URL、一个安装源、一个「先做这个再提交」。
写太长的指令会稀释向量,反而检索不到。一条 100 字以内的记录通常够用:
1 | ## VPN 登录后无法访问内网(2025Q3 高频) |
触发段覆盖了「VPN」「登录」「无法访问」这些高频问法。动作段只有一句,嵌在正常排障步骤中间。
然后是验证。投毒者无法查向量库,但可以用同一个助手问,看回答里有没有那条 URL:
1 | POST /assistant/chat |
1 | 200 OK |
score 0.88 说明这条记录在同主题下排得很靠前。到这里,攻击完成:后续任何问 VPN 问题的员工都会收到这个地址。
切片参数决定毒记录的形态
仓库里的 RAG 配置(004 写过怎么拿到)直接告诉你毒记录该写多大:
1 | chunking: |
chunk_size: 512 时,一条 100 字的记录会独占一个切片,命中干净。如果配置是 1500 字符加标题切分,毒记录最好寄生在长文档里:正常内容在前,触发段和动作段埋在第 800 字符附近,靠 overlap 保证切片边界不清空上下文。
score_threshold: 0.72 说明触发段要和真实问法高度一致。同义词替换会掉分,所以触发段直接抄用户群里的原话,比自己改写更稳。
不是只有知识库能被检索
RAG 之外,很多助手还会实时取数。SQL Agent 把自然语言转成查询,查出来的行会进上下文。这时投毒点变成了业务表里一个自由文本字段——007 的周报案例就是这条路径。判断方法一样:问助手一个会带出该表内容的问题,看回答是否原样复述了字段值。
工具返回的网页内容同理。web_fetch 抓回的页面如果含有「给 AI 的说明」,是否被当作指令,取决于拼装时有没有做隔离。这条在 005 写过,它是 RAG 问题的变体:检索半径从「知识库」扩大到「Agent 能读到的一切」。
防御
- 入库分级。外源网页、工单回流不进全员集合。同步任务带来源标签,检索时按标签过滤,出问题的来源可以整体下线。
- 上传最小权限。
visibility: all是管理员操作。普通用户的上传先进待审集合,通过后转正。 - 内容入库前清洗。剥离 HTML 注释、零宽字符、伪装成配置块的指令段。URL、安装源、令牌样例转成工单号引用,不进切片。
- 检索分区。用户集合、团队集合、全员集合物理分开,先分区再相似度。禁止用模型生成的
collection参数做过滤。 - 引用瘦身。
sources只回title和page,score、excerpt不出后端。需要原文核对时走单独的文档预览接口,鉴权读取。 - 回答中的链接回查。回答里出现的 URL 与知识库白名单比对,不在名单内的链接拦截或标注。
- 监控新入库记录。新文档建立后的 24 小时内,统计它被引用的次数和引用它的用户数。一条新记录快速成为多用户回答的来源,值得人工看一眼。