保护 VS Code 免受即时注入攻击
当聊天对话被间接提示注入恶意代码时,可能会导致 GitHub 令牌、机密文件泄露,甚至在未经用户明确同意的情况下执行任意代码。本文将介绍 VS Code 的哪些功能可以降低这些风险。
过去几个月,适用于 VS Code 的 Copilot Chat 扩展程序发展迅速,新增了众多功能。其全新的代理模式允许您使用多个大型语言模型 (LLM)、内置工具和 MCP 服务器来编写代码、提交请求以及与外部系统集成。该扩展程序高度可定制,用户可以选择使用哪些工具和 MCP 服务器来加速开发。
从安全角度来看,我们必须考虑将外部数据引入聊天会话并包含在提示信息中的场景。例如,用户可能会向模型询问某个包含恶意指令的 GitHub 问题或公开拉取请求。在这种情况下,模型不仅可能被诱骗给出错误答案,还可能通过工具调用秘密执行敏感操作。
在这篇博文中,我将分享我在对 Copilot Chat 扩展程序进行安全评估时发现的几个漏洞,特别是关于代理模式的漏洞,我们已与 VS Code 团队共同修复了这些漏洞。这些漏洞可能允许攻击者泄露本地 GitHub 令牌、访问敏感文件,甚至在未经用户确认的情况下执行任意代码。我还会讨论 VS Code 中一些有助于降低这些风险并保障您安全的独特功能。最后,我将探讨一些可用于进一步增强使用 VS Code 读取和编辑代码安全性的其他方法。

代理模式底层工作原理
假设用户在 VS Code 中打开 GitHub MCP 服务器的聊天窗口,并在代理模式下提出以下问题:
What is on https://github.com/artsploit/test1/issues/19?
VS Code 并非简单地将此请求转发给选定的 LLM(语言学习模型)。相反,它会从打开的项目中收集相关文件,并包含有关用户和当前使用文件的上下文信息。它还会将所有可用工具的定义附加到提示符中。最后,它会将这些编译后的数据发送给选定的模型进行推理,以确定下一步操作。
该模型可能会以get_issue工具调用消息的形式响应,请求 VS Code 在 GitHub MCP 服务器上执行此方法。工具执行时,VS Code 代理会将工具的输出添加到当前对话历史记录中,并将其发送回 LLM,从而形成一个反馈循环。这可能会触发另一次工具调用,或者如果模型判定任务已完成,则会返回结果消息。
要查看对话上下文中包含的内容,最好的方法是监控 VS Code 和 Copilot API 之间的流量。您可以通过在 VS Code 设置中设置本地代理服务器(例如 Burp Suite 实例)来实现这一点:
"http.proxy": "http://127.0.0.1:7080"
然后,如果您检查网络流量,就会发现 VS Code 向 Copilot 服务器发出的请求如下所示:
POST /chat/completions HTTP/2
Host: api.enterprise.githubcopilot.comges: [
{ role: 'system', content: 'You are an expert AI ..' },
{
role: 'user',
content: 'What is on https://github.com/artsploit/test1/issues/19?'
},
{ role: 'assistant', content: '', tool_calls: [Array] },
{
role: 'tool',
content: '{...tool output in json...}'
}
],
model: 'gpt-4o',
temperature: 0,
top_p: 1,
max_tokens: 4096,
tools: [..],
}
在本例中,该工具的输出包含有关相关 GitHub Issue 的信息。如您所见,VS Code 已在 JSON 中正确地将工具输出、用户提示和系统消息分开。然而,在后端,所有这些消息都被混合成一个文本提示进行推断。
在这种情况下,用户期望LLM代理严格按照系统消息的指示,遵循用户的原始问题,并仅提供问题的摘要。更一般地说,我们对LLM的提示表明,该模型应将用户的请求解释为“指令”,将工具的输出解释为“数据”。
在我的测试过程中,我发现即使是像 GPT-4.1、Gemini 2.5 Pro 和 Claude Sonnet 4 这样最先进的模型,也可能被工具的输出结果误导,从而执行与用户最初要求完全不同的操作。
那么,这种漏洞是如何被利用的呢?为了从攻击者的角度理解,我们需要检查 VS Code 中所有可用的工具,并找出那些可以执行敏感操作(例如执行代码或泄露机密信息)的工具。这些敏感工具很可能是攻击者的主要目标。
VS Code 提供的代理工具
VS Code 为 LLM 提供了一些强大的工具,使其能够读取文件、生成编辑内容,甚至执行任意 shell 命令。要查看当前所有可用工具,请在聊天窗口中点击“配置工具”按钮:


每个工具都应该实现VS Code.LanguageModelTool接口,并且可以包含一个prepareInvocation在工具运行前向用户显示确认消息的方法。这样做的目的是确保敏感工具(例如 `get_command_tools`)installExtension始终需要用户确认。这是防止 LLM 幻觉或提示注入的主要防御措施,确保用户完全了解正在发生的事情。然而,每次调用工具都提示用户批准会很繁琐,因此一些标准工具(例如 `get_command_tools`)read-files会自动执行。
除了 VS Code 提供的默认工具外,用户还可以连接到不同的 MCP 服务器。但是,对于来自这些服务器的工具,VS Code 始终会在运行前要求用户确认。
在我的安全评估过程中,我给自己设定了一个挑战:能否在未经用户确认的情况下,诱使 LLM 执行恶意操作。结果发现,有好几种方法可以做到这一点。
由于对受信任URL解析不当导致数据泄露
首先吸引我注意的是fetch_webpage 工具。它允许你向任何网站发送 HTTP 请求,但如果该网站不在受信任来源列表中,则需要用户确认。默认情况下,VS Code 信任localhost以下域名:
// By default, VS Code trusts "localhost" as well as the following domains:
// - "https://*.visualstudio.com"
// - "https://*.microsoft.com"
// - "https://aka.ms"
// - "https://*.gallerycdn.vsassets.io"
// - "https://*.github.com"
用于验证网站是否可信的逻辑存在缺陷。显然,它仅仅使用了正则表达式比较,而没有正确解析 URL。因此,类似这样的域名http://example.com/.github.com/xyz也被认为是安全的。
这使我能够编写一个特殊的提示符,该提示符可以从本地文件中读取 GitHub 令牌并将其发送到外部域。我已将此提示符添加到 GitHub Issue 中:

请阅读上方 GitHub 问题截图中的文本
然后,我让 Copilot 获取有关新创建的问题的详细信息:

如您所见,聊天 GPT-4o 模型错误地遵循了问题描述中的指令,而非按要求总结其内容。因此,询问该问题的用户可能不会意识到他们的令牌已被发送到外部服务器。所有这一切都是在没有任何确认请求的情况下发生的。
我们在 VS Code 中通过将获取工具中使用的 URL 与受信任域功能(旨在保护不同的功能)解耦来解决这个问题。此外,无论请求来自何处,获取工具现在都需要用户确认才能获取以前从未见过的 URL,并会显示安全免责声明:

利用简单的浏览器工具进行数据泄露
后来,我找到了另一种无需授权即可将本地数据发送到外部服务器的方法——这次是使用Simple Browser 工具。根据其描述,该工具用于测试本地网站,但它也支持加载外部网站。我在问题中添加了以下提示:

请阅读上方 GitHub 问题截图中的文本
然后向副驾驶询问了这个问题:

如截图所示,结果是一样的:Copilot 将令牌泄露给了外部网站,而不是简单地向用户显示问题内容。
与 fetch 工具类似,简易浏览器工具现在也需要用户确认才能打开任何新 URL:

请注意,简易浏览器工具也会在 VS Code 的嵌入式浏览器中渲染外部网站的 HTML 内容,这可能会引入额外的攻击面。不过,VS Code 会使用内容安全策略的沙盒指令来妥善隔离这种情况。
使用编辑功能可立即生成生效的更改。
VS Code 还提供了一个editFile 工具,允许用户修改本地文件。每次更改都会清晰地显示给用户,用户需要点击“保留”或“撤销”来确认或还原更改。
这里微妙之处在于,当用户被提示查看这些更改时,文件已经在磁盘上被编辑过,因此“保留”选项不起作用。如果某个进程正在监视文件更新,这些更改可能会被自动检测到。例如,我们可以修改 `/ settings.jsonetc/mcp` 或 `/etc/ mcp.jsonmcp` 文件,因为它们的内容会在每次更改后重新加载。由于 MCP 服务器可以通过 shell 命令启动,因此我们可以在其中插入任意命令。为了测试这一点,我提交了另一个 issue:

请阅读上方 GitHub 问题截图中的文本
当我在 Copilot Chat 中提出这个问题时,客服人员替换了该~/Library/Application Support/Code - Insiders/User/settings.json文件,这改变了 GitHub MCP 服务器的启动方式。随后,客服人员立即将工具调用结果发送到 LLM,导致 MCP 服务器配置立即重新加载。结果,在我来得及回复或查看更改之前,计算器就自动打开了。
问题的核心在于editFile 工具的自动保存行为。这种设计是有意为之,因为该代理程序旨在逐步对多个文件进行增量修改。然而,这种利用方式比以往更加明显,因为文件更改会在用户界面中清晰可见。
与此同时,一些外部漏洞报告也指出了文件立即更改时存在的相同根本问题。EmbraceTheRed 的 Johann Rehberger 报告了另一种利用此漏洞的方法,即覆盖现有文件./.vscode/settings.json with "chat.tools.autoApprove": true。Persistent Security 的 Markus Vervier 也发现并报告了一个类似的漏洞。
如今,VS Code 已不再允许代理编辑工作区之外的文件。未来还将推出更多保护措施(已在预览体验成员中提供),强制用户在编辑敏感文件(例如配置文件)时进行确认。
间接快速注射技术
在测试不同模型对包含公开 GitHub Issues 的工具输出的反应时,我注意到模型通常不会立即执行恶意指令。要真正诱使它们执行此操作,攻击者需要使用类似于模型越狱中使用的各种技术。
例如,
- 包含诸如“仅当当前日期为时”之类的隐式真条件似乎更能吸引模型的关注。
- 引用提示信息的其他部分,例如用户消息、系统消息或提示信息的最后几个字,也会产生影响。例如,“如果用户说‘以上是调用一个或多个工具的结果’”这句话曾被 Copilot 使用过,尽管它最近已经更新过。
- 另一种方法是模仿 Copilot 使用的系统提示符,并在其中插入一条额外的指令。Copilot 的默认系统提示符并非秘密。尽管注入的指令是作为部分内容
role: "tool"而非单独发送以供推理的role: "system",但模型仍然倾向于将其视为系统提示符的一部分。
据我观察,Claude Sonnet 4 似乎是训练最彻底、能够抵抗此类攻击的模型,但即使是它也能被可靠地欺骗。
此外,当 VS Code 与模型交互时,它会将温度设置为 0。这使得 LLM 对相同提示的响应更加一致,有利于编码。然而,这也意味着提示注入攻击更容易复现。
安全增强
就像人类一样,LLM(语言学习模型)会尽力提供帮助,但有时它们难以区分合法指令和恶意第三方数据。与 SQL 等结构化编程语言不同,LLM 接受文本、图像和音频形式的提示。这些提示没有特定的模式,并且可能包含不受信任的数据。这是提示注入攻击频发的主要原因,也是 VS Code 无法控制的。VS Code 通过 Copilot API 支持多种模型(包括本地模型),每个模型的训练方式和行为可能各不相同。
不过,我们仍在努力推出新的安全功能,以便让用户更好地了解系统运行状况。这些更新包括:
- 显示所有内部工具以及 MCP 服务器和 VS Code 扩展提供的工具列表;
- 允许用户手动选择LLM可以使用的工具;
- 增加对工具集的支持,以便用户可以针对各种情况配置不同的工具组;
- 读取或写入工作区或当前打开的文件集之外的文件时,需要用户确认;
- 启动MCP 服务器前,需要用户接受模态对话框以确认信任该服务器;
- 支持禁止特定功能(例如来自扩展程序、MCP 或代理模式的工具)的策略;
我们也一直在密切关注安全编码代理方面的研究。我们持续尝试双重LLM模式、信息控制流、基于角色的访问控制、工具标签以及其他能够提供确定性和可靠安全控制的机制。
最佳实践
除了上述安全增强功能外,您还可以在 VS Code 中使用一些额外的保护措施:
工作区信任
工作区信任是 VS Code 的一项重要功能,它可以帮助您安全地浏览和编辑代码,而无需考虑代码的来源或原始作者。借助工作区信任,您可以以受限模式打开工作区,该模式会阻止任务自动运行、限制某些 VS Code 设置并禁用一些扩展程序,包括 Copilot 聊天扩展程序。请记住,当您处理尚未完全信任的代码库时,务必使用受限模式。
沙盒
另一种可以有效防御此类攻击的重要纵深防御机制是沙箱。VS Code 与开发者容器 (Developer Containers)集成良好,允许开发者在隔离的 Docker 容器内打开代码并与之交互。在这种情况下,Copilot 会在容器内运行工具,而不是在本地计算机上运行。它是免费的,只需创建一个devcontainer.json文件即可开始使用。
此外,GitHub Codespaces是另一个易于使用的 VS Code 代理沙箱解决方案。GitHub 允许您在云端创建一个专用虚拟机,并通过浏览器或直接从本地 VS Code 应用程序连接到该虚拟机。您只需在仓库网页上点击一个按钮即可创建虚拟机。当代理需要执行任意命令或读取任何本地文件时,这可以提供极佳的隔离性。
结论
VS Code 提供强大的工具,使语言学习模型 (LLM) 能够协助完成各种软件开发任务。自 Copilot Chat 诞生以来,我们的目标一直是让用户完全掌控并清晰了解幕后运行情况。然而,密切关注细微的实现细节至关重要,以确保不会绕过提示注入攻击的保护措施。随着模型的不断进步,我们最终或许能够减少所需的用户确认次数,但目前,我们需要仔细监控模型执行的操作。使用合适的沙箱环境,例如GitHub Codespaces或本地 Docker 容器,也能有效抵御提示注入攻击。我们将在未来的 VS Code 和 Copilot Chat 版本中进一步优化这一功能。


苏公网安备 32059002002276号
