世界を動かす技術を、日本語で。

Keyvと仲間がアクティブな「シャイ・フルード」サプライチェーン攻撃で侵害される

2026年8月4日原文(aikido.dev)

概要

2026年8月4日、npmの人気パッケージ群が GitHubアカウント乗っ取り により大規模な サプライチェーン攻撃 を受け、 2億件超の月間インストール数 を持つパッケージが次々と感染。 攻撃者は 資格情報窃取ワーム を仕込み、npmトークンやAWS、GitHub等の 重要なシークレット情報を盗難。 盗まれた情報は 暗号化されて公開GitHubリポジトリ や専用サーバへ送信。 感染は他のメンテナや組織にも拡大し、 自己増殖型ワーム として数百パッケージに波及。 本稿では、攻撃の流れ・窃取対象・感染手法・検知方法・IOCを解説。

2026年8月4日npmサプライチェーン攻撃の全貌

  • keyv のメンテナの GitHubアカウント乗っ取り による攻撃開始
    • keyv: 約1.27億件/週のダウンロード数を誇るkey-valueストレージライブラリ
    • 他にもcacheable、flat-cache、file-entry-cache等の人気キャッシュ系パッケージも同一メンテナ所有
  • 攻撃手法
    • メインブランチへ直接マルウェアファイルをコミット し即座に新リリース
    • GitHub Actions署名付きnpm公開 で正規リリースとして流通
  • 影響パッケージ例(2026年8月4日時点)
    • keyv 6.0.0、flat-cache 6.1.24、file-entry-cache 11.1.6、cacheable-request 13.0.20等
    • その他、@deliveroo/reevent、@or-sdk/invitations、picasso.js等の有名組織パッケージにも拡大
  • 感染規模
    • 434パッケージ(1,381バージョン) が感染、合計 20億件/月 のインストール数

マルウェアの動作概要

  • 各パッケージに setup.mjs および Math_Symbol.js を新規追加
    • package.jsonのpreinstallスクリプト としてsetup.mjsを登録
    • npm install時にsetup.mjsが自動実行され Bunランタイムをダウンロード、Math_Symbol.jsを実行
  • Math_Symbol.jsの機能
    • 資格情報窃取・暗号化・外部送信・自己増殖
    • 強力な難読化 と多機能なシークレットサーチエンジンを内蔵

窃取対象と手法

  • npmトークン
    • ~/.npmrcやファイルシステム全体からauthTokenを抽出
    • registry.npmjs.org/-/whoamiで 有効性をリアルタイム検証 後、外部送信
  • GitHubトークン
    • PAT(ghp_)、OAuth(gho_)、App(ghs_)、JWT OIDC等の各種トークンを抽出
    • ~/.config/gh/hosts.yml、環境変数、ファイルシステムスキャン
    • GitHub Actionsランナーのメモリからシークレットを直接ダンプ
  • AWS認証情報
    • ~/.aws/credentials, 環境変数、EC2/ECSメタデータ、Secrets Manager等
    • 複数リージョンにわたりsecretsmanager:ListSecretsを実行
  • Kubernetesシークレット
    • /var/run/secrets/kubernetes.io/serviceaccount/からトークン・CA証明書等を取得
    • API経由で全シークレットを列挙
  • HashiCorp Vaultトークン
    • VAULT_TOKEN、~/.vault-token、GitHub Actionsパス、Kubernetes経由、AWS IAM認証等
    • 取得後、全KVストアのシークレットを読み出し
  • Stripe・Slackトークン
    • Stripe APIキー(sk_, pk_)、Slackトークン(xox[baprs]-...)を全ファイルから探索
  • 汎用ファイルスキャン
    • OS別に約200種のglobパターンでシークレットファイルをサーチ
      • .env, .env.*, .envrc, *.pem, *.key, *.kdbx, .ssh/config, .tfvars, docker/config.json等
      • 5MB超のファイルはスキップ、最大64並列で高速スキャン
    • 正規表現による秘密鍵・接続文字列等の自動抽出

情報の外部送信(エクスフィルトレーション)

  • 収集した資格情報は RSA暗号化 後に送信(攻撃者のみが復号可能)
  • 主な送信先
    • "Shai-Hulud: Here We Go Again" という説明文の 公開GitHubリポジトリ
      • 1,300件以上が攻撃者のドロップポイントとして利用
    • 失敗時はhttps://npm-cache[.]com:443/routerへフォールバック
      • このドメインはEthereumスマートコントラクト経由で動的に取得され、攻撃者が随時切替可能

自己増殖型ワームの感染拡大手法

  • npm tarball感染
    • 窃取したnpmトークンで 公開権限のある全パッケージを列挙
    • 現行tarballを取得・改変(preinstall追加、setup.mjsとmath_init.js挿入、パッチバージョン自動増加)
    • 改変済みパッケージを自動公開 し、次世代感染を拡大
      • 2次感染以降はmath_init.jsを使用(オリジナルはMath_Symbol.js)
  • GitHubリポジトリ感染
    • ghs_トークンを使い、 最大50ブランチに自動コミット
    • .claude/settings.jsonや.vscode/tasks.jsonに悪意あるフックを追加
      • VS CodeやClaude Codeセッション開始時に自動実行
    • コミットは claude@users.noreply.github[.]com 名義で「chore: update config」として偽装

検知・防御策(Aikidoの例)

  • Aikido利用者
    • 中央フィードでmalware issuesをフィルタし、 100/100クリティカル問題 として検出
    • 手動再スキャン推奨
  • 未導入の場合
    • 無料プランでリポジトリ連携・マルウェア検知可能
    • Device Protectionでチーム端末全体の依存関係を可視化し、 インストール前ブロック も可能
    • Safe Chain(OSS)でnpm/yarn/pnpmコマンド実行時にリアルタイム検査

IOC(インジケーター・オブ・コンプロマイズ)

  • ファイル
    • setup.mjs(SHA-256: 54dc7ea54a1317cca0e890a2770630cf7fa6c97813e0cb9d2caa93012b350668)
    • setup.mjs(コミュニティ感染版: fd3ca4007b225fdf8de7af4345a19179d5efa8c4bb9205f88cda806e5684b1eb)
    • Math_Symbol.js / math_init.js(SHA-256: 9fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bcc)
  • ネットワーク
    • https://npm-cache[.]com:443/router(エクスフィルトレーション先)
    • eth-mainnet.nodereal[.]io(0xE1f2395ee43e45A1556EC6438a88c31B83493103へのリクエスト)
  • その他
    • 説明文に "Shai-Hulud: Here We Go Again" を含む 公開GitHubリポジトリ

まとめ

  • npmパッケージの サプライチェーンリスク 顕在化
  • 認証情報の多様な窃取・自己増殖型感染 の複雑さ
  • 即時検知・自動化された防御策 の重要性
  • IOCの迅速な共有と監視 による被害拡大防止の必要性

Hackerたちの意見

GitHubが公のリポジトリに対して、明らかに怪しいものをアップロードするアカウントを自動的にロックするシンプルな分類器を作ってないのはちょっと驚きだな。少なくともリポジトリが公開される前に、自分のためにもそうした方がいいのに。GitHubのソフトウェアなら、インターンでも1日で80/20のものを作れるんじゃない?AIの支出を有効に使ういい方法だと思うけど。

GitHubが公のリポジトリに対して、明らかに怪しいものをアップロードするアカウントを自動的にロックするシンプルな分類器を作ってないのはちょっと驚きだな。少なくともリポジトリが公開される前に、自分のためにもそうした方がいいのに。もしかしたら、それがアイデアなのかもね。よろしく。

GitHubがこれを発表したのは少し前だよね: https://github.blog/changelog/2026-07-28-npm-publish-time-ma...

現時点で、以前はなかったプレインストールフックを追加するパッケージは、拒否されるべきだし、かなり疑わしい目で見られるべきだね。プレインストールやポストインストールのフックはもう終わりにしよう。新しいものは一時停止から始めるべきだ。

確か、pnpmはデフォルトでそれを許可してないはず。でも、もしそれを排除しても、マルウェアが他の何かにフックする可能性や、CLIアプリケーションでしか動作しない可能性は残るよね。

でも、彼らはindex.jsにドロッパーとかを入れれば、インストール時ではなくインポート時に実行されるよね?最初のインストール時は、特権のある開発者のマシンであることが多いし、NodeやBun、Denoのような「サーバー」ライクなランタイムで実行されるだろうけど。プレインストールスクリプトをブロックするのは基本的な応急処置だよ。

結局、みんな./configureスクリプトとかを実行することになるだけだよ。今のところ私がたどり着いた解決策は、1. Rustコードのビルドスクリプトやprocマクロを監査して(cargo-vetでマークする)。2. 「ビルド/テスト/一時的な場所にアーティファクトをプッシュする」ための隔離されたワークフローを持つ(s3、GitHubアーティファクト、何でも)。このワークフローにはAPIキーは入れない。3. アーティファクトを取得してレジストリに配置するためのAPIキーを持つ別のワークフローを作る。これで「コードがここで実行される」と「環境に特権がある」の明確な分離ができる。私のスロップ駆動のプログラミング言語では、ビルドスクリプトがその機能を前もって宣言するから、静的にそれについて考えることができる(ランタイムの権限も同様に)。

誰か、node_modules(またはpnpmストア)の膨大なファイルの中でこれがどこかに表示されているか確認するためのgrepか何か持ってない?

「何が起こったか」のセクションでは、setup.mjsMath_Symbol.jsの追加、さらにpackage.json"preinstall": "node setup.mjs"を追加する変更が言及されてるから、これらをチェックするのが良い指標になると思う。例えば、こんな感じで探してみて:find . -type f | grep -P "/Math_Symbol.js$"

find . -type d -name node_modules -prune -exec find {} ( -name setup.mjs -o -name math_init.js -o -name Math_Symbol.js ) ; 2>/dev/null

この記事にはたくさんの情報とチェック・クリーン方法が載ってるよ: https://safedep.io/keyv-npm-supply-chain-compromise/

速度を考えるとfdを強くおすすめするよ:fd -HI "^(setup.mjs|Math_Symbol.js|math_init.js)$" 1. https://github.com/sharkdp/fd 2. brew install fd

Hacker Newsで議論の続きを見る