AI 的供應鏈攻擊:為什麼套件裡藏惡意碼
第二,AI 專案普遍存在「先跑起來再說」的文化。 資料科學家與研究人員的目標是驗證想法,不是維運一套高安全標準的系統。於是隨手 pip install、直接 torch.load() 一個從網路下載的權重檔,變成十分常見的日常操作。安全審查在「趕實驗」的壓力下往往被跳過。
第三,模型權重是一種「看起來不像程式碼的程式碼」。 大多數人對 .exe 或 .sh 會有警覺心,但對一個 .bin 或 .pt 模型檔不會。偏偏某些格式在載入時就是會執行程式碼,這一點後面會細談。
第四,AI 應用需要權限才能發揮價值。 一個 Agent 要能讀檔案、要能呼叫 API、要能查資料庫,才有實用性。當工具鏈越完整,它被攻擊後能造成的破壞也越大。從「讀取一個檔案」到「替你發送郵件、修改雲端資源」,這中間的距離比你想像的近。
第五,開發流程本身開始被 AI 介入。 當 Copilot、Cursor、Claude Code 這些工具幫你補完 import 語句時,它們也在替你決定「要信任哪個套件」。這是一個全新的攻擊面,後面會專門討論。
二、套件裡的惡意碼:六種最常見的藏匿手法
接下來這一段,我們把「惡意程式碼如何進入你的專案」拆成六種典型手法。理解手法比記住案例更重要,因為案例會過時,手法不會。
手法一:名稱近似與搶註(Typosquatting)
最古老、成本最低、效果卻意外好的一種。攻擊者註冊與熱門套件只差一兩個字母的名稱,例如 request 與 reqeust、urllib3 與 urllib,或者加上 -py、-python、-official 等後綴。開發者手速一快、IDE 自動補完一按,就裝錯了。
這類套件通常在安裝時就會執行惡意行為:讀取環境變數、掃描本機的 SSH 金鑰與雲端憑證、對外連線回傳,甚至自動在受害者的私有儲存庫裡開 PR,擴大感染範圍。因為安裝腳本(例如 Python 的 setup.py、npm 的 postinstall)預設會被執行,開發者往往完全不會察覺。
近年的變體更精緻:攻擊者會複製原套件的 README、版本號、甚至部分原始碼,讓套件頁面看起來一模一樣。只看名稱與外觀,幾乎看不出異常;唯一能分辨的方式,是去看它做了什麼。
手法二:依賴混淆(Dependency Confusion)
這種手法專門針對企業內部。許多公司會把自家開發的套件放在私有套件庫,並沿用公司內部的命名慣例(例如 company-utils、internal-auth)。攻擊者只要在公開的 PyPI 或 npm 上,用同樣的名稱發布一個版本號更高的套件,套件管理器在解析依賴時,就可能優先抓到公開版本。
結果是:開發者以為自己裝的是公司內部工具,實際上裝的是攻擊者準備好的版本。這個手法最陰險的地方在於,它不需要開發者打錯字,也不需要任何社交工程,只要套件管理器的解析順序對攻擊者有利,就會自動發生。
防禦的重點在於「作用域(scope)」與「來源鎖定」。npm 的 @company/ scope、私有 registry 的優先順序設定、以及 lockfile 中記錄的來源雜湊,都是必要的防線。
手法三:模型權重與 pickle 反序列化
這是 AI 供應鏈最獨特、也最容易被忽略的一塊。
Python 的 pickle 模組可以把物件序列化成位元組流,也可以把位元組流還原成物件。問題在於,還原的過程中允許執行任意程式碼。也就是說,載入一個 pickle 檔案,等同於執行一支程式。而 PyTorch 的 torch.load() 預設就走 pickle 路徑。
於是就出現了這樣的場景:你從模型社群下載了一個「效果很好」的模型,執行 torch.load("model.pt"),此時你的機器就已經在跑攻擊者寫的程式碼了。它可以在訓練環境裡植入後門、可以竊取你的資料集、可以在推論時回傳被操控的結果,甚至可以在你的伺服器上開一個反向 shell。
這類攻擊之所以可怕,是因為模型檔通常很大、無法人工審閱,而且下載模型的人往往不具備資安背景。你不可能像 review 程式碼那樣 review 一個 3GB 的權重檔。
目前相對安全的作法是改用 safetensors 這類純資料格式。它只儲存張量,不涉及程式碼執行,從根本上消除了反序列化風險。若真的必須使用 pickle,至少要在隔離的沙箱環境中載入,並限制網路與檔案系統存取。
手法四:模型替身與「同名不同源」
模型社群平台上的另一種攻擊:攻擊者建立一個與知名模型幾乎同名的儲存庫,複製原始模型的說明文件與設定檔,替換掉權重。開發者透過搜尋、透過他人分享的連結、或透過 AI 工具推薦而下載,很難即時察覺。
這類替身模型可能被植入觸發詞(trigger),在正常輸入下表現得與原模型無異,但當輸入包含特定字串時,就會輸出攻擊者指定的內容。對於企業內部的問答系統、客服機器人、或是自動化決策系統,這種後門極難被傳統測試發現。
更進一步的變體,是在模型的設定檔(config)或自訂程式碼(custom code)中夾帶惡意邏輯。有些平台允許模型附帶推論程式碼,載入模型時會一併執行。這等於把「模型」變成了一個可執行的安裝包。
手法五:MCP Server 與 Agent 工具鏈
隨著 Agent 架構普及,模型不再只是回答問題,而是會呼叫外部工具:讀寫檔案、查詢資料庫、發送郵件、操作雲端資源。這些工具通常透過 MCP(Model Context Protocol)或類似的介面註冊給模型使用。
攻擊面就此出現。一個惡意的 MCP Server 可以:在工具描述中夾帶提示注入(prompt injection),誘導模型執行非預期操作;在回傳結果中藏入指令,讓 Agent 在後續步驟中做出危險行為;或者單純記錄所有經過的資料,把敏感資訊外洩。
由於 Agent 通常被賦予相當大的權限,一個被汙染的工具節點,可能導致整個自動化流程被接管。而且這類攻擊往往發生在「模型已經被信任」之後,傳統的套件掃描工具完全看不到。
手法六:CI/CD 與建置環境的下毒
最後一種,也是最致命的一種:攻擊者不碰你的程式碼,而是碰你的建置流程。
常見路徑包括:入侵 GitHub Actions 的第三方 action、竊取存放在 CI 環境中的 token、利用快取機制植入被篡改的產物、或是在建置階段注入環境變數。一旦建置環境被控制,攻擊者就能在每次部署時,把惡意程式碼打包進你的正式環境,而你本地端看到的程式碼始終是乾淨的。
這類攻擊的偵測難度極高,因為它繞過了程式碼審查,也繞過了本機測試。防禦重點在於最小權限原則、短效憑證(例如 OIDC 聯合身分)、建置產物的簽章與驗證,以及對第三方 action 的版本鎖定。
三、AI 時代的新變數:當攻擊者也有了 AI
前面談的是手法,這一段要談的是「規模」與「速度」的變化。AI 不只讓防禦方變強,也讓攻擊方變強,而且不對稱地變強。
Slopsquatting:AI 幻覺出來的套件名
這是一個近兩年才被正式命名的現象。大型語言模型在生成程式碼時,偶爾會「發明」不存在的套件名稱。這些名稱看起來非常合理,命名風格與真實套件一致,甚至會附上看起來煞有其事的 API 用法。
研究人員發現,這些被幻覺出來的套件名有一定的可預測性。於是攻擊者開始主動監控、預測模型可能生成的假套件名,並搶先在 PyPI 或 npm 上註冊。等到開發者照著 AI 的建議安裝時,就會裝到攻擊者準備好的版本。
這個攻擊鏈之所以危險,是因為它結合了兩個信任來源:開發者信任 AI 助手的建議,而 AI 助手本身並沒有查證能力。當「AI 說可以裝」變成一種日常,傳統的「同事推薦比較可靠」這種社會防線就失效了。
對此的防禦很直接:AI 生成的任何 import 語句,都必須經過人工查證。確認套件存在、確認維護者、確認下載量與發布歷史,再決定要不要裝。把 AI 當成寫程式的助手,而不是套件審查員。
自動化偵察與大規模投毒
另一個變化是攻擊的規模化。過去,攻擊者要人工尋找有價值的目標、手動分析程式碼、手工製作釣魚郵件。現在,這些工作可以大幅自動化:掃描公開儲存庫中誤植的憑證、分析套件依賴圖找出高價值節點、自動生成看起來合理的惡意套件、甚至自動化的社交工程訊息。
同時,AI 輔助開發讓「程式碼產出速度」大幅提升,但對應的審查能力並沒有等比例成長。這種「產出快於審查」的失衡,正是供應鏈攻擊最理想的溫床。
四、開發者為什麼會中招?
理解手法之後,下一個問題是:為什麼這麼多聰明人還是會上當?答案通常不在技術,而在人性與制度。
信任慣性與「它能跑就好」的心態
軟體開發有一個根深柢固的文化:只要能跑,就是對的。這個文化讓工程師能快速迭代,但也讓安全審查變成「有空再說」的事。當一個套件安裝順利、測試通過、功能正常,大腦就會自動判定它是安全的。
再加上時間壓力。上线期限在前,沒人會為了一個「應該不會有事」的風險,去花兩小時審查一個間接依賴。攻擊者很清楚這一點,所以他們設計的惡意行為通常延遲觸發,讓你在一週後、一個月後才發現問題,而那時已經很難回溯。
開源生態的結構性問題
還有一個更根本的問題:整個開源生態建立在「少數志工維護關鍵基礎設施」之上。許多被廣泛使用的套件,維護者只有一兩個人,沒有經費、沒有安全團隊、也沒有時間審查每一則 PR。
這造成了兩個後果。第一,維護者帳號成為高價值目標,只要盜取一個帳號,就能影響數以萬計的下游專案。第二,當維護者想移交專案時,很容易被惡意人士接手,形成「合法接管、惡意改版」的攻擊路徑。
對企業而言,這意味著「相信開源」這件事本身需要被制度化:不是不要用開源,而是要把開源依賴當成外部廠商來管理,有清單、有評估、有更新機制。
五、防禦實務:把信任鏈一段一段補起來
講完風險,接下來談解法。供應鏈防禦不是單一工具能解決的問題,而是一組分層的習慣與制度。
個人與團隊的套件防護
第一,永遠使用 lockfile,並把它提交進版控。lockfile 記錄了每個套件的確切版本與來源雜湊,能防止「今天裝跟明天裝」裝到不同東西。沒有 lockfile 的專案,等於每次建置都在重新抽籤。
第二,鎖定版本並定期更新。這聽起來矛盾,但實務上是:日常使用固定版本,並透過自動化工具(如 Dependabot、Renovate)定期產生更新 PR,由人審查後合併。這樣既能避免意外升級,也不會讓依賴永遠停在有漏洞的舊版。
第三,停用安裝腳本。在 npm 可用 --ignore-scripts,在 Python 可搭配 --no-build-isolation 與 --only-binary 等策略,或使用內部鏡像先做掃描。多數專案根本不需要安裝腳本,停用它的成本很低,收益卻很高。
第四,使用私有套件代理。讓所有依賴都先經過公司內部的 Artifactory 或 Nexus,在那裡做快取、掃描與白名單控管。這樣即使上游被投毒,也能在進入開發環境前攔下來。
第五,導入 SCA 與 SBOM。軟體組成分析(SCA)工具能掃描依賴清單中的已知漏洞與惡意套件;軟體物料清單(SBOM)則讓你在事故發生時,能快速回答「我們到底用了哪些東西」。這在合規要求日益嚴格的今天,已經不只是加分項。
模型與資料層的防護
模型層的防護邏輯與套件層不同,因為模型不是程式碼,無法逐行審查。可行的策略包括:
優先使用 safetensors 等純資料格式,避免 pickle 反序列化風險。若必須使用 pickle 格式,務必在隔離環境中載入,並限制其網路與檔案存取權限。
驗證模型來源與雜湊值。只從官方或可信任的組織帳號下載模型,並比對官方公布的雜湊值。對於內部使用的模型,建立一份核准清單,未經核准的模型不得進入正式環境。
對模型行為做基準測試。建立一組標準測試集,定期檢查模型輸出是否出現異常偏移。這無法保證抓出所有後門,但能提高攻擊者的成本。
限制 Agent 的工具權限。採用最小權限原則,每個工具只給完成任務所需的最低權限;高風險操作(如刪除資料、發送外部請求、修改雲端資源)應要求人工確認。工具的輸入輸出也要經過驗證,避免提示注入一路傳導。
組織層面的治理與文化
技術手段之外,制度才是長期解方。
建立依賴引入流程。新套件不是不能加,而是要有人負責判斷:這個套件解了什麼問題?有沒有更輕量的替代方案?維護者是否活躍?授權條款是否相容?把這個判斷記錄下來,未來才能追溯。
定期演練供應鏈事故。假設某個熱門套件明天被投毒,你們能在多久內找出受影響的專案?能在多久內回滾?這種演練比任何簡報都更能暴露流程缺口。
投資建置環境的安全。CI/CD 是供應鏈的咽喉,卻常被當成「基礎設施部門的事」。短效憑證、最小權限的服務帳號、第三方 action 的版本鎖定、建置產物的簽章驗證,這些都應該被視為核心安全控制,而不是選配。
讓安全成為預設值。最有效的防護,是讓「安全」變成不用思考的預設行為:專案範本自帶 lockfile 與掃描設定、內部 registry 預設阻擋未經核准的套件、CI 預設不給寫入權限。當正確的做法同時也是最省事的做法,採用率才會真正提升。
六、寫給想在 AI 專案裡活久一點的人
最後,回到比較實務的層面。如果你正在帶領一個 AI 專案,或者只是剛開始接觸這塊領域,以下幾點或許值得放在心裡。
把「安裝」當成一個有風險的動作。 每一次 pip install、每一次 npm install、每一次從網路下載模型,都是一次信任的轉移。這不是要你疑神疑鬼,而是要你建立「先確認來源、再執行」的習慣。
不要讓 AI 幫你決定要信任什麼。 AI 可以幫你寫程式、找你沒想到的套件,但它不具備查證能力。它給你的每一個套件名稱、每一個 API 用法,都需要你親自確認。
接受「沒有百分之百安全」這件事。 供應鏈防禦的目標不是零風險,而是把風險降到可接受、可偵測、可回復的程度。與其追求滴水不漏,不如確保事故發生時你能快速反應。
關注社群的早期訊號。 許多供應鏈攻擊在爆發前,會先在 GitHub issue、資安郵件清單、或社群討論中出現徵兆。建立資訊接收的管道,比事後補救便宜太多。
結語:信任是效率的來源,也是風險的來源
回頭看那位深夜趕專案的工程師,他犯的錯其實不是「不夠小心」,而是整個生態讓他別無選擇。現代軟體開發的規模,已經不可能靠人工審查每一行程式碼;我們必須依賴套件、依賴模型、依賴工具鏈,才能把有限的時間留給真正需要創造力的部分。
這沒有錯。錯的是我們把「依賴」當成「免費」,忘了它其實是一種風險的移轉。每一個被安裝的套件、每一個被載入的模型、每一個被授權的工具,都是在告訴系統:「我相信你。」
AI 讓這條信任鏈變得更長、更快、更難看清。但它同時也給了我們更好的工具:自動化的依賴分析、可驗證的軟體物料清單、更透明的模型格式、更嚴謹的權限控管。關鍵在於,我們是否願意把這些工具從「選配」變成「標配」。
套件裡會藏惡意碼,不是因為套件本身邪惡,而是因為那條鏈上總有某一環被攻破。與其假設每一環都安全,不如假設某一環遲早會出事,然後把系統設計成「即使出事也能撐住」。這或許才是面對 AI 供應鏈攻擊,最務實也最長久的態度。
下次你按下 Enter 執行安裝指令之前,多花三秒鐘看一眼來源。這三秒,可能就是你和下一場事故之間的距離。