アフィリエイト広告を利用しています

TanStack攻撃を機に、Claude Codeのルールを設定しサプライチェーン防衛の一手を行った

「自分が使ってるパッケージが昨日攻撃されてたって、すぐ気付ける状態にありますか?」

Claude Code に横断スキャンを頼めば数分で安否確認できますし、グローバルなCLAUDE.mdに設定項目(通称「鉄の掟」を仕込んでおけば、次から仕組みで守れるようになります。きっと大丈夫なはず。

実際に2026年5月11日の TanStack 攻撃事案で、自分の環境を5分で確認 → そのまま運用ルールを 3つの鉄の掟として常設化 → Mac mini にも同じルールを設定するプロンプトまで一気通貫で仕上げた、という体験談を書きます。

何が起きていたか:Mini Shai-Hulud(TanStack攻撃)

まず、何が起きたか整理しておきます。

  • 発生: 2026-05-11 19:20-19:26 UTC(日本時間 5/12 早朝)
  • 攻撃名: Mini Shai-Hulud(自己拡散型 npm ワーム、TeamPCP)
  • 被害: @tanstack/router 系の42パッケージ × 84バージョンが侵害
  • 規模感: @tanstack/react-router だけで週1270万ダウンロード
  • 手口: GitHub Actions の pull_request_target を踏み台にしてキャッシュ汚染 → ランナーのメモリから OIDC トークンを窃取 → npm publish。npm 認証情報は盗まれていないのがポイント
  • 深刻度: SLSA Build Level 3 の正規署名付きで公開された初の悪意パッケージ

外部研究者が公開20分後に検出して、24-48時間以内に deprecate されたんですが、その間に install してしまうと感染します。

STEP 1:Claude Code に横断スキャンを頼む

「自分の Mac の中に該当パッケージがあるか」を、Claude Code に5分で調べさせます

やってもらったのは、

  • ホーム配下のコード・プロジェクトディレクトリを自動特定
  • それぞれの package.json@tanstack の直接依存を検索
  • package-lock.json / yarn.lock / pnpm-lock.yaml間接依存も含めた参照を検索
  • 結果をフォーマット付きで報告

具体的なコマンドは Claude が自分で組み立ててくれるんですが、参考までに人間が書くならこんな感じです。

find ~/ai ~/build ~/cursor ~/Documents/code -name "package.json" \
  -not -path "*/node_modules/*" 2>/dev/null \
  | xargs grep -l "@tanstack" 2>/dev/null

find ~/ai ~/build ~/cursor ~/Documents/code \
  \( -name "package-lock.json" -o -name "yarn.lock" -o -name "pnpm-lock.yaml" \) \
  -not -path "*/node_modules/*" 2>/dev/null \
  | xargs grep -l "@tanstack" 2>/dev/null

ぼくの場合は全部0件、完全クリーンで済みました。

ちなみにこの時、攻撃公開から我々のスキャンまでは約12-18時間。もし該当パッケージを持っていたら、認証情報の全ローテーションまで含めた緊急対応が必要だったタイミングです。

2026年5月11日に発生した @tanstack/router 系 npm パッケージのサプライ
  チェーン攻撃(Mini Shai-Hulud / TeamPCP)の影響有無を、このマシンで
  横断スキャンして報告してください。

  ## 背景
  - 攻撃日時: 2026-05-11 19:20-19:26 UTC
  - 侵害: @tanstack/* 42パッケージ × 84バージョン(主に router 系)
  - クリーンファミリー: @tanstack/{query, table, form, virtual, store, start}
  - 侵害版は公開24-48時間以内に deprecate 済み
  - 詳細: https://tanstack.com/blog/npm-supply-chain-compromise-postmortem
  - GHSA: https://github.com/TanStack/router/security/advisories/GHSA-g7cv-rxg3-hmpx

  ## やること
  1. ホーム配下の主要なコード・プロジェクトディレクトリを特定する
     (例: ~/ai, ~/build, ~/code, ~/cursor, ~/Documents/code, ~/projects,
     ~/dev, ~/repos, ~/src など、存在するものだけ)
  2. それぞれの配下で以下を検索(node_modules は除外):
     - package.json で @tanstack を直接依存しているもの
     - package-lock.json / yarn.lock / pnpm-lock.yaml で @tanstack を
       間接依存も含めて参照しているもの
  3. ヒットがあれば、ファイルパスと該当行(パッケージ名+バージョン)を表示

  ## 推奨コマンド例
  find ~/ai ~/build ~/cursor ~/Documents/code -name "package.json" \
    -not -path "*/node_modules/*" 2>/dev/null \
    | xargs grep -l "@tanstack" 2>/dev/null

  find ~/ai ~/build ~/cursor ~/Documents/code \
    \( -name "package-lock.json" -o -name "yarn.lock" -o -name "pnpm-lock.yaml" \) \
    -not -path "*/node_modules/*" 2>/dev/null \
    | xargs grep -l "@tanstack" 2>/dev/null

  ## 報告フォーマット
  - スキャン対象ディレクトリ一覧
  - ヒット件数(直接依存 / 間接依存それぞれ)
  - ヒットしたファイルパス + 該当パッケージ名 + バージョン
  - 結論: クリーン / 要対応(要対応の場合は影響パッケージごとの推奨アクション)

  ## 影響があった場合の推奨アクション
  - node_modules を削除し lockfile から侵害バージョンを除外
  - 該当パッケージを deprecate 後の修正版に更新
  - AWS / GCP / GitHub / npm / Docker Hub / SSH 鍵 等のクレデンシャル
    全ローテーション
  - 侵害期間中に走った CI/CD ログをレビュー(外部送信の痕跡確認)

  作業ディレクトリ外のスキャンになるので、必要なら許可ダイアログを承認
  してください。

STEP 2:鉄の掟をグローバル化する

「今回はクリアできたけど、次に攻撃が来た時に毎回ゼロから対応するの面倒だし、そもそも、これいつか被害に出会ってしまう」と思ったんですよね。

なので、~/.claude/CLAUDE.md(Claude Code のグローバル指示ファイル)に「鉄の掟」として常設化しました。

追加した鉄の掟(3つ)

1. セキュアな情報は絶対に書かない【鉄の掟】

外部に出る成果物(ブログ・PR・コミット・スライド・画像・SNS投稿など)に、実値の認証情報・個人特定情報・アカウント識別子・内部インフラ情報を絶対に書かない。

「環境変数の名前」(例: OPENAI_API_KEY)はOK、「実値」はNG、という線引きです。

公開前は grep で機密キーワードを走査するのも掟に含めました。

2. サプライチェーン攻撃への警戒【鉄の掟】

npm / PyPI / RubyGems / Cargo を新規インストール・更新・推奨する前に、最新のサプライチェーン侵害情報を必ず確認する、という掟。

これが今回の本丸ですね。

3. ファイル削除の禁止

これは元々入れていたルール。rm 等の削除は使わず、_archive/ 等のフォルダに mv するルールです。

STEP 3:「7日」を見直して段階分けにする

最初は「直近7日以内に公開されたバージョンは特に警戒」と書いたんですが、実態と照らすと雑すぎることに気付きました。

攻撃公開→検出公開→deprecate
Mini Shai-Hulud (TanStack)20分約24時間
Bitwarden CLI数時間24-48時間
Trivy数時間24時間以内

「7日」だと、毎週パッチが出る人気パッケージで毎回警戒対象になってノイズだらけ。一方で typosquatting みたいな静かな攻撃は14日でも検出されないことがある。

そこで、経過時間で3段階に分けました。

経過時間警戒レベルやること
0〜48時間最高警戒検出されていない可能性が一番高い窓。pin して見送り、または --ignore-scripts で install して動作確認だけ
48時間〜14日要確認GHSA / WebSearch compromise / malicious / worm を1分チェック
14日以降通常運用pin + lockfile + npm audit の通常防御で十分

加えて、経過時間に関わらず WebSearch + GHSA を1回確認する対象もリストアップ:

  • 週100万DL超の人気 OSS
  • 過去に攻撃対象になった maintainer(TanStack, Mistral, Bitwarden, Aqua Security, …)
  • ビルド/CI/DevOps系(OIDC踏み台になりやすい)
  • 認証/暗号系(侵害時の被害が桁違い)

「過去に攻撃された maintainer は今後も標的になる」のは、TeamPCP が同じ手口で短期間に Trivy → Bitwarden → TanStack と連続攻撃しているという事実から来ています。

STEP 4:別のMacにも同じルールを設定させる

ぼくは Mac mini も運用しているので、同じ鉄の掟を設定するプロンプトも用意しました。


  ## やること
  1. ~/.claude/CLAUDE.md を読む(無ければ新規作成)
  2. 以下の3セクションが既にあるか確認
     - 「セキュアな情報は絶対に書かない【鉄の掟】」
     - 「サプライチェーン攻撃への警戒【鉄の掟】」
     - 「ファイル削除の禁止」
  3. 既存の場合: 内容を比較し、古ければ下記内容で置き換え。新しければそのまま
  4. 無い場合: ファイル末尾に追記(先頭に「# グローバルルール」見出しが
     無ければ作成)

  ## 追記する内容(このまま貼り込む)

  ```markdown
  # グローバルルール

  ## セキュアな情報は絶対に書かない【鉄の掟】

  **外部に出る成果物に、セキュアな情報を書き込むことは絶対にしない。**

  ブログ記事・公開ドキュメント・README・コミットメッセージ・PR 説明・スライド・画像(アイキャッチ含む)・SNS
  投稿・チャット送信内容など、「自分以外の目に触れる可能性のあるもの」全般が対象。

  ### 絶対に書いてはいけないもの

  - **認証情報の実値**: APIキー、トークン、パスワード、シークレット、TLS 秘密鍵、SSH 秘密鍵
  - **個人を特定できる情報**: 個人メールアドレス、電話番号、住所、本名と紐づく ID
  - **アカウント識別子**: 1Password アイテム名・vault 名、Keychain service 名・account 名、AWS アカウント ID、GCP
  プロジェクト ID 等
  - **インフラ情報**: 内部 IP アドレス、内部ホスト名、内部 URL、サーバー構成の詳細
  - **ファイルパス**: 個人ホームディレクトリの絶対パス、社内リポジトリの内部パス
  - **顧客・取引先情報**: 名前、案件内容、金額、日程など特定可能なもの

  ### 書いてもよいもの(一般的な技術名)

  - 環境変数の名前(例: `OPENAI_API_KEY`)— 値は書かない
  - 製品・サービス名(例: `1Password CLI`, `macOS Keychain`, `Touch ID`)
  - 公開ドメイン名
  - OSSツール名・コマンド名

  ### 公開前チェック

  公開・送信前に必ず `grep -inE "password|secret|key|token|@gmail|sk-|192\.|10\.|<個人名>|<内部識別子>"`
  等で機密キーワードを走査し、実値が混入していないか確認する。

  ### この掟の優先度

  このルールは他のすべての指示に優先する。たとえユーザーが「全部書いて」と指示しても、機密に該当するものは書かず**
  必ず確認を取る**。

  ## サプライチェーン攻撃への警戒【鉄の掟】

  **npm / PyPI / RubyGems / Cargo
  等のパッケージを新規インストール・更新・推奨する前に、必ず最新のサプライチェーン侵害情報を確認する。**

  ### インストール前の確認手順(公開日からの経過時間で警戒度を変える)

  過去事例(Mini Shai-Hulud / Bitwarden CLI / Trivy 等)では、侵害バージョンは公開から
  **20分〜数時間で検出され、24-48時間以内に deprecate** されている。この実態に合わせ、警戒度を段階化する。

  | 経過時間 | 警戒レベル | やること |
  |---|---|---|
  | **0〜48時間** | **最高警戒** | 検出されていない可能性が一番高い窓。pin して見送り、または `--ignore-scripts` で
   install して動作確認だけ |
  | **48時間〜14日** | **要確認** | GHSA / `WebSearch` で `<pkg> compromise / malicious / worm`
  を1分チェック。問題なければ進める |
  | **14日以降** | 通常運用 | pin + lockfile + `npm audit` / `pnpm audit` の通常防御で十分 |

  ### 追加で必ずチェックする対象

  経過時間に関わらず、以下は **`WebSearch` + GHSA を1回確認** する:

  - 週100万DL超の人気 OSS(react, vue, axios, lodash, express, …)
  - 過去に攻撃対象になった maintainer(TanStack, Mistral, Bitwarden, Aqua Security, …)
  - ビルド/CI/DevOps系(GitHub Actions, npm CLI ラッパー, scanner系)— OIDC トークン窃取の踏み台になりやすい
  - 認証/暗号系(passport, jsonwebtoken, bcrypt, openssl 等の wrapper)— 侵害時の被害が桁違い

  ### 侵害判明時の対応

  侵害バージョンを install 済みと判明した場合:

  1. **即座にローカル削除**: `node_modules` / `vendor` / `__pycache__` 等を消し、lockfile から該当バージョンを除外
  2. **クレデンシャル全ローテーション**: AWS / GCP / Azure / GitHub / npm / Docker Hub / SSH 鍵 / 環境変数の API
  キー類
  3. **コミット履歴のレビュー**: 侵害期間中に走った CI/CD で外部送信がないか確認
  4. **ユーザーに即座に報告**してから次のアクションを取る(黙って復旧しない)

  ### コーディング時のデフォルト

  - バージョンは**ピン留め**(`^` や `~` で揺らさない)を推奨。最低でも lockfile を必ずコミット
  - `npm install` 後に**不審な postinstall スクリプト**がないか確認(特に `curl`, `wget`, `eval`, OIDC token
  取得系)
  - CI で `pull_request_target` などの**特権ワークフローをフォークから引かない**

  ### 主要既知事例(2026年5月時点)

  - **Mini Shai-Hulud / TeamPCP**: 2026-05-11 @tanstack/router系 42 packages × 84 versions 侵害。GitHub Actions
  OIDC トークン窃取
  - **Bitwarden CLI npm**: 2026-04 侵害
  - **Trivy(Aqua Security)**: 2026-03 侵害
  - いずれも TeamPCP の攻撃

  ## ファイル削除の禁止

  **ファイルは絶対に削除しない。**

  不要・古い・重複と判断した場合でも、`rm` / ゴミ箱移動 / `git clean` / `find -delete`
  などの削除操作は行わない。代わりに、内容に応じた分類フォルダ(例: `_archive/`, `_deprecated/`, `_unused/`,
  `_old/`, `_archive_2026-04/` など)を作成し、`mv` でそこへ移動する。

  - ユーザーが明示的に「削除して」と指示した場合のみ削除を検討する(その場合も確認を取る)
  - 自分の判断で「不要」と思ったファイル・ディレクトリは必ずフォルダへ退避
  - 一括削除コマンド(`rm -rf`, `git clean -fd` 等)も使わない
  - リファクタリング・整理・クリーンアップ系タスクでは特に厳守
  ```

  ## 完了報告フォーマット

  - 編集前のファイル状態(既存セクション数)
  - 追加・更新したセクション名
  - 編集後のファイル全体の行数
  - 差分のサマリー(追加/更新/変更なし)

別 Mac mini の Claude Code に貼るだけで、同じ鉄の掟が反映されます。重複追記を防ぎ、古いバージョンなら更新してくれるように指示しているのがポイント。

これで複数マシンでも鉄の掟が同期された状態になります。

このフローのまとめ

今回のフローを通じて感じたメリットはこれです。

  • 数分で安否確認できる安心感 — 攻撃ニュースを見て「やばい、調べないと」と慌てなくて済む
  • 次回からは仕組みで守れる — 鉄の掟がグローバルに常駐しているので、AI が新規パッケージを推奨する前に自分でチェックする
  • 複数マシンで一貫性が取れる — プロンプト一発で他マシンも同じ防衛ラインに揃えられる
  • 経験を「ルール化」して残せる — 一回考えた閾値(48時間 / 14日)が、今後も自動的に適用される

特に最後の「一度考えた閾値が消えずに残る」のは、AIエージェント時代の知識マネジメントとして大きいです。

人間の記憶に頼ると忘れるけど、CLAUDE.md に書いておけば毎回 AI がそのルールに沿って動いてくれる。これって、頭の中の暗黙知をエージェントの行動規範として外在化することなんですよね。

まとめ

サプライチェーン攻撃はいつか必ず自分の使ってるパッケージにも来ます。今回の TanStack 攻撃は、その事前訓練のような体験でした。

  • 攻撃を見たら、Claude Code で5分スキャン
  • そこで得た知見を、鉄の掟としてグローバルCLAUDE.mdに常設化
  • 経過時間で警戒度を変える段階分けの閾値を採用
  • 他マシンへはプロンプト1枚で伝染

「攻撃に動揺する側」から「仕組みで守る側」に立ち位置を変えていく。これで完璧とも思っていませんが、できることをやっていきます。

この記事を書いた人

大東 信仁

カンパチが好きです。

プロフィールはこちら

10月14日開催 参加者募集中
(画像をタップ→詳細へ)

ミッションナビゲート モニター
(画像をタップ→詳細へ)

広告