如果你維護 Laravel 應用程式,看完這一段就停下來:去檢查你的 composer.lock 是否在 2026 年 5 月 22 日 當天或之後,對 laravel-lang/lang、laravel-lang/attributes、laravel-lang/http-statuses、laravel-lang/actions 這四個套件重新解析過。如果有,當你的 CI 環境已經外洩,立刻輪替 CI runner 看得到的每一把祕鑰,並稽核 22 號以後從 runner 出去的外連線。下面解釋為什麼。
5/22 那天的一個約 15 分鐘的時間窗裡,一位拿到 Laravel-Lang 這個 GitHub 組織 push 權限的攻擊者,把橫跨四個高使用率 Composer 套件的「所有現存 git tag」改寫到一個新的、會把任何拉它的人後門化的 commit。超過 700 個版本 被改寫指向。這四個套件是翻譯/locale 輔助套件,大約跑在一半的線上 Laravel 應用裡,也是幾十個 starter kit 與 CMS template 的次相依。你只要曾經跑過 composer require laravel-lang/lang,你就在爆炸半徑內。
一、Composer 原本沒有設計來防的攻擊
多數供應鏈攻擊的做法是發一個「看起來人畜無害」的新版本,賭使用者會升級。Composer 預設能擋一大半:釘住版本、用 composer.lock 鎖、Packagist 對於異常的新版本會用簽名與 tag heuristics 警示。
這次攻擊沒有發新版本。它 改寫了已經存在的版本的歷史。v1.0.0、v6.4.3、你過去裝過的每一個 v..*——全部被改寫成指向一個惡意 commit,而不是原本良性的那個。結果是:你的 composer.json 寫 "laravel-lang/lang": "^14.0"、你的 composer.lock 寫「就是這個 tag」——兩個都救不了你。重新 fetch 的時候,兩個都會解析到被改寫的 tag,拿到惡意 blob。
更糟:惡意 commit 把 src/helpers.php 加進 Composer autoload.files map。意思是 payload 在 autoload 階段 就執行——每一個 web request 的第一行、每一個 artisan 指令、每一個 queued job。沒有「易受攻擊的呼叫」可以 grep。光啟動框架就會執行 malware。
payload 本身會聯絡一個 typosquat 的 C2 網域(flipboxstudio.info)、把一個 PHP loader 跟一個 ELF binary 丟到 /tmp、把 process 看得到的環境變數外洩。在 CI/CD runner 上意思是 runner 能存取的每一把祕鑰:AWS keys、GitHub Actions GITHUB_TOKEN、deploy SSH keys、資料庫密碼、Stripe live keys、Mailgun keys。然後它把磁碟上的 artifact 自我刪除,繼續在記憶體裡跑。
二、為什麼這類攻擊在策略上很關鍵
這是業界 60 天內看到的第 二 次大規模「tag 改寫」式供應鏈攻擊(5 月稍早 Python poetry 生態系也發生過類似一次)。2026 年到目前為止,這已經是第三或第四次「憑證外洩→供應鏈轉向」事件——同一類別的還有 5/16 Grafana 原始碼竊取、5/22 Panasonic Avionics 外洩,兩起的起點都是被偷的 GitHub token。
模式已經確立。攻擊者拿到開發者憑證(被釣魚的維護者、外洩的 PAT、留在公開 commit 裡的 token),然後拿來武器化的是「組織的 git 歷史」,而不是 push 一個一眼能辨認的惡意版本。這會擊穿任何假設「版本不可變」的供應鏈防線。
策略上,這代表三件事現在是任何拉 open-source 相依的團隊的「基本配備」:
第一,對任何維護者曾經顯示憑證 hygiene 問題的套件(任何單一維護者撐起的熱門套件都符合),用 commit SHA 而不是 tag 釘住。Composer 用 #sha 語法支援這件事——成本是 composer.json 多一行、升級流程多想一下。好處是 tag 改寫影響不到你。
第二,監控 GitHub Repos API 上你關鍵相依套件的 tag 形狀變化。一個免費 GitHub Action 或一支 30 行的腳本就能在某個 tag 的 SHA 改變的時候通知你——正常運作下這件事不該發生。一旦發生,你有大約 15 分鐘的警報窗,趕在新 tag 散播到 Packagist CDN 之前。
第三,狠狠收緊 CI token 的權限範圍。任何供應鏈攻擊的爆炸半徑等於 build runner 看得到的祕鑰。「一把 deploy token 同時能存取 staging、production、AWS」這種方便,正是這類攻擊變現的對象。每個環境、每個階段一把 token,照排程輪替。
三、Composer / Laravel 專屬、這個 sprint 該出貨的硬化
除了上面那些普遍課題,四個 Composer/Laravel 專屬步驟值得這個 sprint 做掉。
用 composer.lock 釘住,並在 CI 跑 composer install --no-scripts。 --no-scripts 旗標會阻止 autoload 階段的 payload 在 install 階段本身觸發,如果你的稽核在 deploy 前抓到問題,這層多買到一點時間。(production runtime 是另一回事——下面說。)
部署時改用 composer install --prefer-lock --no-dev 並把解析出來的 hash 跟你 5/22 之前抓的 snapshot 比對。任何不一致都暗示下游被改寫過。
在 CI 啟用 Composer 的 audit 指令(composer audit --abandoned=report),並把高於指定嚴重度的告警設成擋 PR。Laravel-Lang 的 advisory 已經發布到 FriendsOfPHP/security-advisories 資料庫,任何跑 composer audit 的團隊都會看到。
把關鍵相依鏡像到你自己的 Composer repository(Toran、Satis、或私有 Packagist 都可以)。鏡像給你一份「篡改可見」的快照——如果上游 tag 被改寫,你的鏡像還握著舊 SHA,diff 會很大聲。
四、若你已中招,具體的補救步驟
如果你的 composer.lock 在 5/22 後對那四個套件中任一個重新解析過——當作已外洩處理。動作順序:
第一步:輪替 CI runner 能存取的每一份憑證,從任何 production 範圍開始。AWS access keys、deploy keys、GitHub PATs、Mailgun、Stripe live keys、S3 keys、CI 看得到的資料庫密碼。別跳過「我們已經沒在用那把」——攻擊者不認得你的意圖。
第二步:作廢 runner 看得到的每一個 JWT signing secret 與每一個 API token。強制重簽。是的,使用者要重新登入。這是對的結果。
第三步:檢視 5/22 以後從 CI runner 出去的網路 log。任何到 flipboxstudio.info 或不熟悉 IP 的連線都是冒煙的槍。在網路 egress filter 把那些網域擋掉。
第四步:把那四個套件釘到已知安全的 SHA。Laravel-Lang 維護者已經在 GitHub issue(Laravel-Lang/lang #8295)上公布每個 tag 最後已知良性 commit 的 SHA。用 Composer #sha 語法釘那些 SHA、推上去、跑一次乾淨的 composer install、檢查 autoload map 不再引用 src/helpers.php。
第五步:如果你的應用程式有自家能寫的翻譯字串,乾脆把套件移除。Laravel 從框架第一版就支援原生翻譯檔;laravel-lang 套件是方便,不是必要。
五、更大的模式與生態系的代價
Composer 生態系是建立在「對維護者的信任」之上。這四個套件的維護者在傳統意義上沒有做錯什麼——他們只是有一把被打穿的憑證。那一次外洩在 15 分鐘的窗內傳染到七位數個下游應用。所有應用加起來的補救成本是一個真實數字、以工程師小時計,整個生態系現在每隔幾個月就要吃一次。
中期解法比任何單一團隊的硬化都難。它是 sigstore 風格的維護者 tag 簽章,加上 Composer resolver 端強制驗證。PHP/Composer 在這件事上落後 npm 與 PyPI 生態系。追上的壓力現在看得到了。
短期內,每個 Laravel 團隊的功課是上面那四個硬化步驟。工作量半天。不做的代價——當這類攻擊命中你 runner 看得到的一把憑證的時候——是好幾週的事件回應、客戶通知、可能的法遵揭露,以及跟你的保險公司重新對話一次。我們已經看到這個禮拜大概四百家公司活生生跑了一遍。算式不接近。
我的觀點
我們吵了很多年「供應鏈是現代 web stack 最弱的一環」。Laravel-Lang 這次攻擊是最乾淨的證明:論述結束,防禦現在是你的責任。你不能等 Composer resolver 長出 tag 驗證。你不能等 GitHub 出貨強制「tag immutable」模式。你必須這個 sprint 就把自家 pipeline 硬化,用上面那些步驟。
我們的代理客戶這禮拜在跑一個一天的 Composer 鎖死 sprint:把關鍵相依用 SHA 釘住、鏡像到私有 repo、在 CI 啟用 composer audit、CI token 依環境拆。成本是每專案半個工程師日。不做的代價是這個禮拜上百家公司活生生經歷的那個事件。算式不接近。
更深的一課是我們每幾個月就要重學的那個:一把流出去邊界外的憑證,等於邊界已經在攻擊者體內。Token hygiene 不無聊——它是 2026 年 Laravel 團隊能做的、單位成本最高槓桿的安全工作。花那半天。釘 SHA。輪替祕鑰。往下一件事走。
資料來源
- Laravel-Lang PHP Packages Compromised to Deliver Cross-Platform Credential Stealer — The Hacker News
- Laravel-Lang Supply Chain Attack: Every Tag Across Multiple Composer Packages Rewritten to Steal CI Secrets — StepSecurity
- Security: All repository tags have been rewritten to point to malicious commits — Laravel-Lang/lang Issue #8295
- Laravel-Lang Composer tag-rewrite Supply Chain Attack — Security Boulevard
- Laravel Lang Compromised with RCE Backdoor Across 700+ Versions — Socket
- Laravel-Lang Composer Tag-Rewrite Supply-Chain Attack — Mend.io