供應鏈安全標準
適用於所有專案。規則審查日期:2026-11-11(Shai-Hulud / Mini Shai-Hulud 蠕蟲後)。
機器層級預設值(~/.npmrc)
minimum-release-age=1440 # pnpm 專用 — 分鐘(1440 = 24小時)
min-release-age=1 # npm 12+ 專用 — 天 (1 = 24小時)
兩種套件管理器使用不同的金鑰名稱與不同的單位。 已於 2026-08-21 透過閱讀各工具的原始碼驗證:pnpm 計算 Date.now() - minimumReleaseAge * 60 * 1e3(分鐘);npm 的 min-release-age 設定定義攜帶 hint: '<days>'。兩行都需要 — 一行無法涵蓋另一行,且將 1440 複製到 npm 金鑰將意味著 1440 天,並會封鎖幾乎所有安裝。
npm 在安裝時會顯示 Unknown user config "minimum-release-age" 並警告將在未來的 major 版本中停止運作。在金鑰存在於 ~/.npmrc 時這是無可避免的:pnpm 11 移除了全域設定寫入功能(pnpm config set --global 現在會導向專案層級的 pnpm-workspace.yaml),因此 ~/.npmrc 是全域 pnpm 閘門唯一能存在的地方。接受此警告;請勿刪除該金鑰。
請勿依賴這些 — 經驗證無效
-
block-exotic-subdependencies— 在 npm 和 pnpm 的原始碼中皆未出現。它從未發揮任何作用。奇異依賴必須透過審查來捕捉,而非此金鑰。 -
ignore-scripts=true— 此技能先前聲稱已全域設定。實際上並未設定,npm config get ignore-scripts回傳false,因此生命週期腳本在安裝時確實會執行。決定於 2026-08-21:保留關閉狀態。請勿啟用。 Postinstall 是 npm 主要的入侵向量,因此這是一個已知且被接受的缺口 — 而非需要修補的遺漏。在全域開啟它會破壞每個專案的原生建置(esbuild、swc、sharp、node-gyp),且錯誤訊息會遠離問題根源。上述的 24 小時釋出年齡閘門承擔了此風險。如果某個特定專案需要腳本隔離,請在該專案範圍內進行設定 — 永遠不要全域設定。
請根據工具本身而非此檔案來驗證類似的主張 — 審計時這裡的三個條目都是錯誤的。
供應鏈攻擊分類學(稽核前參考)
1. 域名搶註 / 依賴混淆
套件名稱與熱門套件幾乎相同,或公開套件與內部限定名稱相符。僅 2025 年就有 454,648 個惡意 npm 套件被發布。
偵測: 對不熟悉的套件執行 npm info <pkg> | grep -E 'created|repository'。與內部 registry 名稱交叉比對。
2. 維護者帳號接管
攻擊者對維護者進行釣魚,發布包含 post-install 有效載荷的新版本。2025 年 9 月的 Shai-Hulud 攻擊影響了 chalk、debug、ansi-styles(每週 2.6B 下載量)。2026 年 3 月,Axios(每週 1 億+)經由北韓社交工程攻擊受影響。
偵測: npm diff <pkg>@<last-known-good> <pkg>@latest -- package.json scripts — 檢查 patch 版本中是否新增了生命週期腳本。
3. 倉庫劫持 / 命名空間搶註
攻擊者註冊一個廢棄的 GitHub 用戶名或 npm 命名空間,重建倉庫,提供惡意程式碼。
偵測: 檢查 package.json 的 repository 欄位;標記建立時間晚於該套件首次 npm 發布日期的 GitHub 帳號。
4. CI/CD 管道注入(pull_request_target / 快取投毒)
攻擊者針對使用 pull_request_target 且與特權發布作業共用快取的倉庫發起 PR。投毒 pnpm store;下一次釋出工作流程洩漏 npm OIDC token。TanStack 攻擊向量(2025 年 11 月,2026 年 5 月 Mini Shai-Hulud,300+ 套件,每週 1600 萬下載量)。
偵測:
grep -r "pull_request_target" .github/workflows/
grep -r "cache" .github/workflows/ | grep -i "pnpm\|npm\|store"
強制規則: 如果工作流程會檢出 PR 程式碼或與特權作業共用快取,絕對不要使用 pull_request_target。
5. Docker 映像投毒
攻擊者入侵 Docker Hub 憑證,用惡意二進位檔覆寫現有映像標籤(包括 latest)。2026 年 3 月,Trivy aquasec/trivy 的 0.69.4–0.69.6 和 latest 標籤被投毒。2026 年 4 月 KICS — 五個標籤被覆寫;掃描包含機密的 Terraform/K8s 配置。
偵測: docker inspect <image> --format '{{.Id}}' 與配置中固定的摘要比對。
強制規則: 將所有映像固定到 @sha256: 摘要。安全工具映像絕對不要使用 latest。
6. GitHub Actions 標籤重指向
攻擊者入侵 Actions 維護者的 token,移動現有版本標籤指向惡意程式碼。tj-actions/changed-files CVE-2025-30066(2025 年 3 月,23,000+ 倉庫)將所有 CI 機密傾印至日誌。2026 年 5 月:熱門 Actions 標籤被重導向至冒名提交。 偵測:
grep -r "uses:.*@v[0-9]" .github/workflows/ # 標記標籤固定(不良)
grep -r "uses:.*@[a-f0-9]\{40\}" .github/workflows/ # SHA 固定(正確)
強制規則: 將每個第三方 Action 固定到完整的 40 字元提交 SHA,而非版本標籤。actions/*(第一方)可使用 major 版本標籤。
7. 鎖檔篡改 / 完整性繞過(PackageGate 等級)
攻擊者修改鎖檔以替換惡意套件版本,或移除完整性哈希值,使下次安裝時靜默取得不同的 tarball。2026 年 1 月(Koi Security)記錄了六個零日鎖檔漏洞。 偵測:
grep -E '"resolved".*git\+|tarball' package-lock.json pnpm-lock.yaml
grep -v "integrity" pnpm-lock.yaml | grep "resolved"
強制規則: CI 必須使用 pnpm install --frozen-lockfile 或 npm ci — 永遠不要在 CI 中使用裸 npm install。
8. 子依賴陰影
攻擊者針對三層以上的傳遞依賴。@ctrl/tinycolor 是 Shai-Hulud 的傳播節點。
偵測: npm ls --all 2>/dev/null | grep -E "postinstall|preinstall"。在 PR 上使用 socket scan。
9. 社交工程維護者交接
攻擊者冒充招聘人員或商業夥伴以獲取 npm 發布權限。UNC1069(北韓)於 2026 年 3 月針對 Axios 維護者,也嘗試攻擊 Socket CEO、Lodash 創作者、Fastify 負責人。
偵測: 對關鍵依賴執行 npm owner ls <pkg>;監控可疑發布前的新協作者。
10. 抗議軟體(維護者蓄意破壞)
維護者故意注入破壞性程式碼。colors.js v1.4.44–1.4.2(2022 年 1 月,無限迴圈)、node-ipc v10.1.1–10.1.3(2022 年 3 月,針對俄羅斯 IP 刪除檔案)。2026 年 5 月出現三個新的惡意 node-ipc 版本。
偵測:
npm diff <pkg>@<prev> <pkg>@<new> -- lib/
grep -r "networkInterfaces\|geoip\|fs.rmdir\|fs.unlink" node_modules/<pkg>/
將 node-ipc、colors、faker 固定到確切的已知良好版本。
11. 蠕蟲型自我複製惡意軟體
有效載荷竊取 npm token/PAT 並自主發布受害者維護的其他套件的惡意版本。首次觀察到於 2025 年 9 月的 Shai-Hulud;2026 年 5 月的 Mini Shai-Hulud(300+ 套件,每週 1600 萬下載量,同時影響 npm 和 PyPI)。 偵測 IOC:
find .github/workflows -name "*.js" # 工作流程中的 bundle.js
grep -ri "shai-hulud" . # 蠕蟲字串
find node_modules -name "data.json" -newer package.json # 外洩暫存
find node_modules -name "cloud.json"
12. 潛伏 / 環境條件觸發的有效載荷
僅在存在 AWS_SECRET_ACCESS_KEY、GITHUB_TOKEN 或 CI=true 時啟動的有效載荷 — 可逃避沙箱掃描器。
偵測:
grep -r "process.env.AWS_SECRET\|process.env.GITHUB_TOKEN\|process.env.NPM_TOKEN" node_modules/
標記任何讀取這些變數但缺乏正當理由的套件。
13. 安全工具作為攻擊向量
攻擊者專門針對安全掃描工具(Trivy、KICS、Semgrep),因為它們在 CI 中以提升的權限存取機密和基礎設施配置。Trivy 和 KICS 都在 2026 年 3 月至 4 月間受到攻擊。 強制規則: 將所有安全工具 Docker 映像固定到摘要,而非標籤。透過供應商發布說明,頻外驗證摘要。
14. 非 Registry / CDN 依賴
從 git URL、GitHub tarball 或自訂 CDN(例如 cdn.sheetjs.com)解析的套件繞過了 registry 安全閘門和來源驗證,也不受釋出年齡閘門的保護 — 該閘門僅適用於 registry 版本。部分完全缺少完整性哈希值。沒有任何機制會自動阻止這些;必須透過審查來捕捉。
偵測:
grep -E '"resolved".*github\.com|cdn\.' package-lock.json pnpm-lock.yaml
grep -E '"version":\s*"(git\+|https?:)' package.json
專案層級的 npm/pnpm 衛生習慣
- 提交鎖檔。CI 必須使用
pnpm install --frozen-lockfile(或npm ci)。CI 中永遠不要使用裸npm install。 - 在
package.json中固定packageManager以鎖定 pnpm/npm 版本。 - 將受損命名空間中的套件固定到確切版本:
@tanstack/*、posthog-node、@mistralai/*、@langchain/mistralai、@ctrl/*、ngx-*、rxnt-*、@zapier/*、@postman/*、@uipath/*、agent-mcp、@semgrep/*、node-ipc、colors、faker。 package.json中沒有萬用字元"*"版本。- 沒有
pkg.pr.newURL — 這些是暫時的 PR 預覽建置,非不可變的 artifacts。 - 對於 npm/yarn 專案,在其本機
.npmrc中鏡像相同的 npmrc 閘門。 - 新專案偏好使用 pnpm。不要僅為了安全性而遷移運作中的專案。
GitHub Actions 強化
強制規則
- 絕對不要在以下情況下使用
pull_request_target:工作流程會檢出 PR 程式碼、根據 PR 程式碼執行安裝/建置/測試,或與特權工作流程共用快取。 pull_request_target僅可用於讀取 PR 元資料(標籤、評論、標題)且不進行檢出。- 不要在 PR 觸發的作業與發布/釋出作業之間共用快取。
- CI 中絕對不要對可變動分支(
@main、@master)使用curl | bash或wget | sh。始終將安裝腳本固定到特定版本並驗證 checksum。
workflow_run 保護
使用 workflow_run 將特權作業鏈接到父工作流程之後時,if: 必須斷言所有條件:
if: >
github.event_name == 'workflow_dispatch' ||
(github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_branch == 'main' &&
github.event.workflow_run.head_repository.full_name == github.repository &&
github.event.workflow_run.event == 'push')
Action 固定
- 將每個第三方 Action 固定到完整的 40 字元提交 SHA,而非
@v1/@v6。 - 為可稽核性加上人類可讀標籤的註解:
docker/login-action@65d0a9e # v3 - 第一方
actions/*可使用 major 版本標籤。 - 取得當前 SHA:
gh api repos/<owner>/<action>/git/ref/tags/<tag> - 自動化操作:
npx pin-github-action .github/workflows/*.yml - 每個作業最小化
permissions:。預設為contents: read。僅在發布步驟新增id-token: write。
npm 發布工作流程
- 在 npm 帳號上要求 2FA:
npm profile enable-2fa auth-and-writes。 - 使用信任發布(OIDC)而非長期有效的
NPM_TOKEN機密。 - 新增
--provenance(或provenance: true),以便消費者能驗證來源。 - 僅從由
main分支標籤推送觸發的release.yml發布。永遠不要從 PR 觸發的工作流程發布。
Docker / 容器衛生習慣
- 將每個
FROM固定到摘要:FROM node:22-slim@sha256:<hash> - 在生產環境 Dockerfile 或 CI 中絕對不要使用
latest或無標籤的映像。 - 安全工具映像(Trivy、KICS、Semgrep、Snyk、Grype、Hadolint)風險最高 — 請優先固定這些。
- 取得當前摘要:
docker buildx imagetools inspect node:22-slim --format '{{json .Manifest.Digest}}' - 對於私有 registry 映像:使用不可變標籤 + 摘要發布。
開發者工具與配置檔
- 永遠不要以純文字形式將 API token 或機密儲存在
~/.cursor/mcp.json、~/.claude/settings.json或類似的配置檔中。使用環境變數或金鑰鏈。 - 將 MCP 伺服器套件固定到確切版本(
[email protected],而非mcp-remote@latest)。 - 在任何供應鏈事件發生後,檢查
~/.vscode/tasks.json和~/.cursor/中是否有意外的自動執行鉤子。
偵測 / 監控
- 在任何包含工作流程的倉庫的 CI 中安裝 zizmor 或
snyk-labs/github-actions-scanner。 - 在任何發布套件的倉庫(任何可發布的函式庫)上新增 socket.dev GitHub App。
- 訂閱 npm 安全公告 RSS 和 PyPI 惡意軟體資料來源。
IOC 快速掃描檢查清單
# Shai-Hulud / 蠕蟲 IOC
grep -ri "shai-hulud" .
find .github/workflows -name "*.js"
find node_modules -name "cloud.json"
# 受損工作流程模式
grep -r "pull_request_target" .github/workflows/
grep -r "curl.*|.*sh\|wget.*|.*sh\|base64.*eval" .github/workflows/
# 未固定的 Actions
grep -r "uses:.*@v[0-9]" .github/workflows/
# 鎖檔中的奇異依賴
grep -E '"resolved".*git\+|cdn\.' package-lock.json pnpm-lock.yaml
grep -v integrity pnpm-lock.yaml | grep resolved
# Docker
grep -r "FROM.*:latest\|FROM.*[^@]$" Dockerfile* docker-compose*.yml