VSCode 버그를 통한 1-클릭 GitHub 토큰 탈취
요약
github.dev 환경에서 VSCode webview의 키보드 이벤트 전달 취약점을 이용해 GitHub OAuth 토큰을 탈취할 수 있는 보안 결함이 발견되었습니다. 공격자는 Jupyter notebook의 마크다운 셀을 통해 악성 스크립트를 실행하고 확장 프로그램을 설치하여 사용자의 비공개 저장소 권한을 탈취할 수 있습니다.
핵심 포인트
- webview의 키보드 이벤트 전달 방식이 보안 취약점으로 작용
- 단축키와 확장 프로그램 설치 유도를 조합한 공격 가능
- 탈취된 토큰은 특정 저장소가 아닌 전체 저장소 접근 권한 보유
- 브라우저 IDE의 권한 범위 제한(Scope) 필요성 제기
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를 호출할 수 없음
좋은 정리였고, 크게 보면 웹에 임베드된 VSCode 편집기가 GitHub에 로그인되어 있다는 사실 자체가 아쉬움
심층 방어 여부와 별개로, 그 원죄 때문에 공격 표면이 크게 생김. 악성 NPM 패키지가 찾을 수 있도록 워크스테이션에 모든 권한을 가진 GitHub API 토큰을 평문으로 두는 것과 비슷함
이상적으로는 브라우저 IDE가 해당 저장소에 대한 pull/push만 가능한 임시 저장소별 권한 범위나 토큰으로 실행되고, github.com 웹 세션은 전혀 없었으면 좋겠음. 전체 GitHub 웹 UI가 필요하면 github.com으로 돌아가고, github.dev는 단일 저장소 서비스로 두는 식이 맞아 보임
다만 사용자에게 불편하고, 구현도 어렵고, github.dev 도구 전반에 역사적으로 박힌 가정일 가능성이 큼
악성 NPM 패키지 문제는 점점 더 심해질 것 같음. 최근 OpenCode 같은 AI 실행 도구가 백그라운드에서 임의의 npm 패키지를 내려받고, 홈 디렉터리와 프로젝트 디렉터리 여기저기에 뿌리는 걸 봤는데 사용자에게 알리거나 묻지도 않았음
더 나쁜 건 개발자들조차 별로 신경 쓰지 않는 듯하다는 점임
자기 저장소를 열 때 로그인된 상태인 건 괜찮지만, 다른 계정의 저장소를 열 때는 절대 그러면 안 된다고 봄. 그리고 webview 키보드 단축키도 무해한 키 바인딩만 허용하고 어떤 keydown 핸들러에도 전파되지 않게 고쳐야 함
데스크톱에서는 Electron이 직접 가로채도록 바꾸고 이 기능은 제거하는 편이 낫고, 웹에서는 기본값으로 비활성화하는 게 맞아 보임
SSH 키와 GitHub deploy key를 쓰면 어느 정도 비슷하게 만들 수 있음. 보안성까지는 단언 못 하지만, 모든 저장소에 접근 가능한 GitHub 설정은 해본 적이 없음
다른 Git 호스팅에도 비슷한 기능이 있는지는 잘 모르겠음
해당 저장소에서 pull은 가능하되, push는 토큰이 아니라 사용자가 최종 push할 수 있는 스테이징 영역으로만 하게 하면 어떨까 싶음
솔직히 LLM 에이전트도 이렇게 해야 함. LLM이 직접 push하게 두는 건 무모해 보임
이 공격이 특히 까다로운 이유는 VSCode 확장이 편집기 자체와 같은 신뢰 수준으로 실행되고, 대부분의 개발자가 권한을 검토하지 않은 확장을 수십 개씩 설치해 둔다는 점임
악성이거나 탈취된 확장이 GitHub 토큰을 조용히 유출하면 네트워크 감시 없이는 알아채기 어렵고, 확장은 격리된 프로필에서 실행해야 한다는 근거가 됨
네트워크 감시가 있어도 GitHub 자체로 유출하면 막기 매우 어려움. SSL 가로채기와 매우 엄격한 URL 허용 목록이 없으면 특히 그렇다
가장 좋은 방법은 GitHub에서 벗어나 자체 호스팅 내부 GitLab/Forgejo로 옮기고 GitHub를 완전히 차단하는 것임
최근에 비슷한 일을 겪었음. GitHub 토큰과 Cloudflare 토큰이 탈취됐음
보안을 진지하게 챙겨도 시간이 충분히 길면 결국 맞게 된다고 봄. 최선은 분리하고 피해 범위를 통제하는 것임
아무도, 아무것도 믿지 말고, OrbStack을 쓰고, 토큰은 언젠가 유출된다는 가정으로 항상 작업해야 함
작업 흐름이 완전히 끊겼지만, 다행히 토큰을 가져간 쪽은 스팸 봇에 가까웠던 듯함. 가짜 스팸 페이지를 잔뜩 만들고 암호화폐 채굴을 시도했음
가장 크게 남는 감정은 침해당했다는 느낌임. 다들 조심하길 바람
GitHub Pages 같은 페이지였는지 궁금함. 계정에 저장소가 생성됐던 건가? 토큰이 털렸다는 걸 어떻게 알아냈는지도 궁금함
MSRC에 VSCode 버그를 제보했을 때 조용히 고쳐버리는 끔찍한 경험이었다는 부분은 전형적인 MSRC임. 연구자들이 어차피 무료로 제보한다는 걸 알아낸 셈인데, 굳이 바꿀 이유가 없다고 보는 듯함
MSRC가 버그를 고치는 건 아님
이 사례의 구체 사항은 모르지만, 예전에 Bountysource와 HackerOne을 통해 버그 바운티 프로그램을 운영한 적이 있음. 가끔 보안팀이 완전히 평가하기 전에 보고서가 개발팀으로 먼저 흘러가는 일이 생김
그 시점에 개발자가 조용히 고쳐버릴 수 있음. 보안 버그와 연관되면 자신에게 나쁘게 보이거나 승진 기회에 영향을 줄 수 있다는, 합리적이든 아니든, 우려 때문일 때도 있음. 결과적으로 보안팀이 재현하려고 할 때는 이미 취약점이 사라져 있음
MSRC 입장에서는 제공된 재현 절차가 더 이상 동작하지 않는 것만 보임. 내부 버그 이력이나 누군가 이미 패치했는지는 보이지 않음. 그래서 원래 발견이 정당했더라도 보고서는 무효로 닫힘
오랫동안 그게 현상 유지였는데, 성가신 보안 연구자들이 명성 대신 보상을 요구하기 시작함
이 익스플로잇에 쓴 시간을 사실상 기부해서 VS Code의 보안 대응 개선 필요성을 알린 셈이라 고마움. 그냥 포기할 수도 있었는데 여전히 돕고 있음
이 취약점을 팔거나 묵혀둘 생각은 없음. 다만 개념 증명을 만드는 데 몇 시간이 걸릴 수 있는데, 공급사가 조용히 패치만 하고 크레딧도 인정도 안 해주면 정말 기분이 나쁨
왜 더 많은 개발자가 Neovim을 시도하지 않는지 잘 이해가 안 됨
취향일 수도 있지만, 설치된 것과 실행 중인 것을 파악할 수 있는 작은 구성이 좋음. VSCode, 브라우저 IDE, 확장, 동기화, 토큰, 임의 플러그인이 섞이면 무엇이 무엇에 접근하는지 알기 어려워짐
몇 년 전 VS Code를 그만두고 Neovim으로 옮겼음. VS Code가 기본 타입 정의가 없는 라이브러리를 위해 임의의 Python 패키지를 자동 설치한다는 걸 알게 된 뒤였음
Microsoft 공식 Python 확장의 기능이었고, 다른 면에서는 그나마 쓸 만한 유일한 확장이었지만, 내 프로젝트가 쓰는 버전과 다른 라이브러리 버전의 타입 정의를 설치했음. 검증되지 않은 서드파티 코드를 아무렇지 않게 실행하는 것처럼 보여 매우 불안했고, 설정으로 끌 수도 없어 보였음
“그 뒤로 뒤돌아보지 않았다”고 말하고 싶지만, 솔직히 지난 1~2년 동안 Neovim이 거의 업그레이드마다 내 설정을 정기적으로 깨뜨리기 시작했음. 언젠가 그럴 수도 있겠다는 낌새는 있었음. 엄밀히 말해 10년이 지났지만 nvim은 아직 첫 안정 버전을 내지 않았고, 그래서 불안정성을 탓할 수는 없지만 기억해둘 만함
다시 순정 Vim으로 돌아갈까 고민 중임. 편의 기능은 많이 잃겠지만, 일하는 도중 깨진 기능을 디버깅해야 하는 일은 줄었으면 좋겠음
Helix가 꽤 마음에 듦. Neovim을 깊이 파보진 않았지만, Helix에는 Vim에서 늘 아쉬웠던 IDE 같은 기능이 꽤 잘 들어 있음
플러그인을 잔뜩 깔거나 SpaceVim 같은 걸 쓰지 않아도 됨. 한번 확인해보면 마음에 들 수도 있음
소프트웨어 습관을 바꾸게 만드는 건 꽤 어렵다는 걸 느낌. 배워야 할 단축키가 있고, 처음에는 느리게 느껴져서 “더 낫지 않다”는 감각이 강화됨
nvim에 익숙해지는 데 시간이 걸리지만, 익숙해지면 더 빠름. 그래도 많은 사람이 안락한 영역에 머무르는 이유는 설명됨
공개 공개는 잘한 일임. MSRC에 불만을 가진 사람이 너무 많고, Nightmare Eclipse 상황처럼 이제 끓어넘치기 시작함
이런 공개들이 쌓이면 MSRC가 스스로를 돌아보고 자신들이 문제라는 걸 깨달을지도 모름. 그럴 가능성은 낮아 보이지만 기대는 해볼 수 있음
이게 여전히 최선의 접근인지는 잘 모르겠음. 기존 XSS 제출과 비교했을 때 “낮음” 등급을 받을 거라고 예상해서 아예 제출도 해보지 않은 듯함
그래도 최소한 시도해보거나, 공개하기 여러 날 전에 알려줬어야 한다고 봄. 어떻게 될지는 모르는 일이니까
글은 아주 좋았지만 마지막 부분에서 조금 헷갈렸음. 이해한 게 맞는지 확인하고 싶음
저자는 새 게시자 신뢰 시스템 때문에 단축키 트릭만으로 악성 확장을 직접 설치할 수는 없다고 했고, 게시자 검사가 없는 로컬 워크스페이스 확장으로 이를 우회할 수 있지만 CSP가 막는다고 했음
해결책은 “게시자 확인 없이 확장 설치” 단축키를 바인딩하는 로컬 워크스페이스 확장을 설치하는 것으로 보임
그래서 1) 확장이 두 개 필요하다는 뜻인지 궁금함. 첫 번째는 키 바인딩만 하는 로컬 확장이고, 두 번째는 실제 악성 확장이며 CSP 때문에 로컬일 필요도 없고 실제로 로컬일 수도 없는 것인지, 2) CSP는 로컬 확장의 JS만 막고 package.json이나 단축키 추가 능력은 막지 않는 것인지 궁금함
AI 자동 생성 콘텐츠
본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기