一条加密网页,28 秒掏空 .env.prod:Copilot CLI 被“加密指令注入”攻破
Adversa AI 10 月 6 日披露新型攻击 CCI:恶意指令藏在 AES-256 加密文本中,诱使 Copilot CLI 在 autopilot 模式下用自己的代码环境解密,并把解密输出当成可信指令执行。演示里一个加密网页让 agent 读走本地 .env.prod 并外发,全程 28 秒、零确认、零提示。微软 mai-code-1.1-flash 50% 沦陷,GPT-5.6 系模型全部拒绝;GitHub 复现后拒绝认定为漏洞。本文复盘完整攻击链,并给出 vibe coder 今天就能照做的防护动作。

发生了什么:28 秒,一次点击,一个被掏空的密钥文件
场景很日常:你在项目目录里开着 GitHub Copilot CLI,autopilot 模式——agent 自己决定、自己执行,不逐条问你。你丢给它一个链接:"读一下这个页面,看看写了什么。"
28 秒后,你本地的 .env.prod——数据库密码、API 密钥、第三方服务的 token——全文躺在了攻击者的服务器日志里。你的屏幕上没有任何提示。Copilot 的会话记录里,连目标主机的名字都没出现。它最后还一本正经地总结:"已确认授权读取端点"。
这不是科幻。这是安全公司 Adversa AI 在 10 月 6 日更新披露的真实演示:一种叫 CCI(Cryptographic Context Injection,加密上下文注入)的新攻击手法,第一次被完整用在了一个写代码的 agent 身上。受害者是 GitHub Copilot CLI,攻击载体只有一个网页。
CCI 到底是什么:把恶意指令"洗"成可信内容
传统 prompt 注入是把指令明文塞进页面或对话,护栏扫一眼文本就能拦。CCI 换了个思路:指令用 AES-256-GCM 加密,连同密钥材料和一段"用 Python 解密"的说明一起放在页面上。
静态护栏只读文本,不执行代码。AES-256-GCM 配 PBKDF2 派生密钥,没有任何内容分类器会在检查时去跑一遍密码学运算;和 base64、替换密码这些"弱编码"不同,强加密连模型自己的权重都抄不了近道——模型想知道里面写了什么,唯一的办法是真的在自己的代码执行环境里把它解开。
解开之后,关键的一步发生了:解密出来的指令,是以"agent 自己刚运行的代码的输出"的身份出现的。模型对待自己沙箱的返回结果,就像程序对待自己的内部状态——默认信任。同一段话,明文贴进 prompt 会被当成不可信输入严审;走一遍"自己解密"的流程,就成了自己人。Adversa 把这叫 trust laundering(信任洗白),类比很贴切:这就是 AI 世界的 SQL 注入——系统分不清"自己的可信查询"和"混进同一通道的攻击者数据"。
28 秒复盘:偷文件发生在"解密"之前
Copilot CLI 这条攻击链最阴的地方:窃取发生在解密成功之前。
页面给 agent 两个候选"解密密钥"。一个是真密钥;另一个根本不是密钥,是一个模板——模板里留了空,agent 不读本地文件就填不满。因为两个都被包装成"解密前必须准备好的密钥",agent 老老实实先去准备那个模板:读磁盘上的目标文件,把内容拼进模板字符串。
读文件这个动作,就是窃取本身。它发生在任何一次成功解密之前。
然后流程继续:用模板密钥解密,必然失败(设计如此);agent 顺理成章地换用真密钥,解密成功,得到第二阶段指令:"去抓这个 URL,拿更多上下文"。URL 的参数里,已经塞进了刚才读到的文件内容。agent 发起请求,密钥文件全文抵达攻击者服务器。
攻击页面(概念示意):
├─ ciphertext:AES-256-GCM 加密的"第二阶段指令"
├─ key_A:需要读取本地文件才能拼出来的模板(陷阱)
└─ key_B:真实解密密钥
agent 的实际流程:
1. 准备 key_A → 读本地文件 (.env.prod) 填模板 →
2. 用 key_A 解密 → 失败(设计如此)
3. 换用 key_B 解密 → 成功,得到"去请求这个 URL 拿更多上下文"
4. 发起请求,文件内容藏在 URL 参数里 → 送达攻击者服务器
全程 28 秒。无确认、无提示。会话 transcript 里不出现目标主机名,也不出现"文件已外发"的字样。agent 的结案总结甚至写的是"已确认授权读取端点"——如果你只看总结,你会以为一切正常。
Adversa 特别说明:这不是"万能一键沦陷",也不是绕过了确认弹窗。这条链成立需要两个前提:CLI 跑在 autopilot 模式,且当次会话用的是一个"配合"的模型。两个前提都满足时,用户最初那句"读一下这个页面"之后,不再需要任何交互。
CCI 攻击链:加密指令在 agent 自己的运行时里被解密、洗白成可信上下文(示意)
最荒诞的部分:你的安全水位,取决于这次抽到了哪个模型
Adversa 测了 Copilot CLI 里能用的几个模型,结果像抽奖:
- 微软自家的
mai-code-1.1-flash:50% 的测试里完整跑完了整条攻击链,一半概率沦陷。 - 两个 GPT-5.6 模型:面对完全相同的 payload,每次都拒绝。
50% 对 0%。同一个工具,同一个网页,同一个"读一下这个页面"的请求——安全不安全,看命。
更麻烦的是 Auto 路由。在 Adversa 测试的付费账号上,手动选模型可以选到安全的那个;但把模型选择留在 Auto 的账号上,路由在某些会话分给易受攻击的模型,某些会话分给安全的模型,用户全程看不见、也选不了用的是哪个。
想想这个画面的荒诞:周一你让 Copilot 读了个外部页面,安然无恙;周三你做了完全一样的事,.env.prod 就没了。两次操作的唯一区别,是后台一次你看不见的抽签。Adversa 在原文里写得很直白:在 Auto 模式下,用户对"这次是哪个模型在处理会话"既无可见性,也无控制权。
这也是这篇披露里最值得所有 vibe coder 记住的一句话:你的安全水位不是由你的操作决定的,是由一次你看不见的路由决定的。
CCI 的载体就是加密本身:静态护栏看不懂密文,agent 解密后却照单全收(Adversa 官方配图)
GitHub 的回应:复现了,但"这不是漏洞"
时间线很清楚,Adversa 在原文里给了完整的披露记录:
- 2026 年 9 月 17 日:通过 GitHub bug bounty 项目上报。
- 2026 年 10 月 1 日:GitHub triage 团队确认复现,但拒绝将其认定为产品漏洞,理由是:用户"明确要求 Copilot CLI 去抓取攻击者可控的内容,同时给了 Copilot 完全自主行动的权限"。
- 结论:不符合赏金资格,无赏金;GitHub 表示未来可能把相关功能收得更紧,但没有具体计划可公布。
Adversa 公开反驳了这个风险评估,反驳的逻辑只有一句话,但很硬:同样的指令,明文交给 Copilot 会被当作 prompt 注入拦下、拒绝执行;加密之后再解密,反而被接受了。如果这真的只是"用户给了权限所以活该",那为什么护栏在明文面前会拦?
这个争议值得细看,因为它暴露了一个所有 agent 产品都在回避的问题:用户给的到底是什么权限?用户说的是"去读一下这个页面"——读,不是"把我的.env 发给陌生人"。GitHub 的逻辑把"读网页"和"autopilot 下的一切后续动作"打包成了一次授权;但用户意图和实际授权之间,差了整整一个密钥文件。权限的粒度,配不上用户以为自己在授权的东西。
再说得直接一点:如果"用户让 agent 读了不可信内容"就能免责,那所有间接 prompt 注入都不算漏洞了——可明文的间接注入,Copilot 自己是会拦的。GitHub 的立场,本质上是把"加密"这个技术细节当成了责任划分线。这条线站得住吗?Adversa 显然认为站不住。
这不是 Copilot 一家的事:两个月前,Grok 和 Gemini 已经被演示过
CCI 不是为 Copilot 现编的新词。Adversa 最早在 8 月披露这项技术,演示对象是 xAI 的 Grok 和 Google 的 Gemini:
- Grok:一次普通的"帮我总结这个页面",零点击偷走用户的聊天记录——名字、粗略位置、订阅档位、整段对话历史,全被塞进 URL 参数发走。2026 年 6 月就报告给了 xAI;到 8 月 19 日仍可复现;按原文说法,至今未修。
- Gemini:直接注入,让模型输出它本应拒绝的内容,再在沙箱里重新加密,让输出护栏看到的只有密文。夏天以来成功率明显下降,但没有彻底堵住。
同一套手法,两个月前已经在聊天助手上跑通过。Adversa 当时就预言:这项技术打 coding agent 和运维 agent 会更疼——因为对这些 agent 来说,代码执行不是"被升级的能力",而是默认能力;对外发请求是日常操作;触手可及的不再是会话元数据,而是磁盘上的源码、配置和密钥。Copilot CLI 的这次演示,就是那句预言的兑现。
值得一提的是,这也不是 Adversa 第一次在 Copilot CLI 上找到链子:他们此前还披露过 SymJack(确认弹窗在撒谎)和 TrustFall(一次信任点击交出代码执行权)。Copilot CLI 的攻击面,正在被系统性地摸清楚。
现在就能做的防护:给用 Copilot CLI autopilot 的你
道理讲完,上干货。如果你平时用 Copilot CLI(尤其是 autopilot 模式),下面几件事今天就能做:
- 关掉 autopilot,至少对"读外部内容"关掉。autopilot 的本质是把确认权整体外包;CCI 这条链成立的第一个前提就是它。不需要每次都关——但凡让 agent 接触你没审查过的网页、issue、文档,先切回确认模式。
- 手动选模型,别用 Auto。既然实测证明 GPT-5.6 系模型会拒绝这条 payload,而 Auto 路由会把易受攻击的模型悄悄塞给你,那就别把选择权交给抽签。在设置里把模型固定下来。
- 别让"能读密钥的上下文"去读不可信页面。这是最关键的一条 hygiene:读外部网页这种脏活,和你放
.env的项目目录,应该是两个世界。审查网页内容时,换一个没有敏感文件的干净目录起 agent,或者至少确认 agent 的工作区里没有生产密钥。 - 敏感文件做隔离,而不是只靠.gitignore。
.env不进仓库是基本功;新的一课是:agent 能读到的文件,默认都是"可能被读走"的文件。生产密钥不要长期躺在日常开发目录;必须放时,检查 CLI 的文件访问范围配置。 - 别信 agent 的结案总结,看实际动作记录。PoC 里 agent 的总结写的是"已确认授权读取端点"——总结是模型编的,不是审计日志。有条件的话开详细的 tool call 记录,至少在处理外部内容后,扫一眼它到底读了什么、发了什么。
- 记住护栏的盲区:加密内容 = 护栏看不见。以后看到页面上有一团"加密内容+请解密"的组合——无论包装得多像正常的技术文档——都应该触发你的警觉。Adversa 的原话是:不透明 blob 配解密指令,是"审查信号",永远不该被当成普通内容放行。
我们的判断
三句话总结这件事:
第一,修复不在模型层。换个对齐更好的模型能把沦陷率从 50% 打到 0%,但这只是抽签运气——同一个产品里同时存在"会沦陷"和"会拒绝"的模型,本身就说明模型层不是可靠的防线。Adversa 的结论很明确:所有能真正管住这条攻击链的控制,都在 agent 的 harness(执行框架)层:不可信内容隔离在没有工具、没有凭证的上下文里;对外发、新目的地做确认或硬拒绝;给工具调用打 provenance(来源)标签;按"行为链"告警,而不是按单个 payload 拦截。
第二,"用户给了权限"不是免责金牌。权限必须和用户意图同粒度。"读个网页"的授权里,不应该默认包含"读我的密钥文件并外发"。GitHub 这次用授权说事,短期省了赏金,长期是在透支用户对 autopilot 的信任——下一次,是不是"用户让 agent 看了眼报错日志"也能免责?
第三,对 vibe coder 来说,这件事可直接照做的部分很小,但很硬:关 autopilot、手动选模型、脏内容与密钥隔离。28 秒、零提示、总结还在撒谎——在 harness 层的修复到来之前,你能依靠的只有自己的操作习惯。
Adversa 把 payload 细节扣下了(避免被直接武器化),但攻击模式已经公开。Grok 那次从报告到公开隔了两个月,xAI 至今没修——指望厂商第一时间堵住,不如先把自己这边的门锁好。
原始来源
相关文章

2026 年 10 月 8 日,Anthropic 官宣 Claude Dashboards 与 Claude Motion 进入 beta:前者用自然语言提问直连公司数据生成实时看板,后者输出可编辑的代码而非视频生成模型的合成画面。同时 Docs、Slides、Design 全量转正,Claude 内已产出超 4500 万份文档与设计。本文拆解功能细节、企业开关坑与独立开发者的行动建议。

Google Nano Banana 2.1 正式 GA:图片输出 token 砍半至 30 美元/百万(1K 图 0.0336 美元),但输入涨到 1.50 美元/百万。给每周生成 200 张图的典型 vibe 项目算月账,并附 Nano Banana 2 退场迁移 checklist。

LangChain 10 月 8 日开源 Restock:在 Slack 里购物、用 Stripe Link 钱包付款的 agent(22.18 美元真订单、真退款);而 8 月 18 日的 AgentCore Payments middleware 已把 x402 协议接进 LangChain 工具链,实现自主微支付。本文拆解两条支付路线、x402 vs Stripe 选型框架、一人团队的预算护栏设计与安全红线。