世界を動かす技術を、日本語で。

VSCodeのバグを利用した1クリックでのGitHubトークン盗難

概要

  • github.dev の VSCode Web版で 重大なセキュリティ脆弱性 を発見
  • 攻撃者がリンクをクリックさせるだけ で GitHub トークンを窃取可能
  • トークンは 全リポジトリ(プライベート含む)への読み書き権限 を持つ
  • Webviewのサンドボックス不備キーボードイベントの誤処理 が原因
  • 証拠コード(PoC)と 自己防衛策、VSCode側の対応も解説

GitHub.devとVSCode Webviewのセキュリティモデル

  • github.dev は GitHubリポジトリを ブラウザ上でVSCode風に編集可能 なサービス
  • OAuthトークン を github.com から github.dev へ渡して認証・操作を実現
    • このトークンは 全リポジトリにアクセス可能 な広範な権限
  • VSCode Web版は Webview(iframe)を用いてサンドボックス化
    • Webview内のJavaScriptは 本体とは別オリジン で実行
    • Node.js APIやVSCode APIへの直接アクセス不可
  • Window.postMessage() で本体とWebview間の通信を実現
    • 例:Markdownプレビューの行ハイライト同期など

脆弱性の詳細

  • Webview内で キーボードイベント(keydown)が本体へ伝播 される仕様
    • 本体はこれを ユーザー操作として扱う
  • 攻撃者が 任意のキーボードイベントを偽造 し、危険なコマンドを実行可能
    • 例:拡張機能のインストール、通知承諾など
  • 拡張機能のインストール時にも 信頼性チェック回避の手口 が存在
    • .vscode/extensions.json で 推奨拡張の通知 を表示
    • Ctrl+Shift+A キーで通知の「インストール」を自動承認
    • ローカル拡張機能 を用いて信頼性チェックをスキップ
  • 拡張機能の package.json で任意のキーバインド追加 が可能
    • 例:Ctrl+F1 で攻撃用コマンドを実行

攻撃の流れ(PoC)

  • 攻撃用リポジトリに Jupyterノートブックローカル拡張機能 を配置
  • ノートブックセル内の imgタグのonerror属性でJavaScriptを発動
  • 攻撃スクリプトの流れ
    • VSCodeの通知表示を待機
    • Ctrl+Shift+A の偽造イベントで拡張インストールを承認
    • 拡張インストール後、 Ctrl+F1 で追加コマンドを実行
    • 攻撃拡張が GitHubトークンを窃取し、API経由でリポジトリ一覧取得
  • 実際のPoC例:

防御策と推奨対応

  • 信頼できないリポジトリやリンクをgithub.devで開かない
  • Jupyterノートブックや拡張機能の内容確認 の徹底
  • VSCodeのバージョンアップ・脆弱性情報の確認
  • OAuthトークンの再発行・権限見直し
  • ブラウザキャッシュや拡張機能の整理

VSCode側の対応と評価

  • Webviewのキーボードイベント伝播仕様の見直し
  • 拡張機能インストール時の信頼性チェック強化
  • CSP(Content Security Policy)設定の改善
  • 脆弱性報告に対する迅速な対応と開示

フルディスクロージャー(Full Disclosure)とタイムライン

  • 脆弱性発見から報告、修正、公開までの流れ
  • コミュニティやユーザーへの 透明性重視の情報公開
  • セキュリティ研究者と開発元の協力体制 の重要性

まとめ

  • github.devのVSCode Webviewは Webアプリ特有の脆弱性に注意
  • リンククリック一発でGitHubトークン漏洩のリスク
  • ユーザー自身の防衛意識VSCode側の継続的なセキュリティ改善 が不可欠

Hackerたちの意見

この脆弱性を通じてVS Codeのセキュリティ対応を改善するために、時間を寄付してくれてありがとう。諦めずに助けようとしてくれてるのが嬉しいよね。

ありがとう、すごく優しいコメントだね。これらの脆弱性を売ったり、放置したりするつもりは全くないよ。でも、ベンダーが証明概念を作るのにかかる時間を無視して、黙ってパッチを当てて、あなたにクレジットを与えないのは本当に気分が悪い。

すごく良いまとめだね。ちょっと視点を広げすぎかもしれないけど、ウェブに埋め込まれたVSCodeエディタがGitHubにサインインしてるのは残念だな。防御の深さとか関係なく、そこから大きな脆弱性が生まれちゃう。まるで、悪意のあるNPMパッケージが見つけられるように、神の権限を持ったGitHub APIトークンがワークステーションに平文で保存されてるみたいなもんだよね。理想的な世界では、ブラウザ内のIDEがリポジトリごとの一時的な権限スコープやトークンで立ち上がって、該当リポジトリへのプルやプッシュだけができるようになればいいのに。github.comのウェブセッションは一切なしでさ。フルなGitHubウェブUI体験が欲しいなら、github.comに戻って、github.devを単一リポジトリサービスにすればいいんじゃないかな。まあ、a) ユーザーには不便、b) 実装が難しい、c) github.devのツールに歴史的な前提が組み込まれてるから、そうなってるんだろうけど。ああ、残念。

悪意のあるNPMパッケージがワークステーション上の任意のファイルを読み取ってるなら、普通は現在の認証情報でgit cloneやpushなどを実行できるんじゃないの?

ブラウザ内のIDEがリポジトリごとの一時的な権限スコープで立ち上がったら素晴らしいよね。実際、彼らはcodespacesのためにそれをやってるんだよ。トークンは、アクティブにしたリポジトリに対してのみ読み書きの権限があるんだ。[1] 彼らはgithub.devでもそれを検討すべきだね。[1] https://orca.security/resources/blog/hacking-github-codespac...

一時的なリポジトリごとの権限スコープやトークンで、そのリポジトリに対してプルとプッシュだけを許可するもの。 リポジトリからプルはできるけど、ユーザーが実際にプッシュできるのはステージングエリアだけにするのはどう?正直、LLMエージェントもこれをやるべきだと思う。自分のLLMにプッシュさせるのは無謀に感じるな。

あの人たちには申し訳ないけど、これはMSRCやVSCodeのセキュリティ姿勢に影響を与えるための数少ない手段の一つなんだ。誰かがマイクロソフトにブラックリスト入りすることになるだろうね。

「おお、素晴らしい神話よ、どうやって自分の製品からすべての脆弱性を取り除くの?」考え中… 脆弱性研究者を全員禁止しよう。

VSCodeのバグを報告するためにMSRCとやり取りした最後の時は、静かにバグを修正されてしまったひどい経験だった。クラシックなMSRCだね。研究者が無料で報告することを理解してしまったから、何も変わらないんだろうね。

長い間そのままだったけど、厄介なセキュリティ研究者たちが権威じゃなくて報酬を求め始めたんだよね。

MSRCはバグを修正しないんだ。具体的なケースは知らないけど、過去にBountysourceやHackerOneを通じてバグバウンティプログラムを管理してたことがある。たまに起こるのは、報告がセキュリティチームが完全に評価する前に開発チームに届くこと。そうなると、開発者が静かに問題を修正することを決めることがある。時には、セキュリティバグに関連付けられることが自分に悪影響を及ぼすかもしれないという懸念からそうすることもある。結果的に、セキュリティチームが報告を再現しようとする頃には、脆弱性はすでに消えている。MSRCの視点から見ると、提供された再現手順がもう機能しないだけが見える。バグの内部履歴や誰かがすでにパッチを当てたかどうかは見えないから、元の発見が正当でも報告が無効として閉じられちゃうんだ。

MSRCの状況は本当に信じられないよ。もっと良い情報源はあるかもしれないけど、The Primeagenのこの動画は良い入門だと思うよ。 https://www.youtube.com/watch?v=9kxx5xp5nTQ

VSCodeが好きだけどマイクロソフトが嫌なら、Zed(zed.dev)を試してみて。

Zedは素晴らしいよ。変かもしれないけど、最後の一歩が、VSCodeと同じようにブラウザベースのZedセッションを持つことなんだ。

Zedには多くの統合AIやチーム共有機能があって、通信するから、NIS2コンプライアンスみたいなことをやってる人には問題だね。VSCodeもコンプライアンスの悪夢だし。

M$は嫌だけどVSが好きなら、VsCodiumを使ってみて。俺は使ってたけど、今はZedが好きで、VSCodiumとSublime Textの代わりに一気に使ってる。

すごく良いまとめだけど、最後の方でちょっと混乱しちゃった。誰か教えてくれない?著者が言ってたのは:新しいパブリッシャートラストシステムのせいで、ショートカットトリックを使って悪い拡張機能を直接インストールすることはできない;ローカルワークスペース拡張を使うことでこれを回避できるけど、CSPがそれをブロックする;解決策は「パブリッシャーをチェックせずに拡張機能をインストールする」ショートカットをバインドしたローカルワークスペース拡張をインストールすることのようだ。だから、こういうことだと思う:1. 2つの拡張機能が必要で、1つ目はローカルでキー バインディング専用、2つ目は「本物」の悪いもので、もうローカルである必要はない(実際、CSPのせいでローカルにはできない)?2. CSPはローカル拡張のJSを防ぐだけで、package.jsonやショートカットを追加する能力には関係ないよね?

1と2は正しいよ、ここでPoCリポジトリを見てみて:https://github.com/ammaraskar/github-dev-token-steal-poc/tre... もっと直接的な実行のためにmy-extension/extension.jsを置いてみるけど、CSPがそれをブロックするんだ。ただ、スクリプトのCSPがブロックしてるだけだから、package.jsonを取得するのはまだ問題ない。だから、結局キー バインディングに使うことになった。

最近、githubトークンが盗まれたり、cloudflareトークンも盗まれたりしたことがあった。セキュリティを真剣に考えていても、長い時間が経てば必ずやられるよ。最善の策は、分けてダメージをコントロールすること。誰も信じない、何も信じない、orbstackを使って、常に自分のトークンがいつか漏れる前提で行動することだ。これで全ての勢いが失われた。幸いなことに、ただのスパムボットが私のトークンを取って、たくさんの偽のスパムページを作って暗号を掘ろうとしてたみたい。最も感じたのは、侵害された感覚だよ。みんなも気をつけてね。

たくさんの偽のスパムページを作って、クリプトをマイニングしようとしてるの? GitHubページみたいな? あなたのアカウントにリポジトリが作成されてたの? トークンがハッキングされたことにどうやって気づいたのか気になる。

もしウェブビューに他のXSSがあって、被害者に開かせることができれば、実質的にそのコンピュータでフルRCEが取れるよ。GitHubのクレデンシャルか、そのコンピュータか、どっちが悪いか決められないね。