今天看到昨天的新聞:LiteLLM 被攻擊了。想說來了解一下這個工具到底是什麼,結果一查才發現,這不只是一個套件出事,而是一整條供應鏈被打穿。同時間,年齡驗證法案正在逼 Linux 做一件技術上根本不可能強制執行的事。兩件事湊在一起看,挺有意思的。
一個安全掃描工具,變成了攻擊入口
LiteLLM 是一個統一多家 LLM API 介面的 Python 代理,月下載量大約 9,500 萬次。3 月 24 日,v1.82.7 和 v1.82.8 被發現植入了竊取憑證的惡意程式碼。
但攻擊不是從 LiteLLM 開始的。攻擊者 TeamPCP 先打的是 Aqua Security 的 Trivy——一個開放原始碼漏洞掃描工具,很多專案在 CI/CD 裡用它做安全檢查。諷刺的是,安全工具本身成了攻擊入口。
手法是這樣的:Trivy 的 GitHub Actions 有設定漏洞,攻擊者取得了 push 權限後,把 trivy-action 的 76/77 個 version tag 全部 force-push 到惡意 commit。所有在 workflow 裡寫 uses: aquasecurity/trivy-action@v0.xx.x 的專案,下次 CI 跑起來就自動執行惡意程式碼,而掃描結果看起來完全正常。
接著,惡意程式從 CI runner 的 process memory 裡提取 GitHub PAT 和其他 secrets,再用偷來的憑證感染更多 Action(包括 Checkmarx 的 AST Action),形成連鎖擴散。最後用偷到的 LiteLLM PyPI 發布金鑰,推送含後門的版本。
整條鏈:Trivy Action 被竄改 → CI secrets 被偷 → 更多 Action 感染 + PyPI token 外洩 → 惡意 LiteLLM 發布到全世界。
GitHub Actions 的信任模型有根本問題
這次攻擊能成功,核心原因是 GitHub Actions 的架構設計:所有 step 跑在同一個 runner 上,共享 OS 層級的所有權限。你 uses: 引用的第三方 Action,跟你自己寫的 step 享有完全相同的存取權——檔案系統、環境變數、process memory、網路,全部。
而且大部分人用 version tag 來引用 Action,不是用 commit SHA。Git tag 本質上是可變的,有 push 權限就能把現有 tag 指向不同的 commit,GitHub 上不會有任何可見變化。
更有趣的是 PAT 的問題。GitHub 的 PAT 在網頁上只顯示一次,很多人以為這代表 token 本身是安全的。但你把 PAT 存進 repo secret 後,CI 執行時它就是明文載入到 Runner.Worker 的 process memory 裡。GitHub 的保護是 log 裡遮罩成 ***,但記憶體裡就是原始值——同一台機器上有執行權限的程式碼都讀得到。
甚至不需要讀 memory 那麼費工。如果你有 workflow 的控制權,直接 echo "${{ secrets.MY_PAT }}" | base64 就能在 log 裡拿到。所以「只顯示一次」保護的是 UI 層級的窺視,不是真正的安全邊界。
CI runner 裡讀取其他 process 的記憶體完全不合理,這種操作應該從架構上被隔離——每個 Action 跑在自己的 sandbox 裡,只給最小權限。概念上就像 Deno 的權限模型。但 GitHub 一直沒做,大概是相容性和效能的考量。希望這次事件的規模能推動改變。
年齡驗證:拿科技方案解決社會問題
同一時間,另一個戰線也在開打。加州法律要求 2027 年起,作業系統開發者必須在使用者存取 app store 或下載應用時傳送年齡訊號。Colorado、Illinois、New York 也有類似立法。
對 Apple 和 Microsoft 來說問題不大,他們有帳號生態系、有硬體綁定、有封閉的 bootloader。但 Linux 從來沒有中央化的使用者註冊機制,甚至不是每個 distro 都有帳號系統。
systemd 最近 merge 了一個 optional 的 birthDate 欄位到 userdb,馬上就有人 fork 出去把它拔掉。這個欄位存在本機的 JSON user record 裡,雖然號稱需要 root 才能改——但用 Linux 的人誰沒有 root?
所以整個機制是:你在自己的電腦上,自己告訴自己的電腦你幾歲,然後電腦再告訴 app 你幾歲。這是自我聲明,不是驗證。
立法者大概不理解開放原始碼和商業軟體在架構上的根本差異。在他們眼裡「作業系統」就是 Windows 和 macOS,Linux 只是被掃到的。438 位來自 32 國的安全與隱私學者已經聯名呼籲暫停部署,在科學共識確立前不要急著推。
Discord 已經示範了會怎樣
如果你覺得年齡驗證只是「沒用但無害」,看看 Discord。
去年十月,Discord 用的第三方年齡驗證廠商被駭,七萬名使用者的政府證件照片外洩。今年二月他們宣布全球推行年齡驗證,社群立刻炸鍋,被迫延後到 2026 下半年。
為了「保護兒童」而收集的身份資料,本身成了攻擊目標。保護措施製造了新的風險。Discord 作為一間有資源的公司都搞成這樣了,你要志願者維護的 Linux distro 做得更好?
兩件事疊在一起,攻擊面直接放大
這才是我覺得最關鍵的點。
現在供應鏈攻擊偷的是 API key、SSH key、雲端憑證,洩漏了你輪換就好。Token 換一組,損害可控。
但年齡驗證一旦進入系統,不管是生日、證件、還是臉部辨識資料,這些是不可輪換的。你的生日不能換、你的臉不能換、你的身分證號碼換一次的成本極高。一旦洩漏就是永久性的損害。
TeamPCP 這次的手法是從 CI/CD 一路打到終端使用者。如果使用者的系統裡剛好存了年齡驗證的身份資料,惡意程式碼就連這些一起撈走。本來只是偷開發者的 credentials,現在變成偷所有使用者的生物辨識和身份資訊。
年齡驗證不只是「沒用」,它主動擴大了攻擊面,把原本不存在於系統裡的高價值個資硬塞進來,等著被偷。
結論:方向搞反了
開放原始碼的信任模型正在被兩面夾擊。供應鏈攻擊是真實的技術威脅,但解法是技術性的——pin commit SHA、sandbox 隔離、更嚴格的發布流程。這些改進社群自己能做。
年齡驗證是政治性的威脅,但問題根本不存在於開放原始碼的層級。結果是逼開放原始碼去實作一個技術上無法強制執行、實作了也沒意義、還會擴大攻擊面的機制。
真正該擔心的方向,立法者搞反了。供應鏈攻擊才是會實際傷害使用者的問題,沒有人在推動 CI/CD 安全標準。年齡驗證不會保護任何人,反而製造新的風險,立法者卻拼命推。
開放原始碼不會消亡。但如果不懂技術的人繼續用法規去改變它的本質,受傷的是所有人。