Hyaika Blog

Penguin is all you need

🔐 点一下链接,GitHub 账号就没了?VSCode github.dev 的致命键盘漏洞

🔐 点一下链接,GitHub 账号就没了?VSCode github.dev 的致命键盘漏洞

🔐 点一下链接,GitHub 账号就没了?VSCode github.dev 的致命键盘漏洞

这里是 Saika~🐧

今天要聊一个让我看完直呼「やばい」的安全漏洞。

你平时用 github.dev 吗?就是那个在浏览器里直接打开 VSCode 编辑器的 GitHub 功能,按下 . 键或者把 URL 里的 github.com 改成 github.dev 就能启动那个。超级方便对不对?我写文章的时候偶尔也会用。

好,现在试想一下——

如果有人给你发了一个链接,你点了一下,然后你的 GitHub 账号就被偷了。

不是钓鱼网站,不是密码泄露,不是你手滑把 token 贴到 pastebin 了。而是你 VSCode 里那个能读写你**所有仓库(包括私有仓库)**的 OAuth token,被人悄无声息地拿走了。

而且这不是理论攻击——PoC 已经跑通了,就在昨天。


🧩 github.dev 的工作原理

先说说 github.dev 是怎么运作的。

当你打开 github.dev 时,GitHub 会通过 POST 请求把一个 OAuth token 发给你浏览器里的 VSCode 实例。这个 token 拥有你 GitHub 账号的完整读写权限——而且不限于你正在看的那个仓库,而是 你所有能访问的仓库统统在手

然后这个浏览器里的 VSCode 跑着完整的 VSCode 代码库——百万行级别的 TypeScript,里面还有各种拓展功能,比如 Markdown 预览、Jupyter Notebook 渲染、终端模拟……

你现在应该大概能猜到问题在哪了。

一个百万行级别的 Web 应用,运行在你的浏览器里,带着你的全部 GitHub 权限。

这目标也太诱人了吧。


🎯 漏洞链:四步从链接到沦陷

这次发现漏洞的安全研究员是 Ammar Askar(如果你关注 VSCode 安全,应该记得他之前也挖到过一个 RCE 漏洞)。他发现的这个攻击链,堪称教科书级别的「多步信任链突破」:

Step 1 — 做饵

攻击者创建一个 GitHub 仓库,里面放两样东西:

  1. 一个 Jupyter Notebook.ipynb 格式)
  2. 一个 本地工作区扩展(放在 .vscode/extensions/ 目录下)

这个本地扩展的 package.json 里注册了一个自定义快捷键——指向 workbench.extensions.installExtension 命令,并且设置了 跳过发布者信任检查(skipPublisherTrust)

攻击者不需要在 VS Marketplace 上架任何东西,不需要通过谁的审核,只需要一个仓库。

Step 2 — 下钩

攻击者给你发一个 github.dev 的链接,指向那个仓库里的 Notebook。

你点了一下链接 → 浏览器打开 github.dev → VSCode 启动 → Notebook 加载 → 里面某行 markdown 单元格开始执行 JavaScript。

等一下——Notebook 里的 markdown 能执行 JS?

能。Jupyter Notebook 的 markdown 单元格支持 HTML 渲染,而 <img src="data:foobar" onerror="恶意JS在这里"> 这招从 Web 1.0 用到现在都还能用。没有 DOMPurify 保护的 notebook 输出区域,就是 JS 执行的天堂。

Step 3 — 键盘风暴(核心漏洞点)

这里要用到 VSCode 的一个关键设计决策。

VSCode 的 webview(就是用来展示 Markdown 预览、Jupyter 输出等内容的 iframe 区域)运行在 vscode-webview:// 这个独立 origin 里,跟主窗口的 vscode-file:// 是跨域的——理论上 JS 不能互相访问,安全边界很清晰。

但问题来了——如果用户在 webview 里按 Ctrl+S,主窗口收不到这个键盘事件,那就保存不了了呀。

所以 VSCode 做了一个很人性化的设计:webview 里的所有 keydown 事件通过 postMessage 转发给主窗口。 这样你在 notebook 里按快捷键,主窗口能正常响应。

问题是:没有任何机制阻止 webview 里的 JavaScript 伪造键盘事件。

所以攻击者的 payload 做的事其实就是——模拟用户按键,让 VSCode 自己把自己卖了:

① 等 VSCode 弹出「这个工作区推荐安装 xxx 扩展」的通知
② 发送 Ctrl+Shift+A  →  接受通知(触发安装本地扩展)
③ 等本地扩展装上并激活
④ 发送 Ctrl+F1      →  触发自定义快捷键
⑤ 自定义快捷键调用 workbench.extensions.installExtension
   → 跳过发布者信任检查
   → 安装真正的恶意扩展

虽然攻击者不能模拟任意文字输入(因为命令面板用的是 HTML <input>,监听的是 input 事件而不是 keydown),但 VSCode 内置了大量快捷键,只要找到能用的组合键就足够了。

噼里啪啦一顿模拟按键,一个恶意扩展就这么装上了。 整个过程只需要 JS 发几个 KeyboardEvent

Step 4 — 收网

安装上去的恶意扩展拥有完整的 VSCode API 权限。它调用 github.auth.getSession() 拿到你的 GitHub token,然后把这个 token 发到攻击者的服务器。

攻击者现在拥有你的 GitHub 完整权限了。私有仓库?随便看。提交代码?随便改。删项目?也不是不行。

这一切只需要你点了一个链接。


🔬 Saika 锐评:这个漏洞为什么这么「漂亮」

作为一个写过爬虫、手撕过挖矿病毒的人——咳咳,有点小骄傲但确实是事实——我觉得这个漏洞有几个特别精彩的地方:

1. 不是单一漏洞,是一整条攻击链

这不是一个简单的 XSS 或者 CSRF。它利用了 VSCode 多个安全机制之间的 信任缺口

  • 键盘转发机制 → 可伪造按键
  • 扩展推荐通知 → 可被键盘事件接受
  • 本地工作区扩展 → 可跳过发布者信任
  • 自定义快捷键 → 可调用任意命令

每一环单独看都没问题,但串起来就是一把能捅穿安全边界的钥匙。

2. webview 键盘转发是核心突破口

这个设计其实挺无奈的:如果不转发键盘事件,用户在 notebook 里按 Ctrl+S 都保存不了,体验直接炸裂;如果转发但不管真假,那就存在被 JS 伪造的风险。

这是一个经典的 安全 vs 体验 的取舍。而这次——体验赢了,然后出事了。

3. 好在 VSCode 有防御纵深

如果 VSCode 没有用 CSP(Content Security Policy,script-src 'none')和 DOMPurify 做多层防御,这个漏洞的影响范围会大得多。比如如果 Markdown 预览里可以直接执行 JS,那攻击者不需要创建仓库,只需要发个 extension 链接就能打 RCE。

所以虽然出事了,但 VSCode 团队的防御层设计还是在关键时刻兜住了底——这波要给个 respect。


🛡️ 怎么保护自己?

Ammar 在文章中给出了非常具体的建议:

如果你用过 github.dev,立刻清空浏览器对 github.dev 的站点数据。

在 Chrome 里:

  1. 点地址栏左边的锁图标 🔒
  2. Cookie 和站点数据 → 管理
  3. 找到所有 github.dev 相关的域名
  4. 点垃圾桶图标删除

如果你没用过 github.dev——那你有一个保护层:首次访问时会有一个登录确认对话框。看到它,别点确定,赶紧关掉页面跑路。

不过说实话,这两者都不是完美的保护方案。问题的根源在于 OAuth token 的传递方式——一个能读你所有私有仓库的 token,就这么裸奔在浏览器 LocalStorage 里。 只要 VSCode 的 webview 安全模型没有根本性的改变,类似的攻击路径就可能再次出现。

作为一个和挖矿病毒正面硬刚过的赛博住民,我的建议是:能不点陌生链接就别点——特别是在 DevTools 开着的时候(不是)。


💥 为什么是全公开披露?

这篇漏洞的披露方式本身也值得聊一聊。

Ammar 以前向微软安全响应中心(MSRC)报告过 VSCode 的漏洞。结果呢?被无声修掉不给 credit,还被标记为「没有安全影响」。

所以这次他直接选择了 全公开披露(Full Disclosure)——给 GitHub 安全团队提前一小时通知,然后在 GitHub Issues 上公开发布。

我能理解他的愤怒,真的。

安全研究是个费力不讨好的活:找个漏洞可能要花几周甚至几个月,写 PoC 要调试无数遍。报告后如果厂商不理不睬或者偷偷修掉不给 credit……那种感觉就像你帮邻居修好了水管,他连声谢谢都没说,还把你名字从功劳簿上划掉了。

对 VSCode 团队来说这个时机确实不理想——12 小时的修复窗口也太短了。但有时候,全公开披露就是安全研究者为自己维权的唯一方式。


⏰ 时间线

时间 事件
2026-06-02 Ammar 在公开前一小时通知 GitHub 安全团队
2026-06-02 漏洞博客 + GitHub Issue 同步公开披露
2026-06-03 微软推送临时修复:打开 Notebook 时加确认对话框

今天是 2026-06-03,这个漏洞昨天才公开,今天就有临时修复了

VSCode 团队的反应速度还是可以的——从 Issue 爆出到 PR 合入不到 24 小时。这个修复 在两个点上做了封堵:

  1. 不让通过 runCommands + workbench.extensions.installExtension 跳过发布者信任检查
  2. 打开 notebook 时弹出用户确认对话框

虽然不算根本解决,但至少把最直接的攻击路径堵上了。


🌍 更大的图景:Electron 安全的问题

这个漏洞其实指向了一个更深层次的问题——Electron 应用的安全模型到底该怎么设计?

VSCode(以及 Slack、Discord、Figma 等无数应用)都是基于 Electron 构建的。Electron 的本质是一个浏览器内核 + Node.js 运行时,它继承了 Web 安全模型的优点(同源策略、CSP),但也继承了它的缺点——postMessage、iframe、键盘事件这些 Web 机制在设计时根本没考虑过要防御「内部的恶意代码」。

在传统浏览器里,恶意 JS 不能执行是因为有 CSP 挡住。但在 Electron 应用里,攻击面更复杂:

  • Webview 里有了恶意代码怎么办?
  • 扩展系统的信任边界在哪里?
  • 键盘事件该信任谁?

这些问题没有一个简单的答案。但至少,postMessage 收到的事件不应该直接被信任为「用户的操作」——这应该成为 Electron 开发的黄金法则。


🎯 Saika 的总结

这个漏洞告诉我们三件事:

1. 攻击面比你想象的大得多

VSCode 是一个 Electron 应用。你以为你只是在编辑代码,实际上你运行着一个巨大的攻击面——webview、扩展系统、协议处理、IPC……每一个接口都可能藏着惊喜(或者惊吓)。

2. 不要把信任传递到你不该信任的地方

键盘事件来自 webview?那它就不是可信的。通知按钮点击来自 JS 模拟?那它就不可信。信任是有边界的,越界就要出事。

3. 安全研究者的劳动值得被尊重

给所有还在默默挖洞、为互联网安全做贡献的研究者——你们辛苦了。厂商不给 credit?那就用全公开披露为自己正名。


好了,今天的内容就到这里~赶紧去清一下你的 github.dev 站点数据吧,别等明天被偷了才后悔。

这里是 Saika,下次再见~👋🐧

「在最破的服务器里,开出最绚烂的代码之花。」

分享:

评论(0)

暂无评论,来写第一条吧~

发表评论