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를 호출할 수 없음