Skip to main content

「Mini Shai-Hulud」が出現:Bunベースの窃取型マルウェアがSAPの@cap-jsおよびmbt npmパッケージを標的に

2026年4月29日

0 分で読めます

2026年4月29日、攻撃者はSAP開発エコシステムのnpmパッケージ4つに、悪意のあるバージョンを公開しました。mbt、@cap-js/db-service、@cap-js/sqlite、@cap-js/postgresです。侵害された各リリースにはpreinstallフックが含まれており、GitHub ReleasesからBun JavaScriptランタイムをダウンロードして、約11.6 MBの難読化された認証情報窃取マルウェアを実行します。

ペイロードにはハードコードされた説明文「A Mini Shai-Hulud has Appeared」が埋め込まれており、侵害された開発者のマシンが各自のアカウントに使い捨てリポジトリを作成するにつれて、この文字列が公開GitHub検索結果にリアルタイムで現れています。このキャンペーンはShai-Huludの名前を再利用しており(使い捨てリポジトリにもこの名前が付けられています)、StepSecurityによる完全な難読化解除の結果、機能するnpm自己拡散コードも含まれていることがわかりました。記事公開時点で実際に確認されているのは、最初に侵害された4つのパッケージのみです。技術的な分析と、最初の公開を可能にした侵害済みnpmアカウントについて、以下で詳しく説明します。

Snykは侵害された4つのバージョンすべてについてアドバイザリを公開しました。影響を受けるリリースはsnyk testで検出され、各パッケージのSnyk Security Databaseページにも表示されます。

影響を受けるパッケージとSnykアドバイザリ

パッケージ

侵害されたバージョン

Snykアドバイザリ

週あたりのダウンロード数(概数)

mbt

1.2.48

約52,000

@cap-js/db-service

2.10.1

約260,000

@cap-js/sqlite

2.2.2

約250,000

@cap-js/postgres

2.2.2

約10,000

週あたりのダウンロード数は、侵害前の週(2026年4月22日~28日)におけるnpmレジストリの公開ダウンロードAPIのデータです。4つのパッケージはいずれもSAP Cloud Application Programming Modelのツールチェーンに属します。mbtは、SAPクラウドアプリケーションのデプロイ用アーカイブをビルドする、npmで配布されるCloud MTA Build Toolです。@cap-js/*パッケージは、CAPアプリケーション向けのデータベースサービスを提供します。

悪意のあるバージョンは、2026年4月29日の短い時間帯にすべて公開されました(時刻はすべてUTC)。タイムスタンプはregistry.npmjs.orgとGitHub APIで直接確認しています。

  • 09:55:25:npmアカウントcloudmtabotからmbt@1.2.48が公開。

  • 10:01:07:最初の被害者の使い捨てリポジトリがGitHubに出現(GitHub APIのタイムスタンプによるとgruposbftechrecruiter/siridar-navigator-935)。

  • 11:25:47:@cap-js/sqlite@2.2.2が公開。

  • 12:03 to 12:04:StepSecurityがcap-js/cds-dbs#1588とSAP/cloud-mta-build-tool#1224で情報開示のIssueを提出。3件目の独立した開示として、longieirlがSAP/open-ux-tools#4616を14:02に提出。

  • 12:14:00:@cap-js/postgres@2.2.2と@cap-js/db-service@2.10.1が公開。

  • 13:31:cap-jsのメンテナーchgeoが返信:「お知らせいただきありがとうございます。最優先でパッケージを整理し、根本原因を調査します。」

  • 13:46:SAPがGitHub ActionsのOIDC信頼済みパブリッシャーcap-npmを通じて、インシデント後のクリーンなバージョンを公開。@cap-js/db-service@2.11.0、@cap-js/sqlite@2.4.0、@cap-js/postgres@2.3.0(調整に合わせて@cap-js/hana@2.8.0も更新)。

  • 14:02:50:SAPのエンジニアpatricebenderがcap-js/cds-dbsのPR #1592を提出。手動承認環境を通さないとnpmに公開できないよう変更し、前述の根本原因に関する記述をそのまま引用。

  • 14:24:cloud-mta-build-toolのコラボレーターkbarnoldが返信:「ご報告ありがとうございます。最優先で対応しています。」

@cap-js/sqlite@2.2.2は検出後まもなくnpmから非公開化されました。残る悪意のあるバージョンには、npmの非推奨メッセージが付いています。mbt@1.2.48には「SECURITY: This version contains malicious code. Do not use.」と表示され、@cap-js/*の悪意のあるバージョンには「DO NOT USE. This version contains unknown content.」と表示されます。特に注意が必要なのは、執筆時点でmbt@1.2.48がmbtのlatest dist-tagに設定されたままで、修正済みのmbtバージョンがまだ公開されていなかったことです。そのため、単純なnpm install mbtでも悪意のあるtarballがインストールされます。公開時点で、4つのパッケージのいずれにもCVE、GHSA、OSVの記録は割り当てられていませんでした。権威ある公開情報源は、本記事で引用しているベンダーのブログ4件とGitHubの情報開示Issue 3件のみです。

「Mini」Shai-Huludと呼ばれる理由(そして実際の違い)

npmサプライチェーンのインシデントでShai-Huludという命名が使われたのは、今回が初めてではありません。2025年9月の最初のShai-Huludキャンペーンでは、@ctrl/tinycolor、ngx-bootstrap、ng2-file-uploadと、多数の依存パッケージが被害を受けました(Snykのゼロデイ脆弱性レポートで発生状況を追跡しています)。2025年11月の次の波であるSHA1-Huludでは、Zapier、PostHog、Postmanのリリースを含む、600を超える個別パッケージに被害が広がりました。KasperskyのSecurelistチームは、これら2つの過去の波を独自に技術分析し(検出名HEUR:Worm.Script.Shulud.gen)、securelist.com/shai-hulud-worm-infects-500-npm-packagesおよびsecurelist.com/shai-hulud-2-0で公開しています。

A Mini Shai-Hulud Has Appeared": Bun-Based Stealer Hits SAP @cap-js and mbt npm Packages

Shai-Hulud NPM攻撃:Snykによる修復(SnykのCLIとSnyk Advisorのページを使い、プロジェクト内のShai-Huludの影響を受けた依存関係を特定して修正する短い解説)。

過去の2つのキャンペーンでは、ワームのような挙動が確認されています。ペイロードは被害者のnpmトークンを窃取し、そのトークンで書き込み権限のある他のすべてのパッケージに自らを公開していました。世間の注目度もそれに応じて高まりました。2025年11月のSHA1-Hulud開示時には、サンドワームに関するWikipedia記事の閲覧数が2,772回に達し、16か月分のデータで1日あたりの最多を記録しました(記事の平均のおよそ4倍)。また、より広範な「サプライチェーン攻撃」のWikipedia記事は、Mini Shai-Huludが発生した2026年4月に月間平均閲覧数の記録を更新しました(1日310回、Wikimedia REST APIによる)。

4月29日のキャンペーンはShai-Huludのブランド名を再利用しています(使い捨てリポジトリには説明文の文字列が名前として付けられています)が、現時点で公開されている証拠からは、挙動がより限定的であることが示されています。

  • 認証情報の窃取:複数の研究者が確認し、詳細を報告しています。

  • 開発者ツールの設定への永続化コードの注入:新たに確認された手法で、詳細は後述します。

  • npmへの自動自己公開:StepSecurityによる静的解析で難読化を解除した結果、コードが存在し、機能することがわかっています。ペイロードは正規表現/npm_[A-Za-z0-9]{36,}/gでnpmトークンを収集し、registry.npmjs.org/-/npm/v1/tokensで各トークンの有効性を検証します(bypass_2fa: trueかつ組織レベルの書き込みスコープがあるものに絞り込みます)。アクセス可能なパッケージを列挙し、tarballのコピー内にsetup.mjsとexecution.jsを追加してから、npm CLIを使わずnpmレジストリに直接PUTして公開します。記事公開時点で、最初の4つ以外に悪意のあるペイロードを含むパッケージは確認されていません。ただし、ワームとしての機能は推測ではなく、実際に確認された事実です。

  • 侵入経路となったCIパイプラインの乗っ取り:SAP自身による最初の公式声明は、同日14:02 UTCに提出されたpatricebenderによるcap-js/cds-dbsのPR #1592に記されています。「2026年4月29日、サプライチェーン攻撃によってリポジトリが侵害されました。権限のない攻撃者が悪意のあるコミットをプッシュしてリリースワークフローを乗っ取り、許可されていないnpmパッケージの公開を実行しました。ワークフローに手動承認のゲートがなく公開権限が設定されていたため、攻撃者は侵害したパッケージを公開できました。」対策は、環境レビューを必須にしてnpmへの公開を制御することです。npmレジストリのデータによると、悪意のある4つのバージョンはすべてcloudmtabotアカウント(正規のmbtメンテナー)から公開されました。SAPが13:46 UTCに公開したインシデント後のクリーンなバージョンは、cloudmtabotではなく、GitHub ActionsのOIDC信頼済みパブリッシャーであるcap-npmを通じて公開されています。cloudmtabotアカウント自体も、その後npmで停止されました。メンテナーの認証情報の侵害は、この種のインシデントで繰り返し見られる侵入経路ですが、SAPの声明では、ワークフローに承認ゲートがなかったことが構造的な根本原因として明確に指摘されています。

認証情報の窃取によってnpm上での自己複製が可能になりますが、直ちに確認された活動は、情報の持ち出しと新たな永続化の仕組みです。いずれの場合も、防御で優先すべき対策(ロックファイルの監査、認証情報のローテーション、ライフサイクルスクリプトのポリシー)は同じです。

攻撃の仕組み

侵害のパターンは4つのパッケージすべてで共通しています。悪意のあるtarballは正規のパッケージファイルを変更せずに残すため、インストール後もCLIは動作します。そのうえで、2つのファイルが追加されます。setup.mjs(4.5 KBの平文Bunローダー。4つのパッケージでバイト単位まで同一)と、execution.js(正確に11,678,349バイトの難読化されたペイロード。ハッシュはmbtと@cap-js/*パッケージ間で異なる)です。mbtだけは、悪意のあるpackage.jsonに、クリーンな以前のリリースにはなかった依存関係が3つ(axios、tar、unzip-stream)追加されています。3つのcap-jsパッケージでは、既存のpackage.jsonにpreinstallフックだけが追加されました。

インストール時に小さなローダーを取得し、それを使ってより大きなランタイムとペイロードを読み込む手法は、今年Snykが他の事例でも確認しています。たとえば、axiosを介したクロスプラットフォームRATのインシデントでは、インストールフックが外部に接続し、別の依存関係を通じて配布されるネイティブバイナリを取得していました。

mbtの1.2.47(クリーン)と1.2.48(悪意のあるバージョン)の差分は次のとおりです。

// 1.2.47: no scripts block
// 1.2.48:
{
  "scripts": {
    "preinstall": "node setup.mjs"
  },
  "dependencies": {
    "axios": "^1.13.5",
    "tar": "^7.5.7",
    "unzip-stream": "^0.3.4"
  }
}

preinstallは、npmがユーザーに何らかの出力を表示する前に実行されます。また、--ignore-scriptsフラグが設定されていない場合、条件付きのポリシーであっても介入する前に実行されます。このフックはsetup.mjsを実行し、次の処理を行います。

  1. (LinuxでのAlpine/musl検出を含め)プラットフォームとアーキテクチャを検出します。

  2. hasCommand("bun")を使って、PATH上にbunがすでにあるか確認します。存在する場合はダウンロードを省略し、既存のバイナリを使用します。存在しない場合は、GitHub ReleasesからBun 1.3.13をダウンロードします(Socketの分析によると、ダウンロード先を検証せずにHTTPリダイレクトを追跡します)。

  3. ダウンロードした場合は、Bunバイナリを一時ディレクトリに展開します。

  4. bun execution.jsを実行し、難読化されたペイロードを起動します。

bun execution.jsが起動すると、ペイロードは2段階の難読化を経て実行されます。obfuscator.io形式の文字列テーブルローテーション(標準外のBase64文字セットを使って48,370個のエントリをデコードし、起動時のチェックサムで検証)と、StepSecurityが「ctf-scramble-v2」と名付けた独自の暗号方式(PBKDF2で導出したマスターキーを使用)です。どちらの層も静的解析によって完全に解明されました。復元されたランタイムは、Bun上で動作するJavaScriptです(WASMやネイティブコードは埋め込まれておらず、Bun.gunzipSync()やBun.mainなどBunネイティブのAPIを使用します)。

StepSecurityによる静的解析では、ペイロードに次の挙動が確認されています。

  • ローカルの認証情報、GitHubとnpmのトークン、GitHub Actionsのシークレット、AWS、Azure、GCP、Kubernetesのクラウドシークレット、パスワードマネージャーCLIのトークン(1Password、Bitwarden、LastPass)、~/.claude.jsonとMCPサーバーの設定、KEY/TOKEN/SECRET/PASSWORDに一致する環境変数、ホスト上にある暗号資産ウォレットの秘密鍵を収集します。また、接続可能な場合はAWSインスタンスメタデータサービス(169.254.169.254)にも問い合わせます。

  • Linux CIランナーでは、Pythonの子プロセスを起動し、GitHub Actionsの/proc/{pid}/memからRunner.Workerプロセスのメモリを読み取ってダンプし、ランナーのメモリから平文のシークレットを直接窃取します。

  • Windowsでは、-ExecutionPolicy Bypassを指定してPowerShellを呼び出します。

  • 窃取したデータをJSONとしてシリアル化し、gzipで圧縮したうえでAES-256-GCM(32バイトのキー、12バイトのIV)で暗号化し、埋め込まれたRSA-4096公開鍵(execution.jsのファイルオフセット9,429,992にgzip+base64形式のPEMとして保存され、実行時にBun.gunzipSync()で展開)を使ってRSA-OAEP-SHA256でAES鍵をラップします。つまり、デッドドロップのリポジトリを発見した防御側は、何かが窃取されたことは確認できますが、何が窃取されたかは特定できません。実質的に、プロセスがアクセスできたすべての認証情報が漏えいしたものとして扱う必要があります。

  • 被害者のGitHubアカウントにランダムな文字列の名前を付けた公開リポジトリを作成し、説明に「A Mini Shai-Hulud has Appeared」と記載して、暗号化された暗号文をデッドドロップとしてコミットします。

  • JavaScriptのIntl APIとPOSIX環境変数(LC_ALL、LC_MESSAGES、LANGUAGE、LANG)を使ってシステムのロケールを確認します。ロシア語(ru)のロケールが検出されると、ペイロードは"Exiting as russian language detected!"をログに記録して終了します。CIS地域を除外するチェックは、これらの地域におけるサイバー犯罪活動の既知の挙動と一致しています。

永続化の仕組み

このキャンペーンをワームに分類するかどうかにかかわらず、公開報告で確認された中で最も目新しい要素は永続化の仕組みです。

StepSecurityによると、このペイロードは3つの永続化・再実行メカニズムを使います。

  • 開発者ツール設定へのインジェクション。盗んだトークンで書き込み可能なすべてのGitHubリポジトリに、ペイロードは.claude/settings.jsonファイルをコミットします。このファイルはClaude CodeのSessionStartフックを使い、開発者がClaude Codeのセッションを開始するたびにペイロードを再実行します。また、VS Codeでプロジェクトを開いたときに実行される"runOn": "folderOpen"を設定した.vscode/tasks.jsonもコミットします。これらの注入ファイルはclaude@users.noreply.github.comのIDで、"chore: update dependencies"というメッセージとともにコミットされるため、PRレビューでは定期的な自動化コミットに見える可能性があります。

  • GitHub Actionsワークフローへのインジェクション。盗んだトークンにworkflowスコープがある場合、ペイロードはタイポスクワッティングしたブランチdependabout/github_actions/format/setup-formatter(tが1つ抜けています)を作成し、Dependabotサービスアカウント(dependabot[bot]@users.noreply.github.com、コミットメッセージ"Add formatter workflow")になりすまして.github/workflows/format-check.ymlをコミットします。注入されたワークフローは${{ toJSON(secrets) }}を使ってリポジトリ内のすべてのシークレットをformat-results.txtというビルドアーティファクトに出力します。

  • 開発者のマシン上でのデーモン化。CI以外のホストでは、ペイロードは環境変数__DAEMONIZED=1を付けて自身を切り離されたバックグラウンドプロセスとしてフォークし、親プロセスは正常に終了します。そのため、npm installは目に見えるエラーなしでユーザーに制御を戻します。切り離された子プロセスは、明確なプロセスの系譜を残さずに実行を続けます。

これにより、npmサプライチェーン攻撃で確認されているインストール時の永続化手法に、package.jsonのライフサイクルフック、CIワークフロー、IDEプラグインのマニフェストに加え、AIコーディングエージェントの設定ファイルが加わりました。

AIエージェントの設定ファイルを狙う攻撃は、初めて確認されたものではなく、既知の手法です。MicrosoftのVSCode #309406はtasks.jsonのrunOn: folderOpenを使う手法について16日前に報告され、By Designとしてクローズされました(Workspace Trustで十分に緩和できるとされていますが、すでに信頼済みのリポジトリへのコミットは信頼性チェックの対象外です)。Anthropicのclaude-code #49778はSessionStartフックについて12日前に報告され、Cozempicサプライチェーン監査で実際に確認された事例を引用していますが、Anthropicからの回答はなく、現在もオープンです。2026年3月のTrivy AIエージェント侵害(CVE-2026-28353)ではさらに踏み込み、盗んだトークンを使って5種類のAIコーディングエージェントを標的とする悪意あるVS Code拡張機能を公開しました。Snykはこの同様の交差領域について、Clinejectionの記事でも取り上げています。Mini Shai-Huludはこのパターンの最初の事例ではなく、新たな一例です。

侵害の痕跡(IOC)

この一覧は、StepSecurity、Aikido、Socket、SafeDepによる公開報告を要約したものです。IOCの全容とフォレンジックの詳細については、各報告を参照してください。悪意ある各バージョンは、npmレジストリ上の改変不可能な記録として、registry.npmjs.org/mbt/1.2.48、registry.npmjs.org/@cap-js/sqlite/2.2.2、registry.npmjs.org/@cap-js/postgres/2.2.2、registry.npmjs.org/@cap-js/db-service/2.10.1で引き続き確認できます。公開日時と"preinstall": "node setup.mjs"という識別情報も各記録に保存されています。

Compromised npm artifacts
  mbt@1.2.48                       shasum 0af7415d65753f6aede8c9c0f39be478666b9c12
  @cap-js/db-service@2.10.1        shasum 4b04304f6d51392e3f43856c94ca95800518a694
  @cap-js/sqlite@2.2.2             shasum 7b6a28e92149637e5d7c7f4a2d3e54acd507c929
  @cap-js/postgres@2.2.2           shasum e80824a19f48d778a746571bb15279b5679fd61c

Compromised npm publisher account
  cloudmtabot (used to publish all four malicious versions)

Files added to the compromised tarballs
  setup.mjs       ~4.5 KB plaintext Bun loader, byte-identical
                   across all four packages
  execution.js    11,678,349 bytes obfuscated payload, hash
                   differs per package

File hashes (SHA-256, per StepSecurity)
  setup.mjs (all packages)
    4066781fa830224c8bbcc3aa005a396657f9c8f9016f9a64ad44a9d7f5f45e34
  execution.js (mbt@1.2.48)
    80a3d2877813968ef847ae73b5eeeb70b9435254e74d7f07d8cf4057f0a710ac
  execution.js (@cap-js/sqlite@2.2.2)
    6f933d00b7d05678eb43c90963a80b8947c4ae6830182f89df31da9f568fea95
  Embedded /proc/mem dumper
    29ac906c8bd801dfe1cb39596197df49f80fff2270b3e7fbab52278c24e4f1a7

In-payload indicators (recovered by StepSecurity static analysis)
  Custom cipher salt              ctf-scramble-v2
  PBKDF2 input key                5012caa5847ae9261dfa16f91417042f367d6bed149c3b8af7a50b203a093007
  Derived master key              fd4b0f07b27e8f41bc70b8e2b79d168fb3fe80d7e0b37f43c506136a3418b44d
  CIS evasion log string          Exiting as russian language detected!
  Daemonization env var           __DAEMONIZED
  GitHub PAT regex                /gh[op]_[A-Za-z0-9]{36}/g
  npm token regex                 /npm_[A-Za-z0-9]{36,}/g

Network and runtime indicators
  - Outbound request to github.com/oven-sh/bun/releases/download/bun-v1.3.13/{asset}.zip
    where {asset} is one of:
      bun-linux-aarch64
      bun-linux-x64-baseline
      bun-linux-x64-musl-baseline
      bun-darwin-aarch64
      bun-darwin-x64
      bun-windows-aarch64
      bun-windows-x64-baseline
    (skipped if `bun` is already on PATH)
  - Process chain during install:
    node setup.mjs -> bun execution.js
  - Linux CI runners: child Python process reading
    /proc/{pid}/mem of Runner.Worker
  - Windows: powershell -ExecutionPolicy Bypass
  - api.github.com calls:
    POST /user/repos               (dead-drop repo creation)
    GET  /search/commits?q=OhNoWhatsGoingOnWithGitHub
                                   (P2P token dead-drop search)
  - Direct PUT to registry.npmjs.org during self-propagation
    (no npm CLI involvement)
  - Cloud metadata reads:
    http://169.254.169.254          (AWS/Azure IMDS)
    http://169.254.170.2            (ECS task metadata)
    http://[fd00:ec2::254]          (AWS IMDSv2 IPv6)

GitHub-side indicators
  - New public repositories on developer accounts with the
    description string "A Mini Shai-Hulud has Appeared"
  - Repository names follow a Dune-themed pattern, regex:
    (sardaukar|mentat|fremen|atreides|harkonnen|gesserit|
     prescient|fedaykin|tleilaxu|siridar|kanly|sayyadina|
     ghola|powindah|prana|kralizec)-(sandworm|ornithopter|
     heighliner|stillsuit|lasgun|sietch|melange|thumper|
     navigator|fedaykin|futar|slig|phibian|laza|cogitor|
     ghola)-\d{1,3}
  - Commits authored by claude@users.noreply.github.com
    with the message "chore: update dependencies"
  - New or modified .claude/settings.json files containing
    a SessionStart hook
  - New or modified .vscode/tasks.json with a task using
    "runOn": "folderOpen"
  - P2P token dead-drop commits referencing the string
    "OhNoWhatsGoingOnWithGitHub" (used by the malware to
    locate base64-encoded tokens left by other victims)
  - Typosquatted Dependabot branch:
    dependabout/github_actions/format/setup-formatter
  - Injected workflow file .github/workflows/format-check.yml
    using the expression toJSON(secrets), authored by
    dependabot[bot]@users.noreply.github.com with commit
    message "Add formatter workflow", uploading artifact
    "format-results.txt"

特徴的な2つの文字列をGitHubでリアルタイム検索できます。

各デッドドロップリポジトリには、単一のREADME.mdファイルと、1つ以上のresults/results-<unix-ms>-<counter>.jsonファイルが含まれています。外部の研究者が稼働中の被害者リポジトリを直接調査し、次のファイル形式を確認しました。

{"envelope": "<base64 AES-256-GCM ciphertext>", "key": "<base64 RSA-4096 wrapped session key>"}

ラップに使われている鍵は攻撃者のRSA-4096公開鍵であるため、被害者のGitHubアカウントに完全にアクセスできても、防御側は内容を解読できません。

今すぐ取るべき対応

被害の範囲は、2026年4月29日の露出期間(およそ10:00〜14:00 UTC)中、または非推奨バージョンが解決可能なままの期間に、ビルドパイプラインや開発者のマシンで、影響を受ける4つのバージョンのいずれかに対してnpm installを実行したかどうかによって異なります。

インストール状況を確認する。ロックファイルで影響を受けるバージョンを検索し、推移的な依存関係の解決にも注意してください。@cap-js/sqlite@2.2.2は@cap-js/db-service@^2.10.0を依存関係として宣言しているため、取得可能なバージョン範囲から@cap-js/sqliteをクリーンインストールすると、誰も直接指定していなくても、推移的依存関係として@cap-js/db-service@2.10.1(悪意あるバージョン)が取り込まれる可能性があります。

# in any project root
rg -n '"mbt"|"@cap-js/db-service"|"@cap-js/sqlite"|"@cap-js/postgres"' \
   package-lock.json npm-shrinkwrap.json yarn.lock pnpm-lock.yaml 2>/dev/null

Snykをご利用のお客様は、snyk testとsnyk monitorを実行すると、上記4つのアドバイザリに基づいて悪意あるバージョンが検出されます。mbt、@cap-js/db-service、@cap-js/sqlite、@cap-js/postgresのSnyk Security Databaseページにも、このセキュリティインシデントが反映されています。

侵害されたバージョンをインストールした場合:

  • そのマシンやパイプラインからアクセス可能な認証情報はすべて、漏えいしたものとして扱ってください。攻撃者が管理するRSA鍵で暗号化されているため、防御側はデッドドロップの内容を読んで影響範囲を確認できず、慎重に認証情報をローテーションする必要があります。StepSecurityがペイロードから復元した134種類のファイルパスパターンには、少なくとも以下が含まれます。npm公開トークン(開発者が管理する他のパッケージへワームのように拡散するため、最優先で対応)、GitHub PATとOAuth認可情報、AWS/Azure/GCPの認証情報、および影響を受けたマシンから引き受け可能なロール、Kubernetesのkubeconfig(~/.kube/config、k3s YAML、Pod内のサービスアカウントトークン)、Docker設定(~/.docker/config.json)、Terraform Cloudの認証情報(~/.terraform.d/credentials.tfrc.json)、Helm設定、SSH鍵(~/.ssh/id*、config、known_hosts、/etc/ssh/配下のホスト鍵)、パスワードマネージャーのCLIトークン(1Passwordのop、Bitwardenのbw、LastPass)、.npmrc / .pypirc / .yarnrc、.gitconfigと.git-credentials、シェルの履歴ファイル、環境変数、および*_TOKEN、*_KEY、*_SECRET、*_PASSWORDのパターンに一致する.env*ファイル、~/.claude.jsonとあらゆるMCPサーバー設定(~/.kiro/settings/mcp.jsonのKiro MCP設定を含む)、メッセージングアプリのセッションデータ(Signal、SlackのCookie、Discord、Telegram、Element、Pidgin)、VPN設定(NordVPN、ProtonVPN、OpenVPNなど)、FileZillaのサーバーリスト、Ansible設定、Bitcoin、Ethereum、Monero、Dash、Zcash、Dogecoin、Litecoin、Electrum、Exodus、Ledger Live、Atomicの暗号資産ウォレット鍵です。また、ペイロードはAWSインスタンスメタデータ(169.254.169.254、169.254.170.2、fd00:ec2::254)とECSタスクメタデータも読み取るため、これらのエンドポイントからアクセス可能なIAMロールも漏えいしたものと見なす必要があります。

  • GitHub Actionsのシークレット露出を監査してください。/proc/{pid}/memを使う手法では、Runner.Workerの読み取り可能なメモリアドレス空間全体が取得されるため、インストール手順で直接参照されていなくても、その時点までにワークフローで使用されたシークレットはすべて対象です。GitHubホストランナーのデフォルト設定では、このアクセスはブロックされません。検出するにはStepSecurity Harden-Runnerのようなランナー側のセキュリティエージェントが必要です。

  • 上記のコードブロックにあるIOCを使って、GitHub組織全体を検索してください。Duneをテーマにした命名パターンと「Mini Shai-Hulud」の説明が付いたデッドドロップリポジトリ、claude@users.noreply.github.comの作成者署名、dependabout/...ブランチ上でのdependabot[bot]@users.noreply.github.comへのなりすまし、toJSON(secrets)でシークレットを流出させてformat-results.txtアーティファクトに出力する注入済みの.github/workflows/format-check.ymlワークフロー、P2Pトークンのデッドドロップに使われたコミット文字列OhNoWhatsGoingOnWithGitHub、予期しない.claude/settings.jsonまたは.vscode/tasks.jsonの追加を確認してください。

  • 安全なバージョンを固定する。3つの@cap-jsパッケージでは、SAPがインシデント後にリリースしたバージョン(@cap-js/db-service@2.11.0、@cap-js/sqlite@2.4.0、@cap-js/postgres@2.3.0)を今後の固定先とし、インシデント前のバージョン(順に2.10.0、2.2.1、2.2.1)を最低ラインにしてください。mbtについては、執筆時点で修正版がリリースされていません。SAPが後継版を公開するまで、mbt@1.2.47に固定してください。

基本的なセキュリティ強化:

  • CI環境では、デフォルトでnpm install --ignore-scriptsを使い、本当に必要なパッケージに限ってライフサイクルスクリプトを明示的に許可してください。これにより、元のShai-Hulud、SHA1-Hulud、そして今回のキャンペーンで配布手段となった、preinstallによる認証情報窃取を全面的に防げます。このライフサイクルフックを使った攻撃手法は、2016年にnpmに報告されて「意図した動作」とされました。paulirishがHacker Newsで再び指摘したとおり、10年たった今もエコシステムで最も悪用されている攻撃対象です。詳しくは、SnykのNPM Security Best Practicesと、上流での防御策を詳しく解説したHow to prevent malicious packagesをご覧ください。

  • ライフサイクルスクリプトをデフォルトで安全に扱うパッケージマネージャーの利用も検討してください。pnpm v10は明示的に許可されない限りライフサイクルスクリプトをブロックし、Bunをインストーラーとして使う場合は信頼済みパッケージの許可リストがデフォルトで用意されています。今回、後者は特に重要です。マルウェアはBunをランタイムとしてペイロードの実行に使いますが、インストーラーとしてのBunなら、配布に使われるpreinstallフックをブロックできていました。Bunコミュニティでは、クールダウン期間を設ける緩和策として、Yossarianの依存関係のクールダウンに関する提案と同様に、minimumReleaseAge設定のリクエスト(#28729)も検討されています。

  • PRの差分で、予期しない.claude/settings.jsonや.vscode/tasks.jsonの変更がないか確認してください。どちらかのファイルへの追加は、依存関係の定期的なメンテナンスに見えても、サプライチェーン攻撃の兆候として扱ってください。

  • SOCおよび検知エンジニアリングチーム向けに公開されたMicrosoft DefenderのKQLクエリ(m4nbat/100_days_of_kql_2026のDay 17)は、このキャンペーンが再利用するBun + TruffleHog + /proc/memの一連の手法を検知します。SHA1-Hulud向けに作成されたものですが、変更を加えずにMini Shai-Huludにも適用できます。Wiz ResearchのIOCフィードとgensecaihq/Shai-Hulud-2.0-Detectorは、メンテナーが新たに侵害された4つのパッケージを反映した後に、有効なブロックリストとして利用できます。

  • リスクベースの優先順位付けを行い、影響範囲が最も大きい認証情報を優先してローテーションとトリアージを進めましょう。対象となるシークレットがすべて同じように機密性の高いものとは限りません。また、暗号化されたデッドドロップが使われているため、防御側が得られる情報は不完全です。

Pythonアプリのセキュリティ対策を始めましょう

Snykを使って、Pythonの脆弱性を無料で検出・修正できます。

クレジットカードの登録は不要です。

またはAzure AD、Docker ID、Bitbucketで登録

Snykを利用すると、利用規約およびプライバシーポリシーを含む各種ポリシーに同意したものとみなされます。