資安與權限設計

門牌換人,鑰匙還有效?npm Trusted Publishing 的 SlugFest 漏洞與 GitHub 緊急上鎖

The Hacker News 於 2026/10/13 報導:Bloom Security 發現 npm Trusted Publishing 在首次成功發布前只信任 GitHub 的 owner/repo slug,忽略永久倉庫 ID,攻擊手法代號 SlugFest。逾 1,500 套件、合計下載逾 1,000 萬次受影響。GitHub 已改為新建信任設定須於 48 小時內完成首次發布才會驗證並綁定不可變身分,並拒絕來自 issue_comment 事件的 trusted publishing token。本文整理維護者與企業前端團隊該立刻做的檢查。

扁平插畫:海軍藍掛鎖角色守護紙箱包裹,浣熊試圖更換小屋門牌,珊瑚與深藍配色,無文字。
門牌換人,鑰匙還有效?npm Trusted Publishing 的 SlugFest 漏洞與 GitHub 緊急上鎖

Bloom Security 揭穿:信任綁在「owner/repo」門牌而不是永久倉庫 ID,逾 1,500 套件、合計逾千萬次下載暴露在被接管風險。GitHub 現在要求新建信任設定 48 小時內完成首次發布,否則過期。

供應鏈攻擊通常讓人聯想到「帳號被盜、token 外洩」。Bloom Security 這次挖到的洞更讓人背脊發涼:攻擊者根本不必偷你的憑證。只要你的 npm Trusted Publishing 還綁在一個「還沒真正發布過」的 GitHub 門牌(slug)上,而那個門牌後來被改名、轉移或刪掉後變成可被別人申請——對方就能走到同一個 owner/repository 地址,用全新的倉庫 ID 換到發布權,把惡意版本掛上你原本的套件名。

2026 年 10 月 13 日,The Hacker News 的 Ravie Lakshmanan 報導了這起事件,以及 GitHub 的緊急因應。研究在 2026 年 6 月 6 日回報給 GitHub;攻擊手法代號 SlugFest。Bloom Security 表示找到逾 1,500 個脆弱套件,合計下載次數超過 1,000 萬。

Trusted Publishing 本來是好事

先把背景講清楚,免得「OIDC/Trusted Publishing 很危險」變成錯誤標題。

npm 在 2025 年 7 月導入 Trusted Publishing:讓你在 CI/CD(例如 GitHub Actions)用 OpenID Connect(OIDC)短效 token 發布套件,不必再把長效 npm token 塞進 secrets。流程大致是:CI 為這次 workflow run 產生短命密碼學 token → npm registry 對照你預先授權的設定驗證 → 通過才給發布憑證。好處很實在:少管長效密鑰、自動產生 provenance 證明,使用者比較能追溯「這包是在哪裡、由誰建出來的」。

問題出在信任錨點選錯了。

漏洞本質:鎖看的是門牌,不是屋主

Bloom Security 研究員 Golan Myers 的比喻很傳神:這像一把鎖,檢查的是門上的地址,而不是誰擁有這間房子——屋主搬走後,搬進來的人就拿到鑰匙。

技術細節是:GitHub 的 OIDC token 其實帶有即使改名、轉移也會跟著走的數字倉庫 ID,但 npm 在該倉庫首次成功發布之前,基本上只認 slug(owner/repository 這種可讀名稱),忽略那個不可變 ID。於是信任綁在「名字」而不是「身分」。

攻擊前提很窄、卻很真實:

  1. 受害者的 trusted publisher 指向某個攻擊者有機會申請到的 GitHub slug;
  2. 而且該倉庫從來沒用這個綁定真正發布過任何版本。

當維護者把倉庫改名、轉移或刪除,舊 slug 釋出後,攻擊者可以:

  1. 在同一個 owner/repository 路徑建立新倉庫(GitHub 會給新的數字 ID);
  2. 建立並觸發 npm publish workflow,拿到帶有「舊 slug+新 ID」的 OIDC token;
  3. 把 token 交給 npm 交換端點——npm 看到 repository claim 符合存檔的 slug,就發出發布憑證;
  4. 攻擊者取得時效性的發布 token,對自己不擁有的套件推上惡意版本,卻繼承原套件的名稱、下載數與依賴關係。

Myers 強調:這不需要內部消息、不需要偷憑證、也不需要搶時間差。唯一前提是「slug 可用,且綁定尚未用來發布」——而那幾乎完全取決於受害者自己的倉庫衛生習慣。

為什麼 AI 代理讓事態更糟

報導引用 Myers 的情境:攻擊者先污染一個套件;熱門維護者機器上的 AI 代理自作主張把依賴拉進來;那個入口再被用來把惡意碼推進更熱門的套件——一個人有正確存取權限被曝露,整條鏈就垮了。Bloom Security 也提醒:代理常自己解析依賴、傾向抓最新版、很少檢查套件從哪來;透過被回收 slug 發布的惡意版,可能在沒有人審核的情況下被拉進來執行。

這和前陣子社群討論的「安裝腳本/自動化代理放大供應鏈風險」是同一類問題的不同切面:自動化愈勤快,愈不能把「最新版=安全」當真。

GitHub 做了什麼

GitHub 的因應重點是把「未驗證」的信任設定變成有期限:

  • 新建的 trusted publisher 設定必須在建立後 48 小時內完成首次成功發布,設定才會被驗證並免除過期;驗證後會綁到「倉庫的不可變身分」。
  • 官方文件寫明:Your configuration becomes validated and exempt from expiry after its first successful publish。
  • 變更 repository 或 project 身分需要新的信任關係與新的 48 小時驗證窗;一般編輯不會重設期限。
  • npm 拒絕來自 GitHub Actions issue_comment 事件的 trusted publishing token(並延續既有對 pull_request_target 的限制)。

簡單說:GitHub 想堵住「先掛一個永遠不用的信任設定、等 slug 改天換人」這條路。改門牌或換專案身分,就請你重新建立信任,並在兩天內真的發一次版來「蓋章」。

給 npm 維護者的立刻行動清單

報導整理的建議,值得直接貼進團隊 runbook:

  1. 稽核所有 trusted publisher 綁定:列出的 repository slug 是否仍指向你控制中的倉庫?
  2. 若倉庫已改名或轉移:刪除舊信任綁定,用目前 slug 重建。
  3. 監控異常的 npm publish 事件(你沒發版卻出現新版本,就是火警)。
  4. 每次刪除、轉移或改名倉庫時,同步刪掉信任綁定——把這步寫進作業程序,不要靠記憶。

企業前端/Node 團隊即使「不是套件作者」,也該做對稱的防禦:鎖定依賴版本與 lockfile、啟用 provenance/attestation 檢查(若流水線支援)、對關鍵套件做允許清單、代理自動升級要有人核准。SlugFest 證明「名字還在」不等於「還是同一間房」。

同系列:Extension Resurrection

文章也提醒這不是 Bloom Security 第一次挖到「名字可被回收」類問題。2026 年 8 月他們發現 Open VSX 與 VS Code Marketplace 的 extension pack 可以引用市集上不存在的擴充套件;攻擊者只要佔據那些空的命名空間,就能讓惡意擴充跟著受信任的 pack 一起被安裝。Open VSX 有 87 個 pack、VS Code Marketplace 有 677 個 pack 被標為脆弱。手法被稱作 Extension Resurrection。主題一樣:可讀識別碼與真實身分之間的綁定,一旦能被安靜替換,信任保證就崩了。

工作室幫客戶維護套件時,流程怎麼改

台灣很多團隊不是「公開 npm 明星維護者」,但一樣會發:

  • 給客戶的私有套件(設計系統、埋點 SDK、內部 UI library);
  • 用 GitHub Packages 或 Verdaccio 之類的內部 registry;
  • 白牌專案裡「看起來像應用、其實有發布步驟」的 monorepo 子包。

這類專案最容易踩的坑是:倉庫為了整理歷史被 rename/搬 org,發布設定卻沒人改。 SlugFest 的前提正好吃這口。建議在交付檢查表加三行:

  1. 每一次 repo 搬遷,資安/維運簽核欄位要勾「trusted publisher 已重建並完成一次驗證發布」。
  2. CI 的 publish job 只允許特定 workflow 檔與特定分支;不要讓 issue_comment 之類的事件有機會觸發發布(GitHub 現在也擋了這條)。
  3. 發版通知打進 Slack/Email,異常版本號或非排程時段直接告警。

對「只消費套件」的前端專案,則把注意力放在 lockfile、Dependabot/Renovate 的自動 PR 是否需要雙人審查,以及是否啟用 npm provenance 驗證。自動化代理若被允許 npm update 後直接合併,等於把供應鏈的最後一哩交給運氣。

你可能會問

Q:我已經用 Trusted Publishing 且常常發版,還危險嗎?
A:首次成功發布後,設定會被驗證並綁向不可變身分,風險模型與「從未發布過的綁定」不同。但仍應確認 slug 仍指向你的倉庫,並在改名/轉移時重建綁定。

Q:長效 npm token 是不是比較安全?
A:不是二選一的道德審判。長效 token 外洩一樣致命。方向仍是短效 OIDC+正確的身分綁定+監控。GitHub 這次修的是綁定時機與驗證窗,不是叫大家回到把 token 貼在 CI 變數裡。

Q:工作室幫客戶維護的私有套件/內部 registry 也要管嗎?
A:要。內部套件被污染,受害的是所有微服務與前端。把「倉庫生命週期事件 → 撤銷發布信任」寫進交付檢查表。

結語

SlugFest 最刺人的一句話是:信任系統裡,可讀名稱與它指向之物的綁定往往是最重要的不變量;當這個綁定能被「改個倉庫名」這種日常操作悄悄替換,保證就失效了。GitHub 用 48 小時驗證窗把口子收小,但維護者的倉庫衛生、企業的依賴治理、以及對 AI 代理自動升級的刹车,一樣都不能省。

今晚就打開 npm 後台與 GitHub 設定頁,把 trusted publisher 列表對一次。門牌還在,不代表屋主還是你。

來源: GitHub Tightens npm Publishing After Flaw Left 1,500+ Packages Vulnerable to Hijacking(Ravie Lakshmanan,The Hacker News,2026/10/13)。

← 返回技術文章