Claude Code Desktop 漏洞:预览窗格可导致本地数据外泄
英文标题:🔶 Claude Code Desktop Vulnerability: Preview Pane Data Exfiltration
Noma Labs 发现,Claude Code Desktop 的预览窗格存在一条可实现任意文件读取的漏洞链:攻击者可将恶意 HTML 伪装为覆盖率报告,并借助超过 256KB 的文件触发 `file://` 加载。由于该路径缺少 CSP 保护且请求过滤器未生效,恶意 JavaScript 可读取本地 SSH 密钥、云凭证、API Key、OAuth Token 等敏感文件,并通过网络静默外传。Anthropic 将该问题评为 CVSS 8.7(高危),影响被视为等同于主机上的代码执行。Anthropic 最终在 Claude Desktop 1.30096.1 及后续版本中修复该问题;该事件也提醒开发者,桌面 AI 工具对不受信任项目文件的自动渲染必须采用完整的隔离、CSP 和网络请求控制。
15.0 KB
46.1 KB
7.7 KB
42.0 KB
59.0 KB
1.8 MB
3.2 MB
88.1 KB
1.9 MB
296.8 KB
4.3 KB
45.9 KB
62.1 KB
53.4 KB
33.3 KB
中文
TL;DR
Noma Labs 在 Claude Code Desktop 的预览窗格中发现了一条漏洞利用链:通过不受限制的 JavaScript 执行,可实现任意文件读取。攻击者可将恶意 HTML 伪装成覆盖率报告并放入公开仓库,该文件能够绕过预览沙箱,并在没有 Content Security Policy(CSP)阻止的情况下运行 JavaScript。
这种攻击的投递机制尤其值得关注:受害者克隆一个公开仓库后,请 Claude 审查某个文件。Claude 会读取该文件,预览窗格则自动将其渲染,嵌入的恶意载荷随即执行。由于 Claude 的预览窗格会通过 file:// URL 加载超过 256KB 的文件,载荷因此能够以同源权限访问受害者的整个本地文件系统。
API Key、SSH 私钥、云凭证、Claude 自身的 OAuth Token 等敏感凭证和机密信息,以及通过 WebRTC 获取的受害者真实 IP 地址,都可能被静默外传。
Anthropic 将 Noma Labs 的这一发现评为 CVSS 8.7(高危),并将其影响视为等同于在主机上执行代码。
什么是 Claude Code Desktop 的预览窗格?
Claude Code Desktop 的预览窗格是大多数用户都使用过、却很少从安全角度考虑的功能。每当 Claude 读取或编辑 HTML 文件时,预览窗格都会在嵌入式面板中自动渲染该文件,让用户能够立即看到结果。
从底层实现看,该预览窗格是一个工件渲染器:它接收 Claude 修改过的 HTML 内容,并通过 Electron 基于 Chromium 的渲染引擎在应用中显示。 受害者无需跳转到某个 URL,也无需在浏览器中打开文件;预览窗格会自动渲染该文件。
为防御恶意内容,预览窗格运行在一个沙箱中:Content Security Policy(CSP)阻止脚本执行,源隔离限制渲染内容可访问的资源,请求过滤器则控制渲染器可获取哪些资源。这一架构在 HTML 文件与受害者机器之间设置了三层防御。Noma Labs 的研究人员绕过了全部三层防御。
沙箱绕过
Anthropic 为预览窗格设置了三项沙箱防御:使用 script-src 'none' 的 Content Security Policy(CSP)来阻止 JavaScript 执行;使用 data: URL 加载,使页面获得不透明源、从而无法获取本地文件;以及在开发服务器代理上设置请求过滤器,用于捕捉渲染器发出的出站请求。
我们如何发现它
我们首先研究了 Claude Code Desktop 如何在预览窗格中渲染 HTML 文件。Claude 的预览窗格对小文件和大文件采用不同的渲染方式:
- 小于 256KB 的文件通过
data:URL 加载,这会限制嵌入式脚本可访问的内容。 - 大于 256KB 的文件会被写入临时文件,并通过
file://URL 加载;在 Chromium 中,这类 URL 可通过fetch()读取其他本地文件。
CSP 会被应用于预览中渲染的文件,以阻止所有内联脚本执行。但它只覆盖 data: URL 路径。file:// 路径从未获得 CSP,因此大文件中的 JavaScript 可不受限制地运行。
此外,还有一个旨在阻止预览窗格读取 file:// 的请求过滤器。当预览窗格代理正在运行的开发服务器(例如本地 React 或 Node 应用)时,该过滤器会生效并阻止此类读取。但当它直接从磁盘渲染静态 HTML 文件(如覆盖率报告)时,过滤器不会启用,fetch() 调用会直接针对真实文件系统解析。
这三处缺口串联起来,使攻击者能够通过预览窗格实现任意文件读取:
- 将文件填充至超过 256KB,以获得
file://源 - 利用缺失的 CSP 来运行脚本
- 利用未启用的请求过滤器读取任意本地路径
漏洞概念验证
[视频/嵌入内容:漏洞概念验证演示]
一个问题,完全攻陷
为演示该漏洞,Noma Labs 研究人员搭建了一个看起来与普通项目完全一致的仓库,其中包含源代码、测试以及一份覆盖率报告。测试工具会生成这类报告,以显示代码库的哪些部分已被测试覆盖。此类仓库通常较大,因为它们会打包 source map 和 CSS,因此一份 500KB 的报告不会引起怀疑。我们将自己的报告制作为超过 256KB,并在其中嵌入 JavaScript 载荷。
- 受害者克隆该仓库并打开 Claude Code Desktop。
- 受害者要求 Claude 查看覆盖率报告,这是一项常规请求,例如审查测试结果或检查哪些模块存在覆盖率缺口。
- Claude 读取该文件。预览窗格自动渲染它,嵌入式载荷随即执行。
- 脚本从临时文件路径中解析受害者的主目录,并通过 fetch() 和 XMLHttpRequest 开始拉取文件:
- SSH 私钥
- AWS 访问密钥和机密
- npm 和 GitHub 身份验证 Token
- Kubernetes 集群凭证
- Docker 镜像仓库认证信息
- Git 身份信息和 Token
由于 Claude Code Desktop 没有 CSP 来限制出站请求,脚本会使用 navigator.sendBeacon() 将所有内容发送回攻击者服务器。sendBeacon() 是一种 Web API,可在后台静默发起单向 HTTP POST 请求。正如前文所述,这种外传方式之所以有效,是因为 Claude Code Desktop 是一款 Electron 应用。Electron 应用的完整 UI 运行在具备所有标准 Web API 访问能力的 Chromium 浏览器引擎上。
在实际使用中,这意味着受害者无需批准任何操作,也无需授予 Claude Desktop 访问任何内容的权限。系统不会出现权限请求,要求受害者审阅覆盖率报告或其内容。受害者最初要求 Claude 查看覆盖率报告的操作,就足以触发预览、执行载荷并外传数据和机密。由于 Claude 代表受害者渲染不受信任的内容,恶意代码便在渲染步骤中执行。
绕过修复
在我们提交初始报告后,Anthropic 部署了补丁,阻止主页面上下文中的 fetch() 和 XMLHttpRequest 调用访问 file:// 路径。然而,Noma Labs 的研究人员发现了另一种绕过该补丁的方法。
通过将 fetch() 调用移入一个由 blob: URL 创建的 Web Worker,我们能够从 CSP 过滤器未覆盖的上下文中发起请求。
const workerCode = `
self.onmessage = async function(e) {
for (const target of e.data) {
try {
// Worker's fetch() bypasses the renderer's request filter
const r = await fetch('file://' + target.path);
if (r.ok) {
const text = await r.text();
// Send stolen file contents back to the main thread for exfiltration
self.postMessage({tag: target.tag, data: text});
}
} catch(e) {}
}
};
`;
// Spawn the Worker via the blob: URL, creating a separate execution context not covered by the filter
const blob = new Blob([workerCode], {type: 'application/javascript'});
const worker = new Worker(URL.createObjectURL(blob));
该 Worker 读取了同一组敏感文件,并将它们发送回主线程;主线程随后通过 sendBeacon() 将其外传。通过这一路径,最初的三项缺陷仍然都可被利用。
Anthropic 的回应
Anthropic 从一开始就严肃对待 Noma 的披露。
他们对初始报告进行了分级,使用 CVSS v4.0 将该漏洞评为 CVSS 8.7(高危),并部署补丁,阻止渲染器直接通过 fetch() 和 XMLHttpRequest 调用访问 file:// 路径。
在我们提交绕过方法、证明 URL Web Workers 可以规避这一修复后,他们确认该问题仍未解决,并承诺开展额外工作来处理它:
在最终复测后,Anthropic 修复了全部问题,关闭该漏洞并将其标记为已解决。
披露时间线
衷心感谢 Anthropic 团队在整个漏洞披露过程中展现出的透明、迅速的合作,以及坚持不懈的投入。安全推进前沿 AI 需要一种共同责任模式:安全研究人员与平台供应商通过持续反馈循环进行透明协作。Anthropic 致力于针对每一种绕过方式持续迭代,直至实现全面、多层的修复,这正是保护更广泛社区所需要的协作标准。
- 2026 年 7 月 4 日,初始报告:向 Anthropic 报告漏洞,并提供完整 PoC,展示如何通过文件预览窗格中的任意 JavaScript 执行外传敏感凭证。
- 2026 年 7 月 9 日,分级:Anthropic 将该漏洞评为 CVSS 8.7(高危)。
- 2026 年 7 月 24 日,修复与复测:Anthropic 修复漏洞并请求进行复测。
- 2026 年 7 月 24 日,报告绕过方法:Noma Labs 演示了
blob:URL 方案的 Web Workers 可绕过请求过滤器。已提交包含视频演示的完整绕过 PoC。 - 2026 年 8 月 3 日,确认绕过:Anthropic 确认修复不完整,并将报告状态改回“已分级”。涵盖 CSP、
file://加载及 Worker 绕过的完整修复正在进行中。 - 2026 年 8 月 17 日,Anthropic 在 Claude Desktop 1.30096.1 及后续版本中发布修复,并通过自动更新交付。
- 2026 年 10 月,GitHub Advisory 和 CVE 尚待发布。
深入了解
SneakPeek 发现只是 Noma Labs 更广泛使命的一部分。主动开展前沿漏洞研究,是我们实现现代 AI 技术栈保护与防御的核心方式。你可以在 Noma Labs 研究索引的此处阅读我们近期的发现和持续进行的安全分析,也可以访问 Noma 的 YouTube 频道此处。在探寻最脆弱、风险最高的问题时,我们将继续分享我们的发现。
English / 原文
TL;DR
Noma Labs discovered an exploit chain in Claude Code Desktop's preview pane that achieves arbitrary file read via unrestricted JavaScript execution. Disguised as a coverage report, the attacker places poisoned HTML in a public repo that bypasses the preview sandbox and runs JavaScript without a Content Security Policy to block it.
The delivery mechanism makes this attack path particularly interesting: a victim clones a public repo and asks Claude to review a file. Claude reads the file, its preview pane renders it automatically, and the embedded malicious payload executes. Because Claude's preview pane loads files above 256KB via file:// URLs, the payload gets same-origin access to the victim's entire local filesystem.
Sensitive credentials and secrets such as API keys, SSH private keys, cloud credentials, Claude's own OAuth tokens, and even the victim's real IP address via WebRTC are silently exfiltrated.
Anthropic scored Noma Labs' discovery as CVSS 8.7 (High) and treated the impact as equivalent to code execution on the host.
What is Claude Code Desktop's Preview Pane?
Claude Code Desktop’s preview pane is a feature most users have used, but few ever consider from a security perspective. Whenever Claude reads or edits an HTML file, the preview pane automatically renders it in an embedded panel so the user can see the result right away.
Under the hood, this preview pane is an artifact renderer that takes HTML content Claude has modified and displays it in the application using Electron's Chromium-based rendering engine.
The victim doesn't navigate to a URL or open a file in their browser; instead, the preview pane renders the file automatically.
To protect against malicious content, the preview pane runs inside a sandbox where a Content Security Policy (CSP) blocks script execution, origin isolation limits what rendered content can access, and a request filter controls which resources the renderer can fetch. This architecture creates three layers of defense between an HTML file and the victim’s machine. Noma Labs researchers bypassed all three.
The Sandbox Bypass
Anthropic sandboxes the preview pane with three defenses: a Content Security Policy (CSP) with script-src 'none' that blocks JavaScript execution, data: URL loading that gives the page an opaque origin so it can't fetch local files, and a request filter on the dev server proxy that catches outbound requests from the renderer.
How We Found It
We started by looking at how Claude Code Desktop renders HTML files in the preview pane. Claude’s preview pane renders small and large files differently:
- Files under 256KB load as
data:URLs, which restrict what embedded scripts can access. - Files over 256KB are written to a temp file and loaded as
file://URLs, which in Chromium can read other local files throughfetch().
A CSP is applied to files rendered in the preview, blocking all inline script execution. But it only covers the data: URL path. The file:// path never receives the CSP, so JavaScript in a large file runs unrestricted.
There is also a request filter meant to block file:// reads from the preview. When the preview proxies a running dev server, such as a local React or Node app, the filter is active and blocks those reads. But when it renders a static HTML file directly from disk, like a coverage report, the filter does not engage and fetch() calls resolve against the real filesystem.
These three gaps chained together give an attacker arbitrary file read through the preview pane:
- Pad the file past 256KB to get a
file://origin - Exploit the missing CSP to run scripts
- Use the inactive request filter to read any local path.
Vulnerability Proof of Concept
VIDEO
**
One Question, Full Compromise**
To demonstrate the vulnerability, Noma Labs researchers set up a repository that looked exactly like a normal project, including source files, tests, and a coverage report. Testing tools generate these reports to show which parts of a codebase have coverage. Repos of this type are normally large because they bundle source maps and CSS, so a 500KB report doesn't raise any flags. We made ours over 256KB and embedded a JavaScript payload in it.
- A victim clones the repo and opens Claude Code Desktop.
- The victim asks Claude to look at the coverage report, a routine request like reviewing test results or checking which modules have coverage gaps.
- Claude reads the file. The preview pane renders it automatically, and the embedded payload executes.
- The script resolves the victim's home directory from the temp file path and starts pulling files via fetch() and XMLHttpRequest:
- SSH private keys
- AWS access keys and secrets
- npm and GitHub auth tokens
- Kubernetes cluster credentials
- Docker registry auth
- Git identity and tokens
Because Claude Code Desktop has no CSP restricting outbound requests, the script sends everything back to the attacker's server using navigator.sendBeacon(), a web API that silently fires a one-way HTTP POST in the background. This exfiltration method works because, as mentioned previously, Claude Code Desktop is an Electron app. Electron apps' entire UI runs on a full Chromium browser engine with access to all standard web APIs.
In practical terms, this means the victim doesn't need to approve or grant Claude Desktop access to anything. No permission request is created to ask the victim to review the coverage report or its contents. The original victim's request to Claude to view the coverage report is enough to trigger the preview, execute the payload, and exfiltrate data and secrets. Because Claude renders the untrusted content on the victim's behalf, the rendering step is where the malicious code executes.
Bypassing the Fix
After our initial report, Anthropic deployed a patch that blocked fetch() and XMLHttpRequest calls to file:// paths from the main page context. However, Noma Labs researchers found another way around the patch.
By moving the fetch() call into a Web Worker created from a blob: URL, we were able to originate the request from a context that the CSP filter did not cover.
const workerCode = `
self.onmessage = async function(e) {
for (const target of e.data) {
try {
// Worker's fetch() bypasses the renderer's request filter
const r = await fetch('file://' + target.path);
if (r.ok) {
const text = await r.text();
// Send stolen file contents back to the main thread for exfiltration
self.postMessage({tag: target.tag, data: text});
}
} catch(e) {}
}
};
`;
// Spawn the Worker via the blob: URL, creating a separate execution context not covered by the filter
const blob = new Blob([workerCode], {type: 'application/javascript'});
const worker = new Worker(URL.createObjectURL(blob));
The Worker read the same set of sensitive files and sent them back to the main thread, which exfiltrated them via sendBeacon().All three original defects remained exploitable through this path.
Anthropic's Response
Anthropic took Noma's disclosure seriously from the start.
They triaged the initial report, scored it CVSS 8.7 (High) using CVSS v4.0, and deployed a patch blocking direct fetch() and XMLHttpRequest calls to file:// paths from the renderer.
After we submitted the bypass demonstrating that URL Web Workers could circumvent the fix, they confirmed the issue remained unresolved and committed to additional work to address it:
After the final retest, Anthropic fixed all issues; they closed the vulnerability and marked it as resolved.
**Disclosure Timeline
**
A sincere thank you to the Anthropic team for their transparent, responsive partnership and relentless persistence throughout this disclosure process. Safely advancing frontier AI requires a model of mutual responsibility in which security researchers and platform vendors collaborate transparently through continuous feedback loops. Anthropic’s dedication to iterating on every bypass until achieving a comprehensive, layered fix exemplifies the collaborative standard needed to protect the broader community.
- July, 4, 2026 Initial Report: Vulnerability reported to Anthropic with full PoC demonstrating exfiltration of sensitive credentials via arbitrary JavaScript execution in the file preview pane.
- July, 9, 2026 Triage: Anthropic scored the vulnerability CVSS 8.7 (High).
- July 24, 2026 Patch and Retest: Anthropic fixed the vulnerability and requested a retest.
- July 24, 2026 Bypass Reported: Noma Labs demonstrated that the blob: URL scheme Web Workers bypass the request filter. Full bypass PoC with video walkthrough submitted.
- August 3, 2026 Bypass Confirmed: Anthropic confirmed the fix is incomplete and moved the report back to Triaged. Complete fix covering CSP, file:// loading, and the Worker bypass is in progress.
- August 17, 2026 Anthropic issued a fix in Claude Desktop 1.30096.1 and later, delivered via auto-update.
- October, 2026 GitHub Advisory and CVE pending publish
Learn More
The SneakPeek discovery is just one part of our broader mission at Noma Labs. Proactive, frontier vulnerability research is core to how we actualize protection and defense of the modern AI tech stack. You can read more about our recent findings and ongoing security analysis across the rest of the Noma Labs research index here and on Noma's YouTube channel here. We'll continue sharing our discoveries as we hunt for what's the most vulnerable and risky.