Claude Code Desktop 취약점: 미리보기 창 데이터 유출
요약
Noma Labs는 Claude Code Desktop의 미리보기 창에서 임의 파일 읽기(arbitrary file read) 취약점을 발견했습니다. 공격자는 오염된 HTML을 통해 샌드박스를 우회하고, 로컬 파일을 `file://` URL로 로드하는 과정에서 전체 시스템에 동일 출처 접근 권한을 얻어 민감한 자격 증명을 유출할 수 있습니다.
핵심 포인트
- Claude Code Desktop의 미리보기 창 취약점 발견
- 공개 저장소 클론 및 검토 요청 시 공격 가능
- API 키, SSH 개인 키 등 민감 정보 유출 위험
- 샌드박스(CSP)를 우회하는 익스플로잇 체인 작동
.jpg
요약 (TL;DR)
Noma Labs는 Claude Code Desktop의 미리보기 창에서 임의 파일 읽기(arbitrary file read)를 달성하는 익스플로잇 체인을 발견했습니다. 이는 무제한 JavaScript 실행을 통해 이루어집니다. 공격자는 커버리지 보고서처럼 위장하여 공개 저장소에 오염된 HTML을 배치하며, 이 코드는 미리보기 샌드박스를 우회하고 Content Security Policy(CSP)가 차단할 수 없도록 JavaScript를 실행합니다.
이 전달 메커니즘은 이 공격 경로를 특히 흥미롭게 만듭니다. 피해자가 공개 저장소를 클론하고 Claude에게 파일을 검토하도록 요청하면, Claude는 해당 파일을 읽고 미리보기 창에서 자동으로 렌더링하며, 내장된 악성 페이로드가 실행됩니다. 왜냐하면 Claude의 미리보기 창은 256KB를 초과하는 파일을 file:// URL을 통해 로드하기 때문에, 페이로드는 피해자의 전체 로컬 파일 시스템에 동일 출처 접근(same-origin access)을 얻게 됩니다.
API 키, SSH 개인 키, 클라우드 자격 증명, Claude 자체의 OAuth 토큰 등 민감한 자격 증명과 심지어 WebRTC를 통한 피해자의 실제 IP 주소까지 조용히 유출됩니다.

Anthropic은 Noma Labs의 발견을 CVSS 8.7 (높음) 점수로 평가했으며, 그 영향을 호스트에서의 코드 실행과 동등하게 간주했습니다.

Claude Code Desktop의 미리보기 창이란 무엇인가요?
Claude Code Desktop의 미리보기 창은 대부분의 사용자가 사용해 온 기능이지만, 보안 관점에서 고려하는 사람은 거의 없습니다. Claude가 HTML 파일을 읽거나 편집할 때마다, 미리보기 창은 해당 내용을 임베디드 패널에 자동으로 렌더링하여 사용자가 결과를 즉시 볼 수 있도록 합니다.
내부적으로 이 미리보기 창은 Claude가 수정한 HTML 콘텐츠를 가져와 Electron의 Chromium 기반 렌더링 엔진을 사용하여 애플리케이션에 표시하는 아티팩트 렌더러입니다. 피해자는 브라우저에서 URL로 이동하거나 파일을 열지 않습니다. 대신, 미리보기 창이 해당 파일을 자동으로 렌더링합니다.
악성 콘텐츠를 방지하기 위해 미리보기 창은 샌드박스(sandbox) 내에서 실행됩니다. 여기서 Content Security Policy (CSP)가 스크립트 실행을 차단하고, origin isolation이 렌더링된 콘텐츠가 접근할 수 있는 범위를 제한하며, 요청 필터(request filter)가 렌더러가 가져올 수 있는 리소스를 제어합니다. 이 아키텍처는 HTML 파일과 피해자의 장치 사이에 세 가지 방어 계층을 만듭니다. Noma Labs 연구원들은 이 세 가지를 모두 우회했습니다.
샌드박스 우회(The Sandbox Bypass)
Anthropic은 미리보기 창에 세 가지 방어책으로 샌드박스를 구현했습니다: JavaScript 실행을 차단하는 * script-src 'none'* CSP, 페이지에 불투명한 origin을 부여하여 로컬 파일을 가져올 수 없게 하는 URL 로딩 방식, 그리고 렌더러의 아웃바운드 요청을 가로채는 dev 서버 프록시의 요청 필터입니다.
data:
발견 과정(How We Found It)
저희는 Claude Code Desktop이 미리보기 창에서 HTML 파일을 어떻게 렌더링하는지 살펴보면서 시작했습니다. Claude의 미리보기 창은 크고 작은 파일을 다르게 렌더링합니다:
-
256KB 미만 파일은 URL로 로드되어 임베디드 스크립트가 접근할 수 있는 범위를 제한합니다.
data: -
256KB 초과 파일은 임시 파일로 작성된 후 URL로 로드되는데, 이는 Chromium에서
file://를 통해 다른 로컬 파일을 읽을 수 있음을 의미합니다.
.fetch()
CSP는 미리보기에서 렌더링되는 파일에 적용되어 모든 인라인 스크립트 실행을 차단합니다. 하지만 이것은 데이터: URL 경로만을 다룹니다. file:// 경로는 CSP를 받지 않기 때문에, 대용량 파일 내의 JavaScript는 제한 없이 실행됩니다.
또한 미리보기에서 읽기를 차단하기 위한 요청 필터가 있습니다. 미리보기가 로컬 React 또는 Node 앱과 같은 실행 중인 dev 서버를 프록시할 때, 이 필터는 활성화되어 해당 읽기 요청을 차단합니다. 하지만 커버리지 보고서처럼 디스크에서 정적 HTML 파일을 직접 렌더링할 때는 필터가 작동하지 않아
file://
실제 파일 시스템에 대해 resolve를 호출합니다.
fetch()
이 세 가지 허점들이 연결되면서 공격자에게 미리보기 창을 통한 임의 파일 읽기(arbitrary file read) 권한을 부여합니다:
-
파일을 256KB 이상으로 채워 origin
file:// -
CSP가 누락된 점을 악용하여 스크립트 실행
-
비활성 요청 필터를 사용하여 임의 로컬 경로 읽기
취약점 PoC (Proof of Concept)
하나의 질문으로 완전한 침해
하나의 질문으로 완전한 침해
****취약점을 시연하기 위해 Noma Labs 연구원들은 소스 파일, 테스트 및 커버리지 보고서를 포함하여 일반적인 프로젝트와 똑같이 보이는 저장소를 설정했습니다. 테스트 도구는 코드베이스의 어떤 부분이 커버리지를 갖는지 보여주기 위해 이러한 보고서를 생성합니다. 이런 유형의 저장소는 일반적으로 소스 맵과 CSS를 번들링하기 때문에 크기가 크며, 500KB 보고서는 아무런 문제가 되지 않습니다. 저희는 256KB가 넘는 파일을 만들고 그 안에 JavaScript 페이로드를 임베드했습니다.

-
피해자가 저장소를 클론하고 Claude Code Desktop을 실행합니다.
-
피해자는 Claude에게 커버리지 보고서를 보라고 요청합니다. 이는 테스트 결과를 검토하거나 어떤 모듈에 커버리지 격차가 있는지 확인하는 것과 같은 일상적인 요청입니다.
-
Claude가 파일을 읽습니다. 미리보기 창이 이를 자동으로 렌더링하고, 임베드된 페이로드가 실행됩니다.
-
스크립트는 임시 파일 경로에서 피해자의 홈 디렉토리를 해석하여 fetch() 및 XMLHttpRequest를 통해 파일을 가져오기 시작합니다:
-
SSH 개인 키
-
AWS 접근 키 및 시크릿
-
npm 및 GitHub 인증 토큰
-
Kubernetes 클러스터 자격 증명
-
Docker 레지스트리 인증
-
Git ID 및 토큰
Claude Code Desktop에는 아웃바운드 요청을 제한하는 CSP가 없기 때문에, 스크립트는 모든 내용을 navigator.sendBeacon()을 사용하여 공격자의 서버로 전송합니다. 이는 백그라운드에서 단방향 HTTP POST를 조용히 발사하는 웹 API입니다. 이러한 유출 방식은 이전에 언급했듯이 Claude Code Desktop이 Electron 앱이기 때문에 작동합니다. Electron 앱의 전체 UI는 모든 표준 웹 API에 접근할 수 있는 완전한 Chromium 브라우저 엔진 위에서 실행됩니다.
실질적으로 이것은 피해자가 Claude Desktop에게 어떤 것에 대한 접근 권한을 승인하거나 부여할 필요가 없다는 것을 의미합니다. 피해자에게 커버리지 보고서나 그 내용을 검토하도록 요청하는 어떠한 권한 요청도 생성되지 않습니다. 원래 피해자가 Claude에게 커버리지 보고서를 보기를 요청하는 것만으로 미리보기가 트리거되고, 페이로드가 실행되며, 데이터와 비밀 정보가 유출됩니다. Claude가 신뢰할 수 없는 콘텐츠를 피해자를 대신하여 렌더링하기 때문에, 렌더링 단계에서 악성 코드가 실행됩니다.
패치 우회 (Bypassing the Fix)
저희의 초기 보고서 이후 Anthropic은 fetch() 호출을 메인 페이지 컨텍스트의 XMLHttpRequest 경로에 대해 차단하는 패치를 배포했습니다. 하지만 Noma Labs 연구원들은 이 패치를 우회할 수 있는 또 다른 방법을 발견했습니다.
file://
호출을
fetch() URL에서 생성된 Web Worker 내부로 이동함으로써, 저희는 CSP 필터가 커버하지 않은 컨텍스트에서 요청을 시작할 수 있었습니다.
blob:
const workerCode = `
self.onmessage = async function(e) {
for (const target of e.data) {
...
Worker는 동일한 민감 파일 세트를 읽어 메인 스레드로 전송했고, 메인 스레드는 이를 sendBeacon()을 통해 유출했습니다. 원래의 모든 결함은 이 경로를 통해 여전히 악용될 수 있었습니다.**
Anthropic의 대응 (Anthropic's Response)
Anthropic은 처음부터 Noma의 공개 내용을 심각하게 받아들였습니다.
그들은 초기 보고서를 분류하고, CVSS v4.0을 사용하여 8.7점(높음)으로 점수를 매겼으며, 렌더러에서 file:// 경로에 대한 직접적인 fetch() 및 XMLHttpRequest 호출을 차단하는 패치를 배포했습니다.
저희가 URL Web Worker가 패치를 우회할 수 있음을 입증하는 바이패스를 제출한 후, 그들은 문제가 해결되지 않았음을 확인하고 이를 해결하기 위한 추가 작업에 전념했습니다:

최종 재테스트 후, Anthropic은 모든 문제를 수정했으며 취약점을 닫고 해결됨으로 표시했습니다.
공개 타임라인 (Disclosure Timeline)
Anthropic 팀의 투명하고 신속하며 끊임없는 협력에 진심으로 감사드립니다. 최첨단 AI를 안전하게 발전시키기 위해서는 보안 연구원과 플랫폼 공급업체가 지속적인 피드백 루프를 통해 투명하게 협력하는 상호 책임의 모델이 필요합니다. Anthropic이 포괄적이고 다층적인 수정 사항을 달성할 때까지 모든 우회 경로에 대해 반복적으로 노력한 것은 광범위한 커뮤니티 보호에 필요한 협업 표준을 보여줍니다.
- 2026년 7월 4일 초기 보고: 파일 미리보기 창에서 임의 JavaScript 실행을 통해 민감한 자격 증명 유출을 입증하는 완전한 PoC를 가지고 Anthropic에 취약점을 보고함.
- 2026년 7월 9일 분류(Triage): Anthropic은 이 취약점에 CVSS 8.7 (높음) 점수를 부여함.
- 2026년 7월 24일 패치 및 재테스트: Anthropic이 취약점을 수정하고 재테스트를 요청함.
- 2026년 7월 24일 우회 경로 보고: Noma Labs는 blob: URL 스킴의 Web Workers가 요청 필터를 우회했음을 입증함. 완전한 우회 PoC와 비디오 워크스루를 제출함.
- 2026년 8월 3일 우회 확정: Anthropic은 수정 사항이 불완전하다고 확인하고 보고서를 다시 분류(Triaged) 단계로 돌림. CSP, file:// 로딩 및 Worker 우회를 모두 포함하는 완전한 수정 작업이 진행 중임.
- 2026년 8월 17일 Anthropic은 Claude Desktop 1.30096.1 버전과 이후 버전에 수정을 배포했으며, 자동 업데이트를 통해 제공됨.
- 2026년 10월 GitHub Advisory 및 CVE 출판 대기
더 알아보기
SneakPeek 발견은 Noma Labs의 광범위한 임무 중 일부일 뿐입니다. 선제적이고 최첨단 취약점 연구는 우리가 현대 AI 기술 스택의 보호와 방어를 실현하는 핵심 요소입니다. 저희는 여기(링크)와 Noma의 YouTube 채널(링크)에서 최근 발견 및 진행 중인 보안 분석에 대해 더 많이 읽어보실 수 있습니다. 가장 취약하고 위험한 것을 찾아내는 과정에서 계속해서 우리의 발견을 공유할 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 HN OpenAI Codex의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기