跟漏洞攻擊程式(exploit)賽跑的 patch
2026年10月22日
十月中短短九天,PHP、GitLab、Node.js、LiteLLM、Railway、Zeabur 接連出事。仔細看,攻擊手法只有兩種:拿官方釋出的 patch 回推出漏洞攻擊程式(exploit),或是偷走一把永遠不會過期的金鑰。A40 Labs 的對策是:只要漏洞已遭利用或屬於 Critical 等級,agent-ops 在 4 小時內開出 pull request,24 小時內上 production。
廠商一發布漏洞的安全 patch,比賽就開始了。攻擊者可能幾小時內就寫好攻擊程式;Critical 的修正要跑完 Scan、Patch、Gate、Release 四站,目標是 24 小時內上線。
我在〈The Cluster You Do Not Watch〉裡介紹過我們的 SRE/Infra agent-ops,整套基礎設施基本上都歸它管。之前它只盯兩件事:cluster 健不健康、資源有沒有浪費。10 月 14 日到 22 日這九天之後,它得多盯一件事:我們跑的東西有沒有已知漏洞,有的話,修正多久能上到 production。
九天六起事件
| 誰 | 日期 | 經過 |
|---|---|---|
| Zeabur | 10 月 14–15 日 | 管理員憑證長期有效,還直接用明文存著。攻擊者讀了 3,218,965 個環境變數和 321,810 個帳號,在 865 個資料庫裡下過指令,主要目標是 AI API key。 |
| PHP | 10 月 21 日 | 兩個免驗證的遠端程式碼執行(RCE)漏洞,CVSS 9.2。8.2 到 8.5 已經修補,8.1 以前的版本不會再修。PoC 已經在網路上流傳。 |
| GitLab | 10 月 21 日 | CVSS 10.0。regex 引擎的整數溢位,在特定條件下不必登入就能執行程式碼,2014 年的 7.0 以來每一版都受影響。 |
| Node.js | 10 月 21 日 | 一次修了十個漏洞,其中四個是 High,包括一個可能導致程式碼執行的 Brotli 漏洞。 |
| LiteLLM | 10 月 21 日 | 有人在 PyPI 和 Docker 上發布了藏有惡意程式的 1.107.0 版,約 1¾ 小時後下架。惡意程式會偷雲端憑證、AI 金鑰、SSH 和 Git token,連瀏覽器存的密碼也不放過。在這之前,GitHub token 已經從內部 log 外洩。 |
| Railway | 10 月 21–22 日 | 攻擊者可能讀到客戶的環境變數,部分還是解密後的明文,包括 API key、資料庫與 registry 密碼。Railway 已撤銷全部 API token。 |
有了 AI,攻擊的效率高出許多
六起事件看下來,攻擊者用的其實只有兩招。
看 patch 寫攻擊程式。PHP、GitLab 和 Node.js 都發布了 patch。patch 本身就標出了哪幾行有問題。以前高手也得花上好幾天,才能照著 diff 寫出漏洞攻擊程式(exploit);現在丟給語言模型,沒多久就能生出初稿。「patch 出來」到「攻擊程式出來」的時間差這幾年本來就在縮短,漏洞的平均被利用時間(time-to-exploit)從 2018–19 年的 63 天降到 2023 年的 5 天(Mandiant, 2024),語言模型只會讓它縮得更快。但「patch 出來」到「patch 真正上線」的時間差完全沒縮。還是要等有人看到公告、開 ticket、排進下一次 release,企業完整修補一個列在 CISA 已知遭利用清單上的漏洞,中位數是 43 天(Verizon DBIR, 2026)。這兩個時間點之間,系統就一直暴露在風險裡(圖一)。
偷金鑰,不打伺服器。Zeabur、Railway、LiteLLM 這三起事件,都不需要什麼高明的漏洞。問題都出在金鑰、密碼這類 secret 存放太久,又放在太多程式讀得到的地方:明文的管理員憑證、環境變數、寫進 log 的 token。而且攻擊者想要的東西也變了。Zeabur 的攻擊者主要在找 AI API key,因為那能直接變現。LiteLLM 是 AI gateway,整個 stack 裡只有它握有所有模型供應商的金鑰,在它身上下毒,就能一次拿到全部。
第一招要靠速度擋。第二招要擋,就得讓手上沒有任何值得偷、又能長期使用的東西。
我們的對策
CVE 迴圈沿用 agent-ops 一貫的做法:agent 負責讀,唯一會寫出來的是 pull request,最後由 CI 把關(圖二)。
- Scan。一支每小時執行的程式會讀取 CISA 的 Known Exploited Vulnerabilities 清單,以及 GitHub、OSV 的安全公告 feed,再把每則新公告拿來比對我們最近一次記錄的部署清單。只要比對到 Critical 或已遭利用的漏洞,一小時內就會觸發 patch 步驟。每天還會再完整掃過一次所有 lockfile、image digest 和鎖定版本的 chart。
govulncheck會分析 Go 的 call graph,如果漏洞落在我們從沒呼叫過的函式,嚴重度就降一級,不會直接發出告警。 - Patch。每個 repo 都在自己的 CI runner 上跑一個 agent。agent 用該生態系原生的工具升級套件、執行 repo 既有的檢查,每個 finding 各開一個經過簽章的 pull request。它可以改 manifest、lockfile 和 Dockerfile,但不能動應用程式碼或 workflow;需要改程式碼才能修的,就停下來交給人處理。
- Gate。只部署到 staging 的 repo,同一 major 版本內的升級只要 CI 綠燈就會自動 merge。跨 major 的升級、chart,以及任何 Terraform 的變更,一律等人審核。
- Release。production 的把關方式不變:production pin 仍然由人 merge。不同的是,現在每個嚴重度都有期限:Critical 會 page 負責人,並單獨發一次 release;如果還沒有 patch,4 小時內要先上緩解措施,例如加一條封鎖規則,或先關掉某個功能。
| 嚴重度 | 開 PR | merge | 上 production |
|---|---|---|---|
| Critical(CVSS ≥ 9,或已遭利用) | 4 小時 | 12 小時,上 staging | 24 小時 |
| High(7.0–8.9) | 48 小時 | 7 天 | 14 天 |
| Medium | 7 天 | 30 天 | 下一次 release |
| Low | 每月一批 | 當月 | 下一次 release |
至於第二招,重點是別讓金鑰外洩。push protection 會在 GitHub 端攔下含有憑證的 commit,就算有人從筆電跳過 hook 直接 push,也進不了 repo;gitleaks 也會再檢查每一個 pull request。掃描器本身也不在硬碟上放長效金鑰:它以兩個 GitHub App 的身分登入,一個只能讀程式碼,另一個只能回寫掃描結果,兩者的私鑰都放在 secret 管理系統裡;讀 registry 時則透過 workload identity federation 取得短效 token,根本沒有雲端金鑰可以偷。掃到的 secret 不會出現在報告、pull request 或 Slack 裡;執行 log 只記它在哪個檔案、哪一行,不記內容,再由負責人輪替。
同一個模型,也能站在我們這邊
攻擊者既然會用模型讀我們的程式碼,我們就要比他們先讀(圖三)。所以我們採用了 Strix,一套開源的 AI 滲透測試工具,由我們自己 host。它除了讀程式碼,也能對執行中的服務實際發動攻擊。一個跟我們 backend 差不多大的 repo,Strix 大約 25 分鐘就能讀完。找到的問題有兩種:一種是已知的 CVE,一般的掃描器也抓得到;另一種是我們自己寫出來的存取控制 bug,任何 CVE 掃描器都看不到。我們用 Strix,就是為了後面這一種。
能改變的是什麼
GitLab 那個不用登入就能執行程式碼的漏洞,從 2014 年的 7.0 版就在了,直到這個月才修補。漏洞會不會出現在程式碼裡,CVE 迴圈管不了;它管的是 patch 發布之後,我們還要帶著有漏洞的版本跑多久。對 Critical 漏洞,我們的目標是 24 小時;業界的中位數是 43 天。