有人把整包 150MB 的 Copilot CLI 塞進 ports tree,FreeBSD 全體凍結近一天
OSnews / FreeBSD Announce Mailing List · 2026-07-22
背景:一個本該用下載的檔案,卻被直接 commit 進版本控制
FreeBSD 的 ports tree 收錄的是「如何取得與建置某個軟體」的 port 描述檔,像 misc/github-copilot-cli 這類條目正常只會存 Makefile、distinfo 與 patch,真正的執行檔在使用者安裝時才會即時下載。但 2026 年 7 月下旬有人在替 GitHub Copilot CLI 更新 port 時,誤把完整的 Linux 版執行檔一起 commit 了進去,而這個 binary 本身就有 150MB 之譜。ports tree 的 Git 歷史原本理應維持輕量,這一下等於把一個不屬於版本控制的二進位檔案永久燒進了歷史紀錄。
發生什麼事:超過 GitHub 100MB 限制,鏡像斷線
FreeBSD 的官方版本庫獨立托管,但同時鏡像到 GitHub 供外界瀏覽與 clone。GitHub 對單一檔案有 100MB 的硬性限制,這個 150MB 的 Copilot binary 一送進去,鏡像同步立刻中斷。核心團隊成員 Kyle Evans 代表 core@ 在 2026 年 7 月 22 日於 freebsd-announce 郵件論壇發出公告,宣布對整個 ports repository 實施近 24 小時的凍結。公告中還提到另一層問題:這個 Copilot CLI 屬於 GitHub 的專有授權,把它的二進位檔案原封不動收進開源 ports tree,等於在歷史紀錄裡埋了一段「授權存疑的 blob」。
處理與後續:改寫歷史、加 server-side hook
核心團隊在公告中列出幾項具體動作:移除有問題的 commit 以恢復外部鏡像服務、準備讓既有 checkout 同步修正歷史的操作指引、提供驗證程序讓社群確認自己本地端的異動範圍是否正確,以及在伺服器端加上 hook 防止同類事故再次發生。
- 移除肇事 commit,重建 GitHub 鏡像同步
- 發布 checkout 端的歷史同步 / rebase 指引
- 提供 diff 範圍驗證程序,方便社群自查
- 加裝 server-side hook,擋下超大檔案與可疑授權內容
公告特別強調「沒有任何跡象顯示 ports tree 遭到入侵」,凍結純粹是為了在改寫歷史前盡量減少累積的新 commit 數量,降低清理時的衝突範圍。整起事件從頭到尾就是一次單純的誤操作,但也讓外界重新注意到「把二進位檔案 commit 進原始碼倉庫」在分散式版本控制下代價有多高——歷史一旦推上遠端,要乾淨移除遠比想像中麻煩。
編譯器懸案:一個 merge 讓 Ferrocene 陷入無限迴圈,查了三層才抓到兇手
Ferrous Systems Blog · 2026-07-09
背景:rustc 的 query 系統與什麼是「cycle」
rustc 內部並非一路從頭編到尾,而是用一套 demand-driven 的 query 系統做記憶化計算:每個 query 由「名稱 + 參數」的 tuple 識別,一個 query 執行時可以呼叫另一個 query,結果會被快取起來。如果同一個 query、同一組參數在呼叫堆疊裡被要求了第二次,就形成所謂的 query cycle——這在正常情況下代表編譯器本身有 bug,因為理論上不該出現真正的循環依賴。Ferrous Systems 團隊在把上游 Ferrocene 分支合併進來後,發現用到 unstable 的 fn_delegation 特性編譯某段程式碼時,編譯器會直接掛住,沒有任何錯誤訊息。
發生什麼事:測試 20 分鐘沒輸出,devpod 被 OOM 殺掉
CI 上的測試在 20 分鐘後逾時、沒有任何輸出;本機重現時,devpod 直接被系統判定 OOMKilled。作者用 GDB 送 SIGINT中斷後擷取堆疊,發現堆疊深度超過百萬層——這是 ensure_sufficient_stack 把堆疊複製到 heap 上暴衝的結果。團隊接著加上除錯追蹤,逐層記錄巢狀 query 的執行順序,才把循環的起點鎖定在 codegen attribute 檢查那條路徑上,也就是 find_and_handle_cycle 反覆被同組參數叫起的地方。
真相:三個 bug 疊在一起才會發作
最後拼出的成因有三層:Ferrocene 專屬程式碼裡的 item_is_validated 在處理 codegen attribute 時,無條件呼叫了某些 query,這在上游原版 rustc 根本不會走到;query 系統裡的 default_span 函式在處理錯誤時又去呼叫 def_span,結果在「回報錯誤」的過程中又生出一層新的 cycle,而系統對這種巢狀 cycle 沒有妥善的收斂機制;ensure_sufficient_stack 本身又缺乏上限保護,才會放任堆疊一路灌爆記憶體而不是乾淨地失敗。而觸發這一切的源頭,是 fn_delegation 引入的「delayed HIR owners」打破了「呼叫 hir_crate_items 的 query 一定安全」這條長年成立的假設。
修復:三個上游 PR 各自補一塊
問題最終回饋上游,由三個 rust-lang/rust 的 PR 分頭處理:#154387 改善 query 系統自身處理 cycle 的方式,替 ensure_sufficient_stack 加上過量遞迴的偵測與更清楚的錯誤回報;#154389 讓巢狀 query cycle 的處理更穩健;#154368 則直接修掉 delegation 延遲降階(delayed lowering)過程中會產生 cycle 的路徑。三個 PR 合起來才讓這個「看似無限迴圈、實際上是三個假設同時失效」的懸案落幕。
find_and_handle_cycle
└─ item_is_validated (Ferrocene-only)
└─ default_span → def_span (nested cycle)
└─ ensure_sufficient_stack (no upper bound)
→ stack copied to heap, OOMKilled拆解監視器韌體,意外從登入頁挖出一組能管全公司 repo 的 GitHub token
hhh.hn(研究者部落格)· 2026-07-24
背景:從官網韌體檔開始的逆向工程
一位資安研究者從 Hanwha Vision(韓華視覺)官網下載了旗下監視器(含 XNP-9300RW 等型號)的韌體檔案,先用「HTW + 型號」組成的已知密語破解外層加密,再用 Claude Code 輔助逆向 fwupgrader 這支工具,一路剝到最內層被加密的 rootfs。目標原本只是想看看攝影機的登入頁前端是怎麼寫的,結果在解開的檔案系統裡意外挖到不該出現的東西。
發生什麼事:Vite build 把整包 CI 環境變數烤進了前端
研究者發現,攝影機管理介面的前端是用 Vite 建置的,而建置流程直接用 process.env 把整個 CI 環境的變數塞進了打包產物——其中包含一個名為 GITHUB_NPM_TOKEN 的變數,內容是一組 ghp_ 開頭的 GitHub 個人存取權杖(Personal Access Token)。這組 token 前後在大約 30 個檔案裡重複出現,而且對 Hanwha 的 GitHub 組織擁有數百個 repository 的管理員(admin)層級存取權限。
- 對 Hanwha GitHub 組織下數百個 repository 的 admin 存取權
- 理論上可推送任意程式碼或竄改韌體建置腳本
- 可讀取原本不公開的專有原始碼
- 環境變數中還夾帶了看似隸屬美國國防部(DoD)配發的 IP 位址,暗示 CI 基礎設施可能與國防相關子公司共用
換句話說,一個原本只該讓瀏覽器顯示登入畫面的靜態前端,卻連著建置環境裡最敏感的一組憑證一起被打包發佈到終端使用者手上的攝影機裡。
後續:12 小時內回應並撤銷
研究者透過 Hanwha 官方的資安聯絡信箱通報後,對方在 12 小時內回覆並確認已撤銷該 token。整起事件的根因並非攻擊或資料外洩,而是常見的 CI 設定失誤:建置工具在沒有明確篩選的情況下,把整個環境變數表都暴露進了公開產物,而 GitHub Copilot CLI 事件同一週發生的這起案例,再次說明「不小心把不該進版本控制 / 不該進 build output 的東西塞進去」是條反覆出現的老問題。
原始來源:hhh.hn 原文