分頁裡的 IDE,一鍵就把 GitHub 權杖交了出去
github.dev 裡的一個零時差漏洞,讓一個惡意的預覽窗格得以伸出它的沙箱、悄悄安裝一個擴充功能,並讀走一個能存取受害者所能觸及的每一個私有儲存庫的 GitHub OAuth 權杖。修補方案對自己的侷限很誠實——而更高明的一手,是打從一開始就別把你的權杖帶進陌生人的儲存庫。
在 github.dev 裡打開一個儲存庫,點一個連結,一個跑在瀏覽器 分頁裡的編輯器就悄悄安裝了一個擴充功能、讀走了你的 GitHub OAuth 權杖,並開始列舉你的私有儲存庫。沒有下載。沒有「允許」 按鈕。整個 IDE 就活在一個網頁裡——而這正是為什麼它的爆炸 半徑是一個關於瀏覽器、而不是關於 IDE 的問題。
2026 年 6 月 2 日,資安研究員 Ammar Askar
發佈
了一個針對 github.dev 的零時差漏洞概念驗證——github.dev 是
Visual Studio Code 的瀏覽器內版本,在任何 GitHub 儲存庫上按
. 就能進入。零時差指的是廠商還來不及修補的漏洞,因為它在
被人知道的同一刻就已經公開。在這個案例裡,照 Askar 的說法,
公開的細節大約在 Microsoft 收到通報後一小時就放出去了。他說
他之所以對 VS Code 的發現改採完全公開揭露,是出於對早先回報給
Microsoft 安全應變中心的處理方式的
挫折。
這套機制值得放慢腳步看,因為它是一個類別的乾淨範例——不是一個 一次性的漏洞,而是一種瀏覽器內開發工具會不斷產出的攻擊形態。
預覽窗格不該是發射台。
程式碼編輯器會算繪大量不受信任的內容。你打開的一個 Markdown 檔案會得到一份算繪好的預覽。一個 Jupyter notebook 會顯示它的 輸出。這些預覽跑在一個 webview 裡——一個嵌在編輯器裡、 經過沙箱化的迷你瀏覽器,刻意與編輯器自身的權限隔開,這樣一個 惡意的 README 就無法直接接管你的機器。
那道牆就是全部的重點。Askar 的漏洞利用越了過去。
webview 透過一條訊息傳遞通道和主編輯器對話——這是兩邊
用來協調的一條狹窄管線。藉著濫用那條通道,跑在不受信任 webview
裡的惡意 JavaScript 得以在主編輯器視窗裡
模擬按鍵
——合成的 keydown 事件。它選的按鍵是 Ctrl+Shift+P,也就是
打開命令選擇區(Command Palette)的快捷鍵,而 VS Code 幾乎可以
從那個文字框執行它所知道的任何命令。
從那裡開始,這場攻擊把一個合法的功能拿來對付它自己。VS Code
支援本機工作區擴充功能:放在專案 .vscode/extensions
資料夾裡的擴充功能,用意是讓一個儲存庫能附帶它自己的工具。因為
一個惡意儲存庫掌控自己的檔案,它就能附帶自己的擴充功能——而那個
平常會問「你真的要執行這個發佈者的程式碼嗎?」的信任提示,被
透過在擴充功能的 package.json 裡精心打造自訂按鍵繫結而繞了
過去。那個發佈者信任對話框,整條鏈裡唯一的人為檢查點,從未出現。
獎品不是你打開的那個儲存庫。
這條鏈的酬載是一個權杖。github.dev 用 GitHub 替你登入,並握著 一個 OAuth 權杖——一份瀏覽器向 GitHub 伺服器出示、用來證明 它正在代表你行動的憑證。OAuth 的重點在於這個權杖可以限定範圍: 一個 app 應該只拿到它所需的那一小塊存取權。
這個權杖並不窄。如同 Askar 所說, 這個權杖「並未限定在你互動的那個特定儲存庫,意味著它對你有 存取權的每一個其他儲存庫都擁有完整存取權」——可讀可寫,包含 私有儲存庫。所以攻擊者拿到的不是你點進去的那個公開專案。他們 拿到的是一把通往你帳號所能觸及一切的鑰匙:你的私有儲存庫、 如果你有存取權的話你雇主的私有儲存庫、坐在那些儲存庫裡的部署 金鑰和機密、你從未給任何人看過的原始碼。這個概念驗證用它來 列舉受害者的私有儲存庫——對大多數實際工作的開發者來說,這份 清單本身就是敏感的。
這正是會推而廣之的部分。瀏覽器內的 IDE 和雲端開發環境之所以 方便,恰恰是因為它們替你攜帶憑證。github.dev 握著一個 GitHub 權杖。一個雲端 IDE 握著一個雲端權杖。一個跑在瀏覽器分頁裡的 代理式編碼助理,握著它推送程式碼和呼叫 API 所需的一切。它們 每一個都是一份高價值的機密,距離一個你沒寫的網頁,只有一次 沙箱逃脫之遙。
誠實的那部分:它修好了嗎?
兩份報導,兩幅不同的圖景,而這個落差很重要。
BleepingComputer 在撰文當下,把這個問題描述為沒有官方修補程式、 也沒有指派 CVE,並提供了一個手動的權宜辦法:清除 github.dev 的 cookie 和本機網站資料,讓最初的登入警告重新出現。
The Hacker News 帶來了 Microsoft 工程師的聲明。合夥軟體工程經理 Alexandru Dima 表示 「這個問題不影響 VS Code Desktop」 ——這個漏洞特定於瀏覽器託管的 github.dev,而非你安裝在機器上的 那個 app。Microsoft 後來表示這個漏洞「已針對我們的服務緩解, 不需要客戶採取任何行動」,這指向的是一個伺服器端的變更,而非 一個你下載的客戶端修補程式。
我們沒有立場獨立驗證這項緩解,所以我們不會告訴你威脅已經結束。 我們能談的,是當一條像這樣的鏈奏效時,爆炸落在哪裡——因為那是 一個架構問題,而架構正是那個不依賴於信任一份新聞稿的部分。
IDE 實際上跑在哪裡。
關於 github.dev,有件事讓它對我們來說很有意思:整個編輯器就是 一個網頁。webview、命令選擇區、擴充功能宿主、OAuth 權杖——全部 都活在一個瀏覽器分頁裡。這意味著「這能造成多大損害」這個問題, 難得一次,跟 Bromure 為任何分頁所要回答的是同一個問題。
在 Bromure 裡,每個分頁都跑在它自己的可拋棄虛擬機裡——一個在 Mac 上的拋棄式 Linux 訪客,沒有任何通往你的檔案、你的 keychain 或你其他分頁的路徑。在一個 Bromure 設定檔裡跑 github.dev,那麼 被竊的 OAuth 權杖、那個惡意的 webview,以及那個被悄悄安裝的 本機工作區擴充功能,就全都限定在那一個 VM 裡。在一個非持久的 工作階段裡關掉視窗,它們所活的那個世界就被抹除:權杖快取、 cookie、擴充功能、整個訪客,全沒了。
這個幾何結構改變了兩件事,而有一件它沒改變。
它改變了權杖能觸及什麼。在一個傳統瀏覽器裡,你每一個 GitHub 工作階段都共用一個 cookie 罐和一個設定檔。一個從你 github.dev 分頁裡撈走的權杖,就坐在那個瀏覽器所握的其他一切旁邊。在 Bromure 裡,你可以在它自己的設定檔裡跑 github.dev——它自己的 VM、它自己 的 cookie、它自己的儲存空間——和你的網路銀行、你的電子郵件,以及 你其他的 GitHub 身分隔開。那個拋棄式設定檔被攻陷,並不會把其他 設定檔裡的 cookie 交給攻擊者。它們不在同一台機器裡。
它改變了這個立足點能撐多久。這條鏈裡最有價值的一手,是那個 被悄悄安裝的擴充功能——一個你每次重新打開編輯器都會持續存在的 立足點。面對一個可拋棄的工作階段,根本沒有什麼可以回去的。那個 擴充功能被安裝進一個不再存在的 VM。
它解決不了什麼。
它沒辦法讓被竊的權杖變回沒被竊。當那個惡意工作階段還活著時, 那個 OAuth 權杖是真的,而攻擊者可以用它從他們自己的基礎設施, 即時地列舉並讀取你的私有儲存庫。隔離收束的是機密活在哪裡; 它沒辦法跨越網際網路伸到 GitHub 的伺服器去撤銷一份攻擊者已經 握著的憑證。那邊的緩解是那些尋常的辦法:短壽命且範圍緊縮的 權杖、在任何可疑狀況後撤銷工作階段,以及一個廠商——這裡是 Microsoft——把那個逃脫口關掉,讓那個權杖打從一開始就搆不著。
有一個比較值得說精確,因為它很容易被含糊帶過。Bromure 根本 不允許安裝 Chrome 擴充功能——不沙箱化、不策展、不來自任何商店。 那是一個刻意的產品立場:瀏覽器擴充功能是現代網路上最被濫用的 立足點之一,所以 Bromure 把這個類別整個移除。但這個故事裡的 擴充功能是一個 VS Code 擴充功能,由 github.dev 這個網頁 app 安裝進它自己的編輯器裡——這跟一個 Chrome 擴充功能是不同的東西, 活在頁面之內而不是它的周圍。Bromure 的「不准擴充功能」規則 搆不進 github.dev 裡頭去阻止它。Bromure 做的,是把整個編輯器, 連同權杖和擴充功能在內,收束在一個你可以丟掉的 VM 裡。
除非根本沒有權杖可偷。
有一種更高明的方式來運用同一套架構,而且它不花一分一毫:把 你是誰和你造訪什麼分開。
整條鏈的存在,是為了搆到一個機密——那個 github.dev 因為你登入 而握著的 OAuth 權杖。那個權杖只需要存在於你處理自己程式碼的 地方。所以就給它剛好那麼多地盤:一個專用的 Bromure 設定檔, 登入了 GitHub,你在裡頭打開你自己的儲存庫,以及你已經信任的 儲存庫。權杖活在那裡,而陌生人的程式碼不在那裡。
其他一切——那個從連結來的有趣儲存庫、某人貼出來的概念驗證、 你正在評估的相依套件——都在一個你誰也不是的地方打開:一個從未 登入過 GitHub 的設定檔。以一個匿名訪客的身分在 github.com 上 讀程式碼;如果你伸手去找編輯器,沒登入的 github.dev 也沒有什麼 值得交出去的東西。一個未驗證的工作階段,無法洩漏一個它根本 沒握著的權杖。那條漏洞利用鏈,若真的跑得起來,也是跑在一個 口袋空空的可拋棄 VM 裡。
那改變了防禦的形狀。收束在第五步限制了損害,也就是在權杖被 取走之後。分離則在第一步就把這條鏈斬首:那個惡意儲存庫從來沒 碰上那份憑證。這套紀律一行就講得完——在你工作的地方登入, 在你遊蕩的地方誰也不是——而 Bromure 設定檔讓它成為一個 兩個圖示的習慣,而不是一份資安政策。
這個一般性的教訓比這個特定漏洞活得更久。隨著越來越多的開發搬 進瀏覽器——雲端 IDE、github.dev、跑在分頁裡並攜帶推送權限的 代理式編碼代理——那些工具所握的憑證就成了一個常駐的目標,距離 一個你沒寫的頁面只有一次 webview 逃脫之遙。可防守的姿態不是 「信任 IDE 裡頭的那個沙箱」。它是去假設那個沙箱遲早會洩漏,並 把事情安排成讓它洩漏進去的那個頁面既可拋棄又一無所有。
把那個有風險的分頁跑在它自己的世界裡——一個你誰也不是的世界。 當某個東西闖進來時,沒有什麼可拿的,而你反正都會把那個世界 關掉。
那正是 Bromure 存在的目的。安裝它,給你自己的 GitHub 一個它 自己的設定檔,以一個陌生人的身分造訪所有其他人的程式碼,並讓 最壞的情況變成一個你可以關上的視窗。