4 ポイント 投稿者 GN⁺ 2025-12-15 | 3件のコメント | WhatsAppで共有
  • Shai-Hulud 2.0 の悪意ある npm パッケージが開発者マシンを感染させ、Trigger.dev の GitHub 組織アクセス権を奪取した事件が発生
  • 感染は開発者が pnpm install を実行した際、悪意あるパッケージの preinstall スクリプトが実行されることで始まり、TruffleHog ツールを用いて認証情報を窃取
  • 攻撃者は17時間にわたり 669個のリポジトリを複製し、その後10分間で 199個のブランチへの強制プッシュと42件のPRクローズを試行
  • パッケージと本番システムは損なわれておらず、攻撃は4分で検知されてアカウントアクセスは遮断された
  • 事件後、npm スクリプトの無効化、pnpm 10 へのアップグレードOIDC ベースの npm 配布ブランチ保護の全面適用など、セキュリティ体制を強化

攻撃の概要

  • 2025年11月25日、内部 Slack でのデバッグ中に、Linus Torvalds 名義の「init」コミットが複数のリポジトリで作成される異常な兆候が発生
  • 調査の結果、Shai-Hulud 2.0 サプライチェーンワームが開発者マシンを感染させ、GitHub 認証情報を窃取していたことが確認された
  • このワームは500個以上の npm パッケージを感染させ、25,000個以上のリポジトリに影響を与えたと報告されている
  • Trigger.dev の公式 npm パッケージ(@trigger.dev/*、CLI)は感染していない

攻撃タイムライン

  • 11月24日 04:11 UTC: 悪意あるパッケージの配布開始
  • 20:27 UTC: ドイツの開発者マシンが感染
  • 22:36 UTC: 攻撃者が初回アクセスし、大量のリポジトリ複製を開始
  • 15:27〜15:37 UTC(11月25日): 10分間にわたり破壊的攻撃を実行
  • 15:32 UTC: 異常を検知し、4分以内にアクセスを遮断
  • 22:35 UTC: すべてのブランチの復旧完了

感染の過程

  • 開発者が pnpm install を実行すると、悪意あるパッケージの preinstall スクリプトが実行され、TruffleHog をダウンロードして実行
  • TruffleHog は GitHub トークン、AWS 認証情報、npm トークン、環境変数などをスキャンして外部へ流出させた
  • 感染したマシンから .trufflehog-cache ディレクトリと関連ファイルが発見された
  • 感染原因となったパッケージは削除されており、追跡は不可能

攻撃者の活動

  • 感染後17時間にわたり 偵察活動を継続
    • 米国およびインドのインフラを利用して669個のリポジトリを複製
    • 開発者の活動を監視し、GitHub トークンによるアクセスを維持
    • 「Sha1-Hulud: The Second Coming」という名前のリポジトリを作成し、認証情報保存に使われたとみられる
  • その後10分間で 破壊的行為を実行
    • 16個のリポジトリで199個のブランチへの強制プッシュを試行
    • 42件の PR をクローズし、一部はブランチ保護設定によって阻止された
    • すべてのコミットは「Linus Torvalds <email> / init」の形式で表示

検知と対応

  • Slack アラートを通じて異常な兆候をリアルタイムで検知
  • 4分以内に感染アカウントの GitHub アクセスを遮断し、その後 AWS・Vercel・Cloudflare などすべてのサービスへのアクセスを取り消し
  • AWS CloudTrail ログの分析結果では、読み取り専用 API 呼び出しのみが存在し、本番データへのアクセスはなかった
  • AWS は別途 Shai-Hulud 関連の疑わしい挙動を検知し、警告を送信

被害と復旧

  • 669個のリポジトリ複製199個のブランチへの強制プッシュ42件の PR クローズ
  • GitHub のサーバー側 reflog が存在しないため復旧は困難だったが、イベント API とローカル reflogを活用して7時間以内に全面復旧
  • npm パッケージと本番インフラは損なわれていない

GitHub App キーの露出

  • 調査中、開発者ノートPCのゴミ箱から GitHub App の秘密鍵が発見された
  • この鍵は顧客リポジトリに対して read/write 権限を持っており、ただちにローテーション措置を実施
  • データベース(インストール ID 保存)は損なわれておらず、顧客リポジトリへのアクセスの証拠はないが、完全には排除できない
  • GitHub サポートチームに追加ログを要請し、顧客にはメールで告知を送付

Shai-Hulud の技術分析

  • setup_bun.js 実行時に Bun ランタイムをインストールし、バックグラウンドで bun_environment.js を実行
  • TruffleHog を使って $HOME ディレクトリ内の認証情報を収集
  • 収集したデータ(contents.jsoncloud.jsontruffleSecrets.json など)を ランダムな GitHub リポジトリへ3重 base64 エンコードの形でアップロード
  • npm トークンが存在する場合、感染したアカウントのパッケージを改変・再配布してワームを拡散
  • 認証情報がない場合は ホームディレクトリの削除を試行
  • 感染指標ファイル: setup_bun.jsbun_environment.js.trufflehog-cache/ など

セキュリティ強化措置

  • npm スクリプトを全面的に無効化ignore-scripts=true
  • pnpm 10 にアップグレード: スクリプトをデフォルトで無効化し、minimumReleaseAge(3日)設定で新規パッケージのインストールを遅延
  • OIDC ベースの npm Trusted Publishers を導入して長期トークンを排除
  • すべてのリポジトリにブランチ保護を適用
  • AWS SSO に Granted を導入し、セッショントークンを暗号化
  • GitHub Actions で外部コントリビューターのワークフロー実行時に承認必須へ変更

他チームへの教訓

  • npm インストール時に実行される 任意コード実行の仕組み自体が攻撃面である
  • ignore-scripts=true の設定と、必要なパッケージだけをホワイトリスト管理することが必要
  • pnpm minimumReleaseAge によって新規パッケージのインストールを遅延
  • ブランチ保護OIDC ベースのデプロイは必須のセキュリティ対策
  • ローカルマシンに長期認証情報を保存せず、CI 経由のデプロイのみを許可すべき
  • Slack アラートのノイズが検知の鍵となった

人間的側面

  • 感染した開発者に落ち度はなく、単に npm install を実行しただけで被害が発生した
  • 攻撃中、そのアカウントが数百個のランダムなリポジトリに自動で「star」を付けた痕跡も見つかった
  • この事件は個人のミスではなく、エコシステムの構造的脆弱性を浮き彫りにした

要約指標

  • 初回感染から最初の攻撃まで: 約2時間
  • 攻撃者のアクセス維持時間: 17時間
  • 破壊行為の継続時間: 10分
  • 検知まで5分、遮断まで4分
  • 全面復旧完了まで7時間
  • 複製されたリポジトリ: 669個 / 影響を受けたブランチ: 199個 / クローズされた PR: 42件

参考リソース

  • Socket.dev: Shai-Hulud Strikes Again V2
  • PostHog、Wiz、Endor Labs、HelixGuard の分析レポート
  • npm Trusted Publishers、pnpm onlyBuiltDependenciesminimumReleaseAge、Granted ドキュメント

3件のコメント

 
click 2025-12-15

pnpm はデフォルトで post-install を個別に許可しなければならない仕組みだったはずですが、結局は開発者も無意識のうちに許可してしまうようですね

 
lamanus 2025-12-16

npm はデフォルトで実行されるため、pnpm に切り替えてデフォルトで無効化するように変更し、セキュリティを強化したという理解です。

 
GN⁺ 2025-12-15
Hacker Newsの意見
  • npm install を実行すること自体は 怠慢 ではない
    問題は、パッケージのインストール時に 任意コード実行を許してしまうエコシステム にある
    しかし根本的なセキュリティ上の失敗は、第三者が何の検証もなく自分の製品にコードを流し込めるパッケージマネージャを使っていることだ
    結局のところ、私たちはパッケージマネージャとその運営者の善意と能力に無限に依存している
    それに OP が認証情報を平文でファイルシステムに保存していたことを示唆しているようにも見える

    • どちらも問題だと思う
      言語レベルで、コードが入力を読み取り、リソースを消費し、型的に正しい出力だけを生成するよう制限する構造は作れる
      サプライチェーン問題の完全な解決にはならないが、露出範囲はかなり小さくなる
    • こういう論理はあまりに循環的だ
      「一人がこうしたツールを使うのは悪くないが、みんなが使うとエコシステムが問題になる」という話になっている
      多くの開発ツールが セキュリティ的に脆弱 だということは、すでに何度も証明されている
      本当に気にしているなら、行動で示すべきだ
    • IDE プラグインも同じだ
      VS Code を使っていたとき、ちょっとした機能を追加するにも、誰が作ったのかも分からないプラグインを入れなければならず不便だった
    • 第三者コードの実行を防ぐパッケージマネージャをどう設計できるのか気になる
      結局 信頼するしかないコード を実行する構造になるのではないかと思う
    • 一部のツールは HTTP 認証に netrc ファイルしか対応していない
      git を HTTP で使うなら、この種の 平文認証情報の露出経路 はほぼ常に存在する
  • pnpm のメンテナが 1 年前に「post-install スクリプトをデフォルトでブロック しよう」と提案していた
    ユーザーにとっては不便になるだろうが、長期的には誰もがありがたく思う変更だと信じていた
    関連 PR: pnpm/pnpm#8897

    • それでもなお同じ問題が繰り返されている
      結局 利便性がセキュリティに勝った また一つの事例だ
  • 「データベースは侵害されなかった」と言っているが、攻撃者が AWS とシークレットにアクセス していたなら、すでに侵害されたと見るべきだ
    アクセス可能性があったなら侵害と見なすべきだ

    • AWS リソースのアクセスログがあり、権限取り消し前にアクセスの痕跡がなければ、データは安全だったと見てよい
  • マルウェアが実行された後では、出所の追跡はほぼ不可能
    pnpm install も正常に完了するので検知しにくい
    Sentinel One や CrowdStrike のような EDR があれば、調査の手がかりはもっと多かったはずだ

    • EDR があれば Trufflehog の攻撃チェーンを検知または遮断できた可能性が高い
  • 「合計 669 個の repo をクローンした」という部分が目についた
    従業員が 100 人にも満たない会社が 600 を超える repo を持っているのが普通なのか気になる

    • 完全に普通だ。repo は家畜であってペットではない
    • うちの組織は 7 人だが、GitHub に 365 個の repo がある
      チーム規模よりも 年数とプロジェクト寿命 のほうが repo 数に大きく影響する
    • マイクロサービス好きのアーキテクトがいれば、こういう結果になる
  • pnpm はすでに preinstall のような ライフサイクルスクリプトの自動実行を停止 していたので、古いバージョンを使っていたようだ
    関連 PR 参照

    • 記事の最後で最新のメジャーバージョンに更新したと言及している
    • それが pnpm を使う主な理由だと思っていたので混乱する
    • 結局 古いバージョンのパッケージマネージャで依存関係を更新 していたのだとすれば、これは彼らの責任だ
    • プロジェクト自体に postinstall スクリプトがあった可能性もある
      pnpm は依存関係のスクリプトは防ぐが、プロジェクトレベルのスクリプトは依然として実行する
  • 透明性のある 事後分析(post-mortem) の共有に感謝する
    こうした事例は業界全体にとって重要だ
    攻撃トラフィックが通常の開発トラフィックと区別可能だったのか気になる
    こちらでも dev 環境で egress フィルタリング を強化しようとしているが、npm install が頻繁に壊れるので悩ましい

    • GitHub 組織の IP 許可リスト機能 を使えば、この種の攻撃の防御に役立ちそうだ
  • 個人ノート PC の git セキュリティについて考えている
    今は SSH キーをローカルに置いて push している
    管理者権限もあるので危険だ。もっと安全にする方法が知りたい

    • 1Password を使って SSH キーと Git 署名を管理し、GitHub OAuth や CLI ログインで push/pull する構成を勧める
      こうすると 署名キーとアクセスキーを分離 でき、管理者アカウントも別管理にできる
      関連文書: 1Password SSH Agent, Git Commit Signing, GitHub OAuth, GitHub CLI Login
    • 私は SSH 秘密鍵を TPM に保存 し、PKCS11 経由で SSH agent から使っている
      キーを外部に流出させられないという利点はあるが、マルウェアが自分のマシン上で動けば依然として危険だ
      Linux の例, macOS の例
    • ノート PC が 感染したら防御手段はない
      TPM や Yubikey で多少難しくはできても、完全な防御は不可能だ
      管理者作業は専用の別マシンで行うのが安全だ
    • Yubikey に GPG キーを入れ、gpg-agent で SSH 認証を行う方法もある
      pushcommit 時に PIN 入力でロック解除する
    • main ブランチへの直接 push を防ぎ、MFA を必須化 すれば、攻撃者がすぐにデプロイブランチへアクセスするのは難しくなる
  • Torvalds 名義のコミットは、感染後によく見られる 目印(signature) だった
    Microsoft の 公式分析記事 でも言及されている
    このワームは非常に騒々しく、一部の攻撃者は露出した認証情報を使って 非公開 repo を公開したり README を改変 したりして宣伝目的に悪用していた

  • 攻撃者が破壊行為をせず 静かに情報だけを流出 させていたら、こうした検知が可能だったのか疑問だ