1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【2026年3月】npm / PyPI サプライチェーン攻撃の全容と実践的な防御ガイド

1
Last updated at Posted at 2026-04-01

即時対応が必要な方へ: Part 5: 自分のマシンを棚卸しする に2分で実行できるスキャンコマンドがあります。まずそこから始めてください。

2026-04-01 17:03 JST 追記
非エンジニア向けにスキャンツールを作成して公開しました。Claude や ChatGPT などで対話しながら設定していくための INSTRUCTION.md も同梱しています。

はじめに

2026年3月19日〜31日の約2週間で、npm および PyPI エコシステムの広く使われているパッケージが連鎖的に侵害された。

  • axios(npm、週間約1億ダウンロード)— メンテナーアカウント乗っ取りによる RAT 配布
  • LiteLLM(PyPI、月間約9,700万ダウンロード)— CI/CD クレデンシャル窃取からの連鎖侵害
  • Trivy / KICS(GitHub Actions)— バージョンタグの上書き
  • Telnyx(PyPI)— 同一キャンペーンの一環

いずれも「メンテナーアカウントの乗っ取り → 公式チャネルからの悪意あるバージョン公開」という共通パターンで、npm installpip install を実行するだけで、15秒で開発マシンが完全に侵害されるものだった。

本記事では、インシデントの全容、影響確認方法、対応手順、予防策、AI Agent 環境の強化、継続運用までを網羅的にまとめる。

テンプレートファイル(.npmrc, pip.conf, CLAUDE.md, AGENTS.md) はすべて GitHub で公開している。
👉 TAKT-R-D/npm-pypi-supply-chain-hardening

目次

Part 内容
Part 1 axios(npm)侵害の詳細
Part 2 TeamPCP キャンペーン(LiteLLM, Telnyx, Trivy, KICS)
Part 3 侵害が確認された場合の対応
Part 4 予防策(npm / PyPI / Composer / CI/CD)
Part 5 自分のマシンを棚卸しする
Part 6 AI Agent 環境の強化
Part 7 監視・継続運用

Part 1: axios npm 侵害

何が起きたか

2026年3月31日(UTC 00:21〜03:15)、axios の npm メンテナーアカウントが乗っ取られ、悪意のあるバージョンが公式パッケージとして公開された。

攻撃者はメンテナーの長期有効な npm アクセストークンを窃取し、GitHub Actions CI/CD を完全にバイパスして直接 npm に公開。正規リリースに含まれるはずの OIDC provenance / SLSA 署名は一切なかった。

影響を受けるバージョン

パッケージ 悪意のあるバージョン 安全なバージョン
axios 1.14.1, 0.30.4 1.14.0, 0.30.3
plain-crypto-js 4.2.1 — (存在自体が不正)

悪意のあるバージョンは約2〜3時間で npm から削除済み。現在 npm install axios を実行しても安全なバージョンがインストールされる。

攻撃の流れ

PHP プロジェクトへの注意

メインが PHP でも、フロントエンドツール(webpack, Vite, Laravel Mix 等)で npm 依存を持っているケースは多い。Huntress の調査では WordPress モジュールの node_modules 深部にまで plain-crypto-js が入り込んでいた事例が確認されている。PHP プロジェクトでも npm 依存の確認を省略しないこと。

影響確認手順

lockfile の確認

# package-lock.json
grep -r "axios.*1\.14\.1\|axios.*0\.30\.4\|plain-crypto-js" package-lock.json

# yarn.lock
grep -r "axios.*1\.14\.1\|axios.*0\.30\.4\|plain-crypto-js" yarn.lock

# 全プロジェクトを横断検索(Mac / Linux)
find ~ -name "package-lock.json" -exec grep -l "plain-crypto-js" {} \;
# Windows(PowerShell)
Get-ChildItem -Path $HOME -Recurse -Filter "package-lock.json" -ErrorAction SilentlyContinue |
  Select-String -Pattern "plain-crypto-js" | Select-Object -Unique Path

node_modules の確認

# Mac / Linux
find ~ -path "*/node_modules/plain-crypto-js" -type d 2>/dev/null

マルウェアは自身の package.json を clean 版に差し替えるため、フォルダの中身が正常に見えることがある。フォルダの存在自体が侵害の証拠。

OS別 RAT アーティファクトの確認

確認項目 Mac Windows Linux
RAT パス /Library/Caches/com.apple.act.mond %PROGRAMDATA%\wt.exe /tmp/ld.py
永続化 なし(実行中のみ) レジストリ Run キー MicrosoftUpdate なし(再起動で消える)
プロセスチェーン osascript → curl → com.apple.act.mond node → cmd/cscript → wt.exe python3 /tmp/ld.py

macOS:

ls -la /Library/Caches/com.apple.act.mond
ps aux | grep -i "com.apple.act.mond"

Windows:

Test-Path "$env:PROGRAMDATA\wt.exe"
Get-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name "MicrosoftUpdate" -ErrorAction SilentlyContinue

Linux:

ls -la /tmp/ld.py
ps aux | grep "python3 /tmp/ld.py"

ネットワーク IOC

種別
C2 ドメイン sfrclak.com
C2 IP 142.11.206.73
ポート 8000

Part 2: TeamPCP キャンペーン(PyPI + GitHub Actions)

概要

2026年3月19〜27日、TeamPCP と呼ばれる脅威グループが連鎖的なサプライチェーン攻撃を実行した。各侵害で得たクレデンシャルが次の攻撃を可能にするドミノ式の手法が特徴。

なお、axios の攻撃は TeamPCP とは別のアクターで、Google Threat Intelligence Group は北朝鮮の脅威アクター UNC1069 によるものと分析している。

タイムライン

日付 対象 エコシステム 悪意のあるバージョン
3/19 Trivy GitHub Actions, Docker v0.69.4、76タグ書き換え
3/23 Checkmarx KICS GitHub Actions, OpenVSX kics-github-action
3/24 LiteLLM PyPI 1.82.7, 1.82.8
3/27 Telnyx PyPI 4.87.1, 4.87.2
3/31 axios npm 1.14.1, 0.30.4

連鎖の仕組み

  1. Trivy → CI/CD シークレットと GitHub トークンを窃取
  2. 窃取した Trivy のクレデンシャル → Checkmarx KICS の GitHub Actions を侵害
  3. 窃取した CI/CD クレデンシャル → LiteLLM の PyPI 公開トークンを奪取
  4. 同じ手法 → Telnyx の Python SDK に適用

Python プロジェクトの確認

LiteLLM(v1.82.7, v1.82.8):

pip show litellm 2>/dev/null | grep -iE "name|version"
find / -name "litellm_init.pth" 2>/dev/null  # v1.82.8 の悪意ある .pth ファイル

v1.82.8 の .pth ファイルは Python インタプリタの起動時に自動実行される。LiteLLM を明示的にインポートしなくてもマルウェアが動作する。

Telnyx(v4.87.1, v4.87.2):

pip show telnyx 2>/dev/null | grep -iE "name|version"
パッケージ C2
LiteLLM models.litellm.cloud(正規ドメインのタイポスクワット)
Telnyx 83.142.209.203

GitHub Actions の確認

# 影響を受けるアクションの検索
grep -r "aquasecurity/trivy-action\|aquasecurity/setup-trivy\|Checkmarx/kics-github-action\|Checkmarx/ast-github-action" .github/workflows/
# 脆弱 — タグでピン(攻撃者がタグを上書きした)
- uses: aquasecurity/trivy-action@v1

# 安全 — コミット SHA でピン(不変)
- uses: aquasecurity/trivy-action@a7a829a0e31574e4e2e4af6e8ab3bf4c0a32c371

Part 3: 侵害が確認された場合の対応

いずれかの IOC が検出された場合、そのマシンは完全に侵害されたものとして扱う。

  1. 即座にネットワークから隔離する
  2. マシンを再イメージ(クリーンインストール)する — インプレースの修復は不可
  3. すべてのクレデンシャルをローテーションする:
    • npm / PyPI / Composer トークン
    • AWS / GCP / Azure クレデンシャル
    • SSH 秘密鍵
    • GitHub / GitLab トークン
    • CI/CD シークレット
    • .env ファイルに含まれるすべての値
    • データベースパスワード
    • すべての API キー(LLM プロバイダーキーを含む)
  4. CI/CD パイプラインを確認: 攻撃期間中にビルドが走った場合、そのシークレットもローテーション
  5. クラウド環境の監査ログを確認

Part 4: 予防策

npm(JavaScript / TypeScript)

バージョンの完全固定

{
  "dependencies": {
    "axios": "1.14.0"  // ← "^1.14.0" ではなく exact
  }
}
npm config set save-exact true

lockfile の厳格な運用

# CI/CD では npm install ではなく npm ci を使う
npm ci

package-lock.json は必ず Git にコミットする。

lifecycle scripts の無効化

npm config set ignore-scripts true
# .npmrc
ignore-scripts=true

ignore-scripts=true は lifecycle scripts をブロックするが、npm install 時のコード実行パスはこれだけではない(例: Git 実行パス)。ignore-scripts 単体に頼らず、バージョン固定、lockfile 強制、pnpm 採用と組み合わせること。

pnpm の採用

pnpm(v10+)はビルドスクリプト承認モデルを提供する。依存パッケージの lifecycle scripts はデフォルトでブロックされ、onlyBuiltDependencies 設定や pnpm approve-builds コマンドで明示的に承認する必要がある。

{
  "pnpm": {
    "onlyBuiltDependencies": ["sharp", "esbuild", "prisma"]
  }
}

モノレポでは pnpm-workspace.yaml にも設定可能。v10 未満では動作が異なる場合があるため pnpm --version で確認。

新規パッケージのクールダウン

# 公開から72時間以内のパッケージを拒否(npm v11+)
# キー名は npm バージョンで異なる可能性あり。npm help config で確認。
npm config set minimumReleaseAge 3d

provenance の確認

npm audit signatures

PyPI(Python)

ハッシュ検証 + wheel 限定

# ハッシュ検証 + ソースビルド禁止(setup.py 実行パスを完全排除)
pip install --require-hashes --only-binary :all: -r requirements.txt

--require-hashes--only-binary :all: の組み合わせが pip が提供する最も強力なインストール時防御。

依存関係のロック

# pip-tools
pip-compile requirements.in
pip-sync requirements.txt

Composer(PHP)

# lockfile を尊重し、install scripts を無効化
composer install --no-dev --no-scripts

# 脆弱性チェック
composer audit

PHP プロジェクト内の npm 依存も忘れずに確認:

find /path/to/php-projects -name "package-lock.json" -exec grep -l "plain-crypto-js" {} \;

CI/CD(GitHub Actions)

コミット SHA でピン

# 脆弱
- uses: actions/checkout@v4
# 安全
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2

Environment Reviewers

本番シークレットにアクセスするワークフローには required reviewers を設定。

self-hosted runner の回避

パブリックリポジトリでの self-hosted runner は強く非推奨。GitHub-hosted または JIT ランナーを使用。

CODEOWNERS

# .github/CODEOWNERS
/.github/workflows/   @security-team @devops-lead

Dependabot + Dependency Review

- uses: actions/dependency-review-action@<sha>
  with:
    fail-on-severity: high

Dependabot の自動マージは絶対に使わない。 PR のオープンのみに設定し、手動レビュー必須。

予防策チェックリスト

対策 npm PyPI Composer CI/CD
exact version 固定 save-exact true == で指定 ^/~ 除去
lockfile コミット package-lock.json poetry.lock composer.lock
lockfile only install npm ci pip-sync composer install 全て
install scripts 無効化 ignore-scripts=true --only-binary :all: --no-scripts 全て
ハッシュ要求 --require-hashes CI で強制
provenance 確認 npm audit signatures SLSA / Sigstore provenance 要求
lockfile PR レビュー 必須 必須 必須 ブランチ保護
SBOM 生成 syft / cdxgen 同左 同左 ビルドごと
CODEOWNERS .github/CODEOWNERS
Environment reviewers publish/deploy に必須

Part 5: 自分のマシンを棚卸しする

影響を受けたすべてのツールが公式アナウンスを出すわけではない。例えば Anthropic は Claude Code の npm 版を非推奨としてネイティブインストーラーに移行したが、axios を transitive dependency として含む多くのツールはそのようなアナウンスを出さない可能性が高い。上流からの通知を待たず、自分のマシンを能動的に確認。

クイックスキャン(コピペで実行、2分)

# ===== npm: グローバルインストールの確認 =====
echo "=== npm global: axios ==="
npm list -g axios 2>/dev/null

echo "=== npm global: plain-crypto-js(存在してはならない) ==="
npm list -g plain-crypto-js 2>/dev/null

# ===== PyPI: 侵害パッケージの確認 =====
echo "=== Python: litellm ==="
pip show litellm 2>/dev/null | grep -iE "name|version"

echo "=== Python: telnyx ==="
pip show telnyx 2>/dev/null | grep -iE "name|version"

# ===== ファイルシステム =====
echo "=== plain-crypto-js(ホーム以下) ==="
find ~ -path "*/node_modules/plain-crypto-js" -type d 2>/dev/null

echo "=== 悪意のある axios バージョン ==="
find ~ -path "*/node_modules/axios/package.json" \
  -exec grep -l '"version": "1.14.1"\|"version": "0.30.4"' {} \; 2>/dev/null

echo "=== litellm_init.pth(存在してはならない) ==="
find ~ -name "litellm_init.pth" 2>/dev/null
Windows(PowerShell)版
Write-Host "=== npm global: axios ==="
npm list -g axios 2>$null

Write-Host "=== npm global: plain-crypto-js ==="
npm list -g plain-crypto-js 2>$null

Write-Host "=== Python: litellm ==="
pip show litellm 2>$null | Select-String "Name|Version"

Write-Host "=== Python: telnyx ==="
pip show telnyx 2>$null | Select-String "Name|Version"

Write-Host "=== plain-crypto-js ==="
Get-ChildItem -Path $HOME -Recurse -Directory -Filter "plain-crypto-js" -ErrorAction SilentlyContinue |
  Where-Object { $_.FullName -match "node_modules" }

Write-Host "=== litellm_init.pth ==="
Get-ChildItem -Path $HOME -Recurse -Filter "litellm_init.pth" -ErrorAction SilentlyContinue

結果の見方

検出内容 対応
plain-crypto-js がどこかに存在 侵害確定。 Part 3 を即実行
axios 1.14.1 / 0.30.4 が存在 侵害確定。 Part 3 を即実行
litellm_init.pth が存在 侵害確定。 Part 3 を即実行
litellm 1.82.7 / 1.82.8 侵害確定。 Part 3 を即実行
telnyx 4.87.1 / 4.87.2 侵害確定。 Part 3 を即実行
axios(安全版)がグローバルツール内に存在 ツールの要否を見直し。npm 非依存の代替を検討
何も検出されない 問題なし。定期的に再実行

Part 6: AI Agent 環境の強化

なぜ AI Agent に特別な注意が必要か

AI コーディングエージェント(Claude Code, Codex, Antigravity 等)は npm installpip install を日常的に実行する。人間なら見慣れないパッケージに気づいて止まるかもしれないが、Agent は躊躇なく実行する。

Agent 指示ファイル対応表

Agent 指示ファイル スコープ
Claude Code CLAUDE.md プロジェクトルート → CWD。~/.claude/CLAUDE.md でグローバル設定も可
Codex(OpenAI) AGENTS.md ~/.codex/ → プロジェクトルート → CWD。階層マージ
Antigravity(Google) AGENTS.md / GEMINI.md v1.20.3+ で AGENTS.md サポート。GEMINI.md 優先
Cursor .cursorrules プロジェクトルート。AGENTS.md も読む

AGENTS.md がクロスツール標準になりつつある。 CLAUDE.md + AGENTS.md の両方に同一のルールを記載するのが最も確実。

👉 テンプレート: templates/CLAUDE.md / templates/AGENTS.md

多層防御の構成

レイヤー 機能 防御対象
Agent 指示(CLAUDE.md / AGENTS.md) pnpm 使用、ハッシュ要求、人間承認を指示 Agent が誤ったツール選択 / 自律的にインストール
.npmrc ignore-scripts=true lifecycle scripts をブロック Agent が指示を無視して npm を実行
pip.conf require-hashes + only-binary 未検証 pip install をブロック 未検証 Python パッケージのインストール
Corepack packageManager pnpm 利用を促進(完全ブロックではない — CI で補完) Agent が npm にデフォルト
pnpm onlyBuiltDependencies(v10+) 承認済みパッケージのみ scripts 許可 未承認パッケージの postinstall
Human-in-the-Loop 人間が lockfile 変更前に承認 ゼロデイ攻撃

Corepack の注意点: npm はデフォルトで Corepack の shim 対象ではない。packageManager: "pnpm@..." は強い運用上のシグナルだが、npm 実行の完全遮断策ではない。CI で package-lock.json の存在を検出してエラーにするなど、追加のチェックで補完。

👉 設定ファイル: templates/.npmrc / templates/pip.conf

Part 7: 監視・継続運用

予防策は一度設定して終わりではない。

lockfile 変更には PR レビューを必須にする

package-lock.json, pnpm-lock.yaml, requirements.txt, composer.lock のすべての変更は PR でレビュー。ブランチ保護ルールで少なくとも1名の承認を要求。

新規依存の承認プロセス

Dependabot / Renovate の自動マージは禁止。PR のオープンのみに設定し、以下を手動レビュー:

  • 新しい transitive dependency の出現
  • 複数パッチをスキップするバージョンジャンプ
  • lifecycle scripts を突然追加した依存

SBOM の生成

syft dir:. -o spdx-json > sbom.json

ビルドごとに生成し、ビルドアーティファクトと一緒に保存。

Provenance / Attestation の定期検証

npm audit signatures
gh attestation verify <artifact> --owner <org>

以前 provenance を持っていたパッケージが突然なくなった場合は高優先度アラート。

定期監査

npm audit --audit-level=high
pip-audit
composer audit

参考情報

axios:

TeamPCP:

テンプレート:

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?