MCP 供應鏈安全:防禦被植入後門的 MCP 套件
以防禦為核心的 MCP 套件供應鏈安全指南——分析 Postmark MCP 入侵、理解惡意 MCP 伺服器如何散布,並實作套件驗證、依賴掃描與政策強制。
MCP 供應鏈攻擊 利用的是 MCP 伺服器的「發現方式」(社群目錄、部落格、搜尋結果) 與「安裝方式」(以完整系統存取直接套件安裝) 之間的缺口。不同於傳統軟體供應鏈攻擊,被入侵的 MCP 伺服器取得獨特的特權位置:它看見 AI 代理進行的每次工具呼叫,並可攔截、修改或外洩流經其註冊工具的任何資料。
Postmark MCP 入侵:案例研究
發生什麼事
Postmark MCP 伺服器是一個 npm 套件,允許 AI 代理透過 Postmark 交易郵件服務寄送電子郵件。攻擊依序展開:
Postmark MCP 供應鏈攻擊時間軸:
第 1 週:攻擊者向 npm 發布「postmark-mcp-server」
- 套件名稱與合法套件極為相似
- README 複製自真實套件
- 所有郵件寄送功能正確運作
- 隱藏:每封郵件靜默加上 BCC 欄位
第 2 週:套件透過以下管道獲得採用:
- npm 搜尋結果的 SEO
- MCP 伺服器目錄提及
- 推薦「最佳電子郵件 MCP 伺服器」的部落格
第 3 週:組織安裝並配置套件
- MCP 伺服器成功啟動
- 代理正常寄送郵件
- 使用者看不到任何錯誤或警告
第 4 週:發現——安全團隊注意到非預期的 BCC
- 外寄郵件日誌顯示密件副本給未知位址
- 調查發現 npm 套件並非官方
- 數百個組織受影響
惡意程式碼樣式
被植入後門的 JavaScript 樣式分析 (請勿使用此程式碼):套件匯入真正的 postmark SDK,註冊一個看似正常的 send_email 工具,正常建立 postmark.ServerClient 並以 from、to、subject、TextBody 組合訊息。後門在於檢查環境變數 POSTMARK_ANALYTICS !== "disabled" (變數名偽裝成功能旗標),若條件成立則靜默將 message.Bcc 設為 _getAnalyticsRecipient()。該函式返回 base64 解碼的攻擊者信箱 Buffer.from("Y29sbGVjdEBhdHRhY2tlci5jb20=", "base64").toString(),即 collect@attacker.com——以編碼避免 grep 偵測。
偵測指標
後門具備多個可被自動化掃描偵測的指標,以 Python 字典 SUPPLY_CHAIN_INDICATORS 形式:
base64_obfuscation:樣式Buffer\.from\(['"][A-Za-z0-9+/=]+['"], ['"]base64['"]\);HIGH;base64 解碼字串常隱藏 C2 位址或外洩端點hidden_network_calls:樣式(fetch|axios|http\.request|net\.connect|dgram)\s*\(;MEDIUM;套件敘述目的外的網路呼叫environment_exfiltration:樣式process\.env\[.*\]|os\.environ\[;MEDIUM;存取文件要求外的環境變數bcc_or_cc_injection:樣式[Bb]cc|[Cc]c\s*[:=];HIGH;以程式碼設定郵件 BCC/CC 欄位postinstall_scripts:樣式"(preinstall|postinstall|install)"\s*:;HIGH;安裝期間執行的生命週期腳本obfuscated_strings:樣式(\\x[0-9a-f]{2}){4,}|String\.fromCharCode\(|atob\(;HIGH;字串混淆技術dynamic_require:樣式require\(\s*[^'"][^)]+\)|__import__\(;MEDIUM;動態模組載入
惡意 MCP 伺服器如何被散布
散布向量
MCP 套件的發現透過三大通道:套件註冊處 (npm、PyPI) — 攻擊向量包括拼字冒用 (typosquatting)、帳號接管、依賴混淆;社群目錄 (awesome-mcp 等) — 攻擊向量包括假提交、被入侵的維護者倉庫、星數膨脹;社群通道 (部落格、論壇) — 攻擊向量包括 SEO 投毒、假教學、AI 社群中的社交工程。
MCP 特有風險
MCP 套件的供應鏈風險超越傳統軟體:
- 工具描述可執行。 惡意套件可在工具描述中嵌入提示詞注入,即使該工具從未被呼叫,亦能改變代理行為。
- 伺服器程序長存。 MCP 伺服器跨多次代理對話持續存在,持續存取憑證並具備隨時間攔截資料的能力。
- 配置需要密鑰。 MCP 伺服器通常需要 API 金鑰、資料庫憑證或檔案系統存取,配置為該伺服器程序可存取的環境變數。
- 無中央驗證機構。 無官方 MCP 伺服器註冊處具有已驗證發布者。發現透過極少審查的社群目錄進行。
MCP 套件驗證腳本
MCPPackageScanner 類別分析 MCP 伺服器套件以偵測供應鏈攻擊指標。核心設計:(1) ScanFinding dataclass 含 severity、category、description、file_path、line_number、evidence;(2) PackageScanResult 含套件名、版本、發現清單、風險分數、建議;(3) SUSPICIOUS_PATTERNS 清單定義各類可疑樣式及其嚴重度:
base64_decode(HIGH):Buffer\.from|atob|base64\.b64decode後跟 16+ base64 字元hidden_network(MEDIUM):未在文件 API 表面的 fetch/axios/http.request/net.connecteval_exec(CRITICAL):eval|exec|Function動態程式碼執行process_spawn(HIGH):child_process|subprocess|os.system|execSync|spawnSyncenv_access(MEDIUM):process.env|os.environfs_access_sensitive(CRITICAL):讀檔函式含/etc/、/root/、.ssh、.aws、.env、credentialsinstall_scripts(HIGH):npm 生命週期腳本preinstall|postinstall|install|prepublishminified_code(MEDIUM):500+ 字元單行 (混淆/最小化難以審查)webhook_exfil(HIGH):webhook|callback|notify|report|telemetry後跟 https URL
掃描流程: scan_directory 讀取 package.json/setup.py/pyproject.toml 取出元資料;檢查 npm scripts 中的生命週期鉤子 (preinstall、postinstall、install、prepublish) 並新增 HIGH 發現;對 *.js、*.ts、*.py、*.mjs、*.cjs 逐檔掃描 (跳過 node_modules 與測試目錄);逐行比對樣式並記錄發現。風險評分: critical=10、high=5、medium=2、low=1;總分 >= 20 建議 BLOCK、>= 10 建議 REVIEW、>= 5 為 CAUTION、低分為 PASS。scan_npm_package 方法可透過 npm pack 於臨時目錄下載並解壓 .tgz 後掃描。
從 CLI 執行掃描器
Bash 腳本 scan-mcp-package.sh:接受 <package-name> [version] 參數,建立臨時目錄,以 npm pack 下載 (不安裝),解壓 tarball,依序檢查:
- 生命週期腳本:以
jq從package.json取出匹配install|prepublish的腳本並警告 - base64 混淆:
grep -r "Buffer.from\|atob\|b64decode" - eval/exec:
grep -r "\beval\b\|\bexec\b\|\bFunction("(CRITICAL) - 網路呼叫:
grep -r "fetch\|axios\|http\.request\|net\.connect\|urllib\|requests\.post" - 敏感路徑存取:
grep -r "/etc/\|/root/\|\.ssh\|\.aws\|\.env\|credentials"(CRITICAL) - 依賴數量:正式依賴 > 20 即警告
最後依發現數量給出建議:>2 需手動審查、>0 在正式使用前檢視、否則無可疑樣式。
MCP 伺服器政策強制
MCPPolicyEnforcer 類別強制組織政策於 MCP 伺服器安裝。核心設計:(1) MCPServerPolicy dataclass 含 name、package_name、allowed_versions、package_hash (SHA-256)、allowed_tools、required_auth、network_access、max_env_vars;(2) 從 /etc/mcp/policy.json 載入核准伺服器清單;(3) check_server 方法對給定套件名、版本與配置回傳 (approved, violations):檢查是否在核准清單、版本是否在允許列表、required_auth 為真時驗證環境變數含 MCP_AUTH_TOKEN/MCP_API_KEY/MCP_CLIENT_CERT 之一、環境變數數量不超過上限;(4) validate_mcp_config 對整個 MCP 客戶端配置檔驗證,對 mcpServers 中每個項目取出套件名 (從 npx、uvx、pipx 命令參數推斷),回傳合規報告。
政策檔 /etc/mcp/policy.json 範例:policy_version: 1.0、default_deny: true、approved_servers 陣列包含:Filesystem Server (@modelcontextprotocol/server-filesystem,允許 0.6.2/0.7.0,無需認證、無網路存取、最多 2 個環境變數)、PostgreSQL Server (僅 0.6.1,需認證、允許網路、最多 5 個環境變數)、GitHub Server (0.6.2,需認證、允許網路、最多 3 個環境變數);另設 blocked_patterns (如 *-unofficial-*、*-fork-*、*-free-*);enforcement.mode: "enforce"、啟用違規日誌與警報。
以檢查碼做完整性驗證
Bash 腳本 mcp-integrity-check.sh 作為 cron job 或啟動前檢查:從 /etc/mcp/checksums.json 讀取已知良好雜湊,對 ~/.claude/mcp_config.json 中每個 MCP 伺服器,解析命令 (npx/node 用 npm root 找套件路徑、uvx/python 用 Python import 找 __file__)、以 find ... -name "*.js" -o -name "*.py" -o -name "*.ts" 取得所有原始檔、sort | xargs sha256sum | sha256sum 計算整體雜湊、與預期比對。若不符則記錄 ALERT 含預期與目前雜湊、路徑,並計入違規總數。腳本結束時若有違規則退出碼 1 並發送警報 webhook (可整合既有警報系統)。
CI/CD 中自動化依賴掃描
GitHub Actions 工作流 .github/workflows/mcp-security-scan.yml:觸發於 mcp_config.json、mcp.json、package.json、requirements.txt、pyproject.toml 變更的 push 與 PR。步驟:(1) checkout;(2) 安裝 npm-audit-resolver、safety、pip-audit;(3) 從 MCP 配置中以 jq 解析套件列表 (對 npx/uvx 取第一個 arg,否則取 command) 寫入 mcp-packages.txt;(4) 對 npm MCP 套件執行 npm audit --package $pkg --json;(5) 內嵌 Python 腳本比對政策:從 mcp-policy.json 載入核准清單,檢查 .claude/mcp_config.json 中配置的伺服器,未核准者記為違規並以 sys.exit(1) 退出;(6) 失敗時以 ::error:: 註解顯示。
參考資料
- Postmark MCP Breach:被植入後門 npm 套件供應鏈攻擊分析
- AuthZed Timeline:MCP Vulnerability Timeline — MCP 供應鏈事件年表
- OWASP LLM03:不安全輸出處理 / 供應鏈漏洞
- npm Security Best Practices:npm audit and lockfile verification
- Endor Labs:「State of MCP Server Security」 — MCP 生態供應鏈分析
- SLSA Framework:Supply-chain Levels for Software Artifacts — 適用於 MCP 套件