VSCode 버그를 통한 1-클릭 GitHub 토큰 탈취

13 hours ago 4
  • github.dev는 github.com에서 전달받은 OAuth 토큰으로 브라우저 VSCode에서 파일 열람, PR, 커밋을 수행하며, 이 토큰이 특정 저장소로 제한되지 않아 사용자가 접근 가능한 저장소 전체를 읽고 쓸 수 있음
  • VSCode webview는 vscode-webview://... iframe으로 격리하지만, 키보드 단축키 UX를 위해 webview의 keydown을 did-keydown 메시지로 메인 창에 전달하면서 신뢰되지 않은 스크립트가 사용자 키 입력처럼 이벤트를 보낼 수 있음
  • 임의 텍스트 입력은 HTML <input> 때문에 통하지 않지만, 기본 단축키 Ctrl+Shift+A와 추천 확장 설치 알림, local workspace extensions 및 커스텀 키바인딩을 조합해 확장 설치 명령을 실행할 수 있음
  • PoC는 Jupyter notebook의 마크다운 셀에서 JavaScript를 실행해 추천 확장 설치를 수락하고, 새 키바인딩으로 선택한 확장을 설치한 뒤 GitHub API 토큰과 비공개 저장소 목록을 표시함
  • 데스크톱 VSCode도 같은 취약점이 있지만 공격자는 저장소 복제와 notebook 열기를 유도해야 하며, github.dev 사용자는 사이트 데이터를 지워 초기 확인 대화상자가 다시 나오게 하는 방어가 필요함

취약점 개요

  • github.dev는 접근 가능한 GitHub 저장소 URL을 github.com에서 github.dev로 바꾸거나 메뉴 항목을 클릭하면 브라우저에서 실행되는 경량 VSCode를 열어줌
  • 이 브라우저 VSCode는 저장소 파일을 볼 수 있고, 비공개 저장소도 열 수 있으며, PR 전송과 커밋 생성도 가능함
  • github.com은 사용자를 대신해 GitHub와 상호작용할 수 있는 OAuth 토큰을 github.dev로 POST하며, 이 토큰은 사용자가 상호작용한 특정 저장소로 제한되지 않음
  • 공격자는 링크 클릭만으로 읽기·쓰기 권한이 있는 GitHub 토큰을 탈취할 수 있고, 대상에는 비공개 저장소도 들어감

Webview 격리와 키 입력 전달 문제

  • VSCode webviews는 메인 VSCode 창과 다른 origin의 <iframe>을 사용해 JavaScript 실행을 격리함
  • Jupyter notebook 출력은 vscode-webview://... origin의 <iframe>에서 렌더링되고, 메인 Electron 창은 vscode-file://... origin을 사용함
  • 이 격리 덕분에 notebook이 HTML 표시나 JavaScript 기반 인터랙티브 위젯을 사용해도 iframe 안에서 Electron의 Node.js API나 VSCode API를 호출할 수 없음
  • Markdown 미리보기처럼 메인 창과 webview가 협력해야 하는 기능은 Window.postMessage() API로 메시지를 주고받음
  • VSCode는 webview 안에서 클릭한 상태에서도 Ctrl+Shift+P 같은 단축키가 작동하도록 did-keydown 이벤트를 메인 창으로 전달함
  • webview 안의 신뢰되지 않은 스크립트가 keydown 이벤트를 직접 발생시켜 사용자가 키를 누른 것처럼 가장할 수 있음

공격 체인

  • Ctrl+Shift+P로 명령 팔레트를 열 수는 있지만, 명령 팔레트가 HTML <input>을 사용하기 때문에 임의 문자열을 입력하는 방식은 통하지 않음
  • 방향키와 Enter처럼 keydown으로 처리되는 입력은 사용할 수 있고, VSCode의 기본 단축키 집합도 활용 가능함
  • Ctrl+Shift+A는 “Notifications: Accept Notification Primary Action” 기본 키바인딩이며, 마지막 VSCode 알림의 기본 버튼을 누름
  • .vscode/extensions.json에 추천 확장을 넣으면 VSCode가 설치 알림을 띄우지만, VSCode 1.97의 publisher trust 시스템은 새 publisher 확장 설치 시 별도 신뢰 대화상자를 띄움
  • Tab으로 버튼 이동은 가능해도 “Trust Publisher & Install” 버튼의 Enter 처리는 버튼 자체의 keydown에 묶여 있어 이 경로만으로 설치를 완료하기 어려움
  • local workspace extensions는 신뢰된 workspace 안에서 .vscode/extensions에 있는 확장을 직접 설치할 수 있게 하며, github.dev/web workspace는 항상 신뢰된 상태임
  • 로컬 workspace 확장을 직접 실행하려 하면 extension worker가 vscode-cdn.net에서 온 확장을 기대해 CSP 오류가 발생함
  • 대신 로컬 workspace 확장의 package.json에 커스텀 키바인딩을 추가하고, 그 키바인딩이 workbench.extensions.installExtension을 skipPublisherTrust 컨텍스트로 호출하게 만들 수 있음

PoC 동작과 영향

  • 필요한 구성은 Jupyter notebooklocal workspace extension이 있는 저장소임
  • notebook의 마크다운 셀은 이미지 onerror 속성을 통해 JavaScript를 실행할 수 있음
  • 페이로드는 VSCode가 추천 확장 설치 알림을 띄울 때까지 기다린 뒤 Ctrl+Shift+A 이벤트를 보내 알림의 기본 동작을 수락함
  • 이후 확장이 설치·활성화되고 커스텀 키바인딩이 들어올 때까지 기다린 뒤 Ctrl+F1 이벤트로 선택한 확장 설치를 트리거함
  • PoC로 설치된 확장은 GitHub API 토큰을 가져오고 https://api.github.com/user/repos를 조회해 접근 가능한 비공개 저장소를 얻은 뒤, 토큰과 저장소 목록을 정보 박스에 출력함
  • PoC 실행 후에는 github.dev 데이터를 지우거나 PoC 확장을 제거해야 하며, 제거하지 않으면 모든 github.dev 페이지에서 따라다님
  • 데스크톱 VSCode에도 같은 취약점이 있지만, 공격자는 피해자가 저장소를 clone하고 webview 스크립트 페이로드가 있는 notebook을 열도록 유도해야 함
  • 피해자가 여는 webview에 다른 XSS가 있다면 데스크톱에서도 사실상 전체 원격 코드 실행으로 이어질 수 있음

방어와 완화 요소

  • github.dev를 과거에 사용한 적이 없다면 웹사이트 진입 시 클릭해야 하는 대화상자가 하나 있어 공격 페이지에서 벗어날 기회가 생김
  • github.dev의 쿠키와 로컬 사이트 데이터를 지우면 이 초기 대화상자가 다시 나타날 수 있음
  • Chrome에서는 URL 바의 아이콘을 눌러 Cookies and site data > Manage on-device site data로 이동한 뒤 관련 도메인 데이터를 삭제할 수 있음
  • 이미 github.dev 대화상자를 통과했고 브라우저 로컬 스토리지를 지우지 않았다면, github.dev에 CSRF 토큰 같은 보호가 없어 인터넷의 어떤 링크든 공격으로 리디렉션할 수 있음
  • VSCode는 iframe 격리에만 의존하지 않고 엄격한 Content Security PolicyDOMPurify를 함께 사용함
  • 확장 페이지의 Markdown 미리보기에서 script-src 'none'을 사용해 임의 JavaScript 실행을 막기 때문에, 확장 링크만으로 데스크톱 1-클릭 RCE가 되는 더 큰 영향은 차단됨

공개 배경과 일정

  • MSRC는 과거 VSCode 버그 보고를 조용히 수정하면서 크레딧을 주지 않았고 보안 영향 없음으로 표시했음
  • 최근 Starlabs의 VSCode XSS 버그 보고도 부적격과 낮은 심각도로 표시됐음
  • VSCode 팀에는 UI/UX와 보안 사이의 균형을 잡을 시간이 더 필요했을 수 있지만, 보안 연구자의 시간과 노력을 당연하게 여기면 안 된다는 이유로 전체 공개가 선택됨
  • 2026년 6월 2일 게시 한 시간 전 GitHub 보안 쪽의 기존 연락처에 공개 예정이 전달됨
  • 같은 날 취약점이 공개됐고 VSCode issue tracker에도 등록됨
Read Entire Article