すべての投稿に戻る
公開日 · 著者 Renaud Deraison

そのパッケージは本当にRed Hatのものだった

2026年5月下旬から6月1日にかけて、Miasmaと呼ばれるワームが、`@redhat-cloud-services` npmスコープ — Red Hat自身のネームスペース、週間ダウンロード数約117,000、Red Hatの本物の公開パイプラインによる署名付き — の32のパッケージに認証情報窃取コードを注入しました。捕まえるべきタイポスクワットも、フラグを立てるべき未知のメンテナーもありませんでした。信頼シグナルはスコープに記されたベンダー名であり、そしてそのベンダー名こそが攻撃者が乗り込んできたまさにそのものでした。なぜ「評判の良い公開者を選ぶ」が防御でなくなったのか、そしてインストールを実行するエージェントがプロファイルごとのBromure VM内に住むとき何が変わるのかを示します。

5月に取り上げたサプライチェーン攻撃には手がかりがありました。 バージョン範囲があるべき場所のGit URL。どこからともなく 現れるBunランタイム。故意に失敗するオプショナル依存関係。 Miasmaには手がかりがありません。パッケージは @redhat-cloud-services/sources-clientとその31の兄弟 — 正真正銘Red Hatのもので、Red Hat自身のnpmスコープの下にあり、 Red Hat自身のパイプラインによって有効な署名付きで公開されて いました。何も偽装されていませんでした。攻撃者は何も偽装する 必要がありませんでした。スコープに記された名前こそが、攻撃の 全てだったのです。

@redhat-cloud-services/vulnerabilities-clientを解決する コーディングエージェントはためらいません。そしてあなたも ためらわないでしょう。それは業界最大級のエンタープライズ ベンダーの1つからのファーストパーティ依存関係です。審査すべき メンテナーはいません。なぜならメンテナーはRed Hatだからです。 入れ替わった文字がないか目を凝らすべき名前もありません。 なぜなら名前は本来あるべき通りに正確に綴られているからです。 注意深い開発者や注意深いエージェントがnpm installを実行する 前に適用する全てのヒューリスティックが、緑を返します。そして インストールが実行され、preinstallフックが発火し、その フックは4.2メガバイトの難読化されたJavaScriptの塊で、 ファイルシステムをキーのために読み始めます。

このインシデント全体は、1つの不快な事実のデモンストレーション です:評判の良い公開者はセキュリティコントロールではない。 それはコントロールのように感じられます。過去3年間の サプライチェーンアドバイスのほとんどがそれに寄りかかって います。そして5月29日、それは何ひとつ買えませんでした。

Miasmaが行ったこと。

このキャンペーン — 文字列Miasma: The Spreading BlightOX Security によれば2026年5月29日付のコミットに初めて現れます — は AikidoとOX Securityによって捕らえられ、 後にSocket、JFrog、Wiz、ReversingLabs、Microsoftらによって 分析されました。BleepingComputerThe Hacker News は両方とも6月1日に報じました。

その形を、仕組みまで剥ぎ取ると:

  • 侵入口は侵害されたRed Hat従業員のGitHubアカウントで、 @redhat-cloud-servicesのソースリポジトリに悪意のある コミットをプッシュするために使われました。
  • GitHub Actionsワークフローが_index.jsスクリプトを運び、 これがnpmの信頼された公開エンドポイントにOIDCトークンを 使用して認証しました — npmが今や長命の公開トークンより 推奨している、同じキーレスのメカニズムです。npmの側から 見れば、Red HatのCIがRed Hatのパッケージを公開しました。 署名は本物でした。
  • 公開されたパッケージは"preinstall": "node index.js"フックと 約4.2 MBの難読化されたペイロードを運んでいました。
  • インストール時、ペイロードはGitHub Actionsシークレット、 AWS認証情報、Google Cloud認証情報、Azureサービスプリンシパル、 HashiCorp Vaultトークン、Kubernetesサービスアカウントトークン、 npmおよびPyPI公開トークン、SSHキー、Docker認証情報、GPGキー、 .envファイルをスイープし、見つけたものを暗号化して 流出させました。
  • それは盗んだアクセスを使ってGitHub API経由でコミットし、 GraphQL経由でaction.ymlファイルを読み、ミューテーション 経由で新しいワークフローを書き戻すことで自己伝播しました。 その変更は、コミットログ上のRed Hat自身の言葉で、verified かつsignedとして現れました。

合計で、96バージョンにわたる32のパッケージが攻撃を受け、 それらは週間ダウンロード数約117,000のパッケージで、 より広範なキャンペーンは309のGitHubリポジトリに及びました。 Socketの評価は、これは*「事実上のミニShai-Huludキャンペーンで ある:インストール時実行、認証情報の収集、CI/CDのターゲティング、 暗号化された流出、潜在的な下流への伝播という、同じ中核戦術を 使用する」というものでした。Red Hatの声明は「パッケージは 内部開発に厳密に限定されており、悪意のあるコードは顧客の利用の ために公開されることは一度もなかった」*というもので — これは 真実であり、また、パッケージが撤回される前の期間に @redhat-cloud-services/*を推移的依存関係として引き込んだ 開発者やCIランナーにとっては、大した慰めにもなりません。

誰もが推奨する防御こそが、壊れたものだった。

私たちは3週間前に似たワーム について書きました — TanStackの侵害で、決め手はピン留めされた Git URLにぶら下がったprepareスクリプトと、どこからともなく 現れたBunランタイムでした。あの投稿からの正直な教訓は: ロックファイルを信頼するな、署名を信頼するな、でした。Miasmaは 同じネジの次の一回転であり、何が違うのかを正確にしておく価値が あります。なぜなら、その違いこそが全ての要点だからです。

標準的なサプライチェーン衛生のスタックには3つの段があります。 バージョンをピン留めしろ。来歴を検証しろ。評判の良い公開者を 選べ。Miasmaは3つすべてをまっすぐ通り抜けます。ピン留めは何も しません。なぜなら悪意のあるバージョンこそが公開された バージョンだからです。来歴は何もしません。なぜなら来歴は有効 だからです — OID信頼された公開フローは本当にRed HatのCIで あり、下流ではワームがGitHub自身がverifiedかつsignedと記した ワークフローコミットを鋳造しました。そして3つ目の段、評判の 良い公開者を選べは、ここで打ち負かされるだけではありません — それが攻撃面なのです。@redhat-cloud-servicesスコープの評判 こそが、パッケージが二度見されずに引き込まれる理由です。 ネームスペースが信頼されればされるほど、それを乗っ取った者に とって有用になります。

これを捕まえる「パッケージをもっと注意深く読む」のいかなる バージョンも存在しません。パッケージは問題ありません。 パッケージはRed Hatのものです。問題は、開発者の周囲の認証情報 を伴うインストール時のコード実行が契約であり、信頼された名前は、 そのコードが一度実行されたとき何に触れられるかを何も変えない、 ということです。

開発者ラップトップ / CIランナー — インストールが実行する何にでも見えるホスト秘密RED HAT自身のパイプライン侵害された従業員のGitHubアカウント → pushGH Actions: OIDC公開署名: 有効来歴: 本物npm: @redhat-cloud-servicessources-clientvulnerabilities-clientrbac-client … (32 pkgs)週間DL数 約117kpreinstall: node index.jsコーディングエージェント — ためらう理由なしtool: bashnpm i @redhat-cloud-services/sources-clientファーストパーティのベンダースコープ ⇒ 緑↳ preinstallがnode index.jsを実行↳ 4.2 MBの難読化ペイロードホストファイルシステム&ENV — 全て本物、全てpreinstallフックが読める~/.aws, GCP, Azure SPNsクラウドキー(本物)Vaultトークン, kube SAトークンクラスターアクセス(本物)~/.npmrc, PyPIトークンここで公開(本物)~/.ssh, GPGキーリング署名 + push(本物)$GITHUB_TOKEN, .envファイルCIシークレット(本物)tar | encrypt | exfiltrate自己伝播盗んだGitHubアクセスaction.ymlを読む (GraphQL)汚染ワークフローをコミット現れ方: verified, signedキャンペーン内309リポジトリ次のスコープが信頼を継承する
@redhat-cloud-servicesを直接解決する開発者マシンまたはCIランナー上のMiasma。侵害された従業員アカウントがRed Hatのリポジトリにプッシュし、OIDC信頼された公開フローが悪意のあるバージョンを正真正銘Red Hatのものとして署名し、npmが有効な署名付きでそれらを配信します。エージェントはためらう理由なくファーストパーティ依存関係をインストールします。preinstallフックがnode index.js — 4.2 MBの塊 — を実行し、ホストをAWS、GCP、Azure、Vault、Kubernetes、npm/PyPIトークン、SSHおよびGPGキー、.envファイルのためにスイープし、それらを暗号化し、外に送り出し、盗んだGitHubアクセスを使ってverifiedかつsignedとして現れる新たな汚染ワークフローをコミットします。タイポスクワットなし、偽メンテナーなし、Git URLトリックなし。信頼シグナルはネームスペースであり、ネームスペースは本物です。

Bromure Agentic Coding内での同じインストール。

Bromure Agentic Codingは、あなたのコーディング エージェントをプロファイルごとのLinux VM内で実行します — 独自のカーネル、独自のファイルシステム、独自のネットワーク スタックを、AppleのVirtualizationフレームワーク上で持ちます。 プロファイルは一貫した作業のスコープです:このクライアントこの内部プロダクトこのオープンソースライブラリ。エージェントは その中でnpm installを行い、ホスト — あなたの本物のキーチェーン、 あなたの本物のクラウド認証情報、あなたの本物のSSHキー — は、 preinstallフックが越えられないハードウェア強制の境界の反対側に あります。

認証情報はプロファイル内に住んでいません。それらはホスト上、 認証情報ブローカーの背後に 住んでいます。エージェントがコミットをプッシュしたりパッケージを 公開したりする必要があるとき、ゲストのファイルシステムから トークンを読み取りません — 読み取るべきものがないのです。 Unixドメインソケット経由でブローカーに、自分に代わって認証情報を 使用するよう依頼します。ブローカーは本物のGitHub App秘密鍵を 保持し、エージェントが既に作業していたリポジトリにスコープされた 短命のinstallationトークンを鋳造し、そして — それを要求するよう 設定されたプロファイルに対しては — リクエストが出ていく前に開発者が ホスト上で答える認可プロンプトを表示します。トークンは完全に ホスト側で鋳造され発信リクエストに添付されます。それはゲストの メモリやディスクに決して入りません。原則は、ssh-agentと同じ くらい古い:認証情報の使用を仲介し、そのは決して仲介しない。

ではMiasmaのスイープをその境界を通して歩いてみましょう。 node index.js~/.aws/credentialsを読み、スタブか何もないかを 見つけます。~/.npmrcを読み、公開トークンを見つけません。 環境を$GITHUB_TOKENのために読み、盗むものを見つけません — installationトークンはホスト上で鋳造され消費され、決してゲストに 書き込まれず、そしてブローカーは開発者が認可プロンプトに答えた ときに限ってそれを鋳造するのです。GPGキーリング、SSH秘密鍵、 Vaultトークン、kubeconfig:ホスト側にあり、もし露出するとしても 仲介され、なければ存在しません。4.2 MBのペイロードは設計通りに 正確に最後まで実行されます。それはただ、開発者のキーを一度も 保持していなかったゲストを流出させるだけです。

ホスト上のエージェントnpm i @redhat-cloud-services/sources-clientpreinstall → node index.jsホストを直接読む本物の認証情報 — プレーンテキストで読まれる~/.aws/credentialsAKIA… 本物~/.npmrc _authTokennpm_… 本物$GITHUB_TOKENghp_… 本物~/.ssh/id_ed25519秘密鍵Vault, kube SA, GPG全て本物→ 暗号化 + 流出→ 再公開、伝播プロファイルごとのBROMURE VM内のエージェントゲスト — preinstallフックが見られるもの~/.aws, ~/.npmrcスタブ / 不在~/.ssh, GPG, Vaultディスク上にないpush が必要?→ Unixソケット経由でブローカーに依頼認可プロンプト → ホスト側で使用(「キーをくれ」は動詞ではない)ホスト — ブローカーが本物のキーを保持GitHub App秘密鍵短命トークンをホスト側で鋳造値は決して境界を越えない
左:エージェントがホスト上で実行されるため、preinstallフックが本物のキーを直接読みます — Miasmaチェーンが完了します。右:エージェントがプロファイルごとのBromure VM内で実行されます。本物の認証情報はブローカーの背後でホスト上に座っています。エージェントが正当にプッシュする必要があるとき、Unixソケット経由でブローカーに依頼し、ブローカーは短命でリポジトリにスコープされたinstallationトークンをホスト側で使われるよう鋳造し — 開発者がホスト上で答える認可プロンプトの背後でゲートされ — トークンはゲストに決して着地しません。ゲストのファイルシステムと環境を読む悪意のあるpreinstallフックは、スタブを見つけ、トークンは全く見つけません。被害半径は1つのプロファイルであり、開発者のキーチェーン全体ではありません。

プロキシが転送を拒むpush。

キーを盗むことはMiasmaの半分にすぎません。もう半分は伝播です: それは盗んだGitHubアクセスを使って汚染ワークフローをAPI経由で コミットし戻し、それこそが1つの悪いインストールを309のリポジトリに 変えたものです。ブローカーは窃取を処理します。Guardrailsは、 Bromure Agentic Coding 2.0で追加され、誤用を 処理します。

Guardrailsはホスト側のポリシーエンジンで、仲介されたトラフィックが 既に流れている同じMITMプロキシの内部に住んでいます。そのため、 ゲスト内の侵害されたエージェントはそれを迂回できません。各 リクエストは、それがリソースに対して実際に何をするかによって 分類され、各リソース — GitHub、AWS、Kubernetes、Dockerレジストリ、 DigitalOcean、GitLab、Bitbucket、ホスト型データベース — は オフ破壊的操作をブロック、または読み取り専用に設定 できます。あるプロファイルのGitHub guardrailを読み取り専用モードに すると、git push — ワームがワークフローを書き戻すのに必要な git-receive-pack — は強い403を返し、一方git fetchは機能し 続けます。Kubernetes APIに対するDELETE、レジストリ内の マニフェスト削除、EC2へのTerminate*呼び出し:同じ扱いです。 エージェントには通常のAPI失敗が見えるだけです。Miasmaの伝播 ステップは、エージェントが本物の認証情報の近くにたどり着けたか どうかにかかわらず、プロキシが転送を拒む書き込みです。

持続化についてはどうか?

ここはプロファイルごとのモデルがコストについて正直になるところ です。Miasmaはワームです。その全ての野望は戻ってくることです。 使い捨てディスクの幻想の上では、それを払いのけられます — タスクの 後にディスクは消えます。Bromureプロファイルは長命なので、自身を プロファイル内のスタートアップスクリプトに書き込むペイロードは、 そのプロファイルでの次のエージェントセッションまで生き残れます。 私たちはそうでないふりをするつもりはありません。

しかし、その持続化が継承するのは、ホストキーのないゲストと、 短命でスコープ制限されたトークンしか話さないブローカーです。 ワームは、自分が死んだのと同じサンドボックスで目覚めます。 同じスタブを読めます。このプロファイルが認可されている1つの リポジトリのために認証情報を使うようブローカーに依頼できます — そしてそれがどこかに行くには開発者が依然として認可プロンプトに 答える必要があり、Guardrailsはそのpushを完全に拒否できます。 ワームはホストのキーチェーン、他のプロファイル、あるいは開発者の クラウド認証情報には到達できません。なぜならそれらはそもそも 境界の内側に一度もなかったからです。持続化が買うのは、何も入って いない箱の中での継続的な存在です。

そしてそのすべて — preinstallの発火、node index.jsが数 メガバイトの塊をロードすること、スタートアップパスに書き込まれた ファイル、エグレスの試み — はハイパーバイザーレベルの セッショントレースに 着地します。Aikidoが翌朝にインジケーターを公開するとき、 「このプロファイルは一度でもMiasmaを実行したか?」という質問は、 grepであって、インシデントレスポンスの取り組みではありません。

これがあなたを救わない場所。

ブローカーのスコープが全てのゲームです。

あるプロファイルが今日あなたのnpmスコープに公開するよう プロビジョニングされていて、そのプロファイルが今日Miasmaを インストールするなら、ブローカーはそれに公開させるでしょう。 仲介が機能するのは、付与が狭くて短命だからです。公開する 必要のないプロファイルは公開できるべきではありません。 意図的にスコープを定めてください。

それはdiffをレビューしません。

Miasmaはverifiedかつsignedとして現れるワークフローを コミットすることで伝播しました。読み取り専用のGitHub guardrailはpushを完全にブロックします — しかし正当に プッシュする必要のあるプロファイルは破壊的操作ブロック モードで実行され、Guardrailsはメソッドによって分類するので あって、diffの中身によってではありません。隔離もメソッド レベルのguardrailも、エージェントがプッシュを許可されている 汚染ワークフローをコミットするよう言いくるめられることを 止めません。diffを読んでください。トレースがどのdiffを読む べきかを教えてくれます。

クリップボードはデフォルトで共有されています。

Bromureはホスト/ゲスト間のクリップボード共有を有効にして 出荷されます。なぜならスタックトレースをチャットに貼り 付けることは人間が一日中行うことだからです。機密的な プロファイルでは、クリップボードを分離してください。 コントロールは存在します。ただデフォルトではないだけです。

トレースは監査ログであり、IDSではありません。

セッショントレースはpreinstall、塊、エグレスを記録します。 それ自体で、宛先が敵対的であると判断することはありません。 十分にキャプチャするので、いったん誰かがインジケーターを 名指しすれば、あなたの答えは2秒先にあります。

次のスコープはすでに信頼されている。

TanStackワームの教訓は、ロックファイルと署名は防御ではないと いうことでした。Miasmaは不快な系を加えます:公開者もまた防御で はない。@redhat-cloud-servicesスコープは、信頼されることで 何も悪いことをしませんでした — 信頼されることはベンダー ネームスペースの全ての目的であり、それこそがそれを攻撃する 価値のあるものにしたまさにそのものです。次のキャンペーンは、 あなたが同じくらい信頼するスコープに乗って、同じくらい有効に 署名されて、まさにベンダーのものであったパイプラインによって — そうでなくなる直前まで本物だったパイプラインによって — 乗り 込んでくるでしょう。

あなたはそれを、もっと注意深く信頼することでは直せません。 あなたは、「どのスコープがこれを公開したか」があなたのキー チェーンが依存する質問でなくなるように物事を配置することで、 それを直します。Bromure Agentic Codingは、 エージェントがプロファイルごとのVM内でインストールを行い、本物の 認証情報がブローカーの背後でホスト上に留まり、preinstall フックにできる最悪のことが、あなたのキーを一度も保持していなかった 箱を流出させることである、そんな設定です。無料、オープンソース、 そして今日出荷されています。