Cursor 给你装的扩展,把凭证带走了
打开你 Cursor 项目根目录,看一眼有什么——.env 装着数据库密码、.git/config 写着 OAuth token、~/.aws/credentials 是 prod 资源凭证。
现在看你装了多少扩展。
这些扩展跑在 extension host 进程里,向 IDE 申请 workspace 权限读项目目录文件——你的凭证在它们的视野里。它们不需要越权,不需要漏洞,光靠 IDE 给它们的合法读权限,就能把你 .env 里的内容读走。
这是 web 时代踩过的同一道题
20 年前 Chrome 扩展能读所有 cookie——一个广告拦截扩展,理论上能把你登录 Gmail 的 session 一起带走。后来 Chrome 加了 host_permissions 颗粒度、加了 manifest v3、加了用户授权确认——花了十几年才把"扩展 = 同进程"这道边界画对位置。
IDE 没学到这条教训。Cursor 继承 VSCode 的扩展机制,扩展和你的代码、你的 .env、你 git config 跑在一个 workspace 视图里。一行 fs.readFileSync('.env') 就够了。
差别只在:Chrome 扩展卖的是浏览历史,IDE 扩展卖的是工作凭证。后者一旦泄露,进 prod 数据库的钥匙就在第三方代码手里。
<figure><img src=“images/01-credential-flow.png” alt=“Cursor 扩展凭证流向”></figure>
信任边界不是文档说的那个边界
每个扩展的 README 都会写"我们尊重你的隐私 / 不会上传任何文件"。这条没用,因为它不是 enforcement,是承诺。
真正决定边界在哪的是 manifest.json 里那行 permissions、是 extension host 的进程隔离设置、是 OS 级 capability。代码强制能做什么、不能做什么——文档说什么的不算数。
这条 web 工程师 20 年前就懂了:承诺不算边界,能做不能做才是边界。把 enforcement 留在文档里 = 没有 enforcement。
怎么自查
打开 Cursor 的扩展列表,按这三件事筛一遍:
- 哪些扩展申请了 workspace 范围权限——这些扩展能读你的 .env、.git/config、本地配置文件
- 这些扩展的开发者是谁——是大厂签名 vs 个人匿名,差别巨大
- 它们最近一次更新是什么时候——好扩展可能上个月才被收购,新主人塞了恶意逻辑
然后把可疑的 disable 掉。secret 该走 password manager / OS keychain,不要明文塞 .env。
更彻底的做法:把 prod 凭证从开发机里完全拿走。本地用 staging credentials,prod credentials 只在 CI runner / 服务器上 inject。开发机不存,扩展也偷不到。这跟"hook 配置在 settings.json 模型读不到" 是同一道理——凭证不在视野里,就没有"读出来"这条路径。
扩展系统的根本问题
VSCode/Cursor 的扩展机制的设计前提是:扩展由社区贡献,靠商店审核保证安全。
这条假设在 2026 年已经不成立。原因有几个:扩展可以 silent 自动更新(你装的时候是好的,下次启动可能换了主人);签名机制弱(很多扩展只有 publisher 名字,没强校验);大量扩展闭源(你看不到它在你电脑上跑什么代码)。
正确的方向是 capability 模型:每个扩展声明"我需要读什么",运行时只能在声明的范围内操作。MCP 服务器走的就是这个路子——每个 server 显式声明 tools,host 决定哪些能调用。VSCode 扩展机制比 MCP 早十几年,但权限设计反而落后。
我自己做内容写作管线时也踩过同一道边界题——subagent 不该读 audit 配置,因为它"在视野里"等于"在控制范围内"。当时改了一周才把边界画对。这件事在写代码、写规则、装扩展上都成立——边界不是写的,是隔出来的。
装扩展前问一句话
「这个扩展跑起来之后,能读到我电脑上哪些文件?」
如果答案是"我的 .env、.git/config、~/.aws"——而你不能 100% 确信开发者不会带走它们,就不要装。
便利和安全之间,没有第三种选择。
出处
- 中文媒体「Cursor AI 扩展可窃取开发者令牌」相关报道
- VSCode Extension API: extensions running in extension host process with workspace permissions