資訊安全

CVE-2026-45793:PHP 生態圈剛剛驚險閃過 14 小時的供應鏈大爆炸——你的 Composer 版本對了嗎?

2026.05.18 · 34 次瀏覽
CVE-2026-45793:PHP 生態圈剛剛驚險閃過 14 小時的供應鏈大爆炸——你的 Composer 版本對了嗎?

Composer 一個 2021 年寫下的 token 驗證 regex,差點讓整個 PHP 世界的 GITHUB_TOKEN 在 CI log 裡明文外流

5 月 12 日 22:00(UTC),GitHub 悄悄推出了一個新的 `GITHUB_TOKEN` 結構化格式,token 字串中加入了連字號 `-` 作為分隔符。對 GitHub 來說這是個常規改版。對 PHP 生態圈來說,這個改動觸發了一顆埋了五年、所有人都不知道的地雷——Composer 在 2021 年寫下的 token 驗證 regex 不接受 `-`。當驗證失敗時,Composer 會把 token 完整內容 print 到 stderr。在 GitHub Actions 環境裡,stderr 預設會被寫進公開的 build log。


接下來 14 個小時內,任何 PHP 專案,只要 CI 用 `composer install`、`composer update`、或任何會打 GitHub API 的 Composer 子命令,build log 裡就會出現一段明文的 `GITHUB_TOKEN`。如果你的 workflow 被觸發於 `push`、`pull_request_target`、或 `schedule`,這段 log 在公開 repo 是任何人都能讀的。


這個漏洞被指派為 CVE-2026-45793,CVSS 7.5。


一、為什麼這 14 小時差點變成 PHP 史上最大供應鏈事故


`GITHUB_TOKEN` 是 GitHub Actions 預設注入到 workflow 的權杖,預設權限通常包含 `contents: write`、`pull-requests: write` 等。對攻擊者來說,拿到一支有 write 權限的 token 意味著:


  • 可以對 repo push 新的 commit、新的 tag。
  • 可以發布新的 release。
  • 對於 Packagist 已連結 GitHub release 的套件,可以直接污染下一版的 release 內容。

如果攻擊者在這 14 小時內監聽熱門 PHP 專案的 build log(這在公開 repo 是合法可做的),蒐集到的 token 數量可能是萬等級。把惡意 commit 推到任何一個被廣泛依賴的套件(例如 monolog、guzzle、symfony 子套件),不需要 phishing、不需要社交工程,就能直接污染下游所有 `composer install` 的開發者與生產主機。


GitHub 在 5 月 13 日 14:30 UTC 暫時回滾了 token 格式變更。Composer 也在同一波修補了 2.9.8、2.2.28、1.10.28 三條 LTS 線。但這個 token 格式之後還會再次推出——這次只是給 PHP 生態圈幾天時間把 Composer 升上去。


二、立刻可以做的 5 件事


不要等下一次 GitHub 推格式時才忙著補。現在就:


  1. 升級 Composer:CI 鎖到 `composer self-update 2.9.8` 或以上。Dockerfile 裡 `composer:2` 標籤要明確改成 `composer:2.9.8`。
  2. 撤銷可能外洩的 token:到 GitHub Settings → Developer settings → Personal access tokens → 撤銷 5 月 12-13 號之間用於 PHP 專案 CI 的所有 PAT。
  3. 檢查 Actions log:對任何 5 月 12-13 號的 build,grep `gho_` 或 `ghs_` 或 `ghp_` 開頭的字串,找到的全部當作已外洩處理。
  4. 刪除公開 build log:對任何曾命中的 build,到 Actions UI 把整個 workflow run 刪掉。注意:log 即使刪除,攻擊者已經抓走的副本是回收不來的。
  5. 加上一道防線:在 GitHub Actions workflow 加上 `permissions:` 區塊,把 `GITHUB_TOKEN` 預設降到 `read-all`,需要 write 的 job 個別申請。這是即使下次再外洩也能止血的根本辦法。

三、給 Laravel / Symfony 團隊的額外檢查項


  • 私有套件 repo(Satis / Private Packagist / GitHub Packages):檢查授權 token 是否有外洩;如有,整批 rotate。
  • Composer scripts 中的 `post-install-cmd`:別在這裡 echo 任何 token 或環境變數做 debug,這類 print 也會進 build log。
  • Laravel Envoyer / Forge 部署 hook:如果部署流程從 GitHub Actions 觸發,檢查中繼變數是否被 log。
  • Symfony Flex recipes:upstream 沒被污染,但養成 `composer audit` 進 CI 的習慣。

四、為什麼這個事件值得寫進你的安全 SOP


這件事最可怕的地方是:沒人做錯事。GitHub 推一個更安全的 token 格式是好事。Composer 寫一個嚴格的 token 驗證是好事。把驗證失敗的細節 print 出來方便 debug 也是好事。三件「正確的事情」湊在一起,變成一個 14 小時的全球供應鏈窗口。


這是 supply chain attack 在 2026 年的新形態——攻擊面不在你的程式碼裡,而在你依賴的工具、依賴的平台、依賴的 default 設定相互作用的縫隙裡。


我的觀點


身為 PHP / Laravel 接案開發者,三件事必須馬上做:


第一,把「Composer 版本」加進你給每位客戶的 SRE 月度檢查表。過去這是 nice-to-have,現在這是合約等級的責任。


第二,所有客戶專案的 GitHub Actions workflow,今天就加 `permissions:` 預設 read-only。寫一份遷移 commit 模板,半小時可以處理 20 個 repo。


第三,學會跟客戶解釋這類「沒人做錯事但全世界差點爆炸」的事件。客戶往往認為「我們沒被駭就沒事」,你要讓他們明白「這次是運氣好,不是制度好」。能講清楚這條的接案夥伴,才有資格把單價往上提。


資料來源