3 ポイント 投稿者 GN⁺ 2025-10-31 | 2件のコメント | WhatsAppで共有
  • NPMリポジトリで100個以上の認証情報窃取用の悪性パッケージが8月以降未検出のままアップロードされ、合計8万6,000回以上ダウンロードされていたことが確認された
  • セキュリティ企業 Koi は、「PhantomRaven」と名付けた攻撃キャンペーンがNPMの Remote Dynamic Dependencies(RDD) 機能を悪用し、126個の悪性パッケージを配布したと報告
  • RDDは、パッケージが信頼されていないドメインから依存コードを動的にダウンロードできる仕組みで、静的解析ツールでは検出されない
  • 攻撃者はこの機能を利用してHTTP接続による悪性コードのダウンロードを行い、パッケージのメタデータ上では「0 Dependencies」と表示されるため、開発者やセキュリティスキャナーが認識できなかった
  • このような構造的脆弱性は、NPMエコシステムにおけるセキュリティ管理の限界と自動インストール機構の危険性を浮き彫りにしている

NPMリポジトリ内での悪性パッケージ拡散

  • 攻撃者がNPMコードリポジトリの構造的な弱点を利用し、8月以降100個以上の認証情報窃取用パッケージをアップロード
    • 大半のパッケージは未検出のまま配布され、累計ダウンロード数は86,000回以上
  • セキュリティ企業 Koi はこの攻撃を PhantomRavenキャンペーン と命名し、NPMの特定機能が悪用されたと分析
    • Koiによれば、126個の悪性パッケージのうち約80個が記事執筆時点でもなおNPM上に残っていた

Remote Dynamic Dependencies(RDD)の脆弱な構造

  • RDDは、パッケージが外部Webサイトから依存コードを動的にダウンロードすることを許可する機能
    • 通常、依存関係はNPMの信頼されたインフラから取得されるが、RDDはHTTPなどの暗号化されていない接続でのダウンロードも許可する
    広告
  • PhantomRavenの攻撃者はこの機能を使い、悪性URL(例: http://packages.storeartifact.com/npm/unused-imports)からコードをダウンロードするよう設定
    • こうした依存関係は開発者やセキュリティスキャナーから見えず、パッケージ情報には「0 Dependencies」と表示される
  • NPMの自動インストール機能により、このような**「見えない」依存コードが自動実行**される構造になっている

セキュリティツールの検出限界

  • Koiの Oren Yomtov は、「PhantomRavenは既存のセキュリティツールの死角を巧妙に悪用した事例だ」と述べた
    • RDDは静的解析ツールでは検出されない
  • その結果、攻撃者はセキュリティ検証を回避しながら悪性コードを配布できた

追加の脆弱要因

  • Koiは、RDDで取得された依存関係はインストールのたびに攻撃者のサーバーから新たにダウンロードされると説明
    • キャッシュやバージョン管理がないため、同じパッケージでもインストール時点ごとに異なる悪性コードが注入される可能性がある
    広告
  • このような動的ダウンロード構造は、パッケージ完全性の検証を困難にする

NPMの構造と背景

  • NPMはJavaScript向けのパッケージマネージャーで、GitHub子会社の npm, Inc. が管理
    • Node.jsの標準パッケージマネージャーであり、コマンドラインクライアントと npm registry で構成される
    • registryには公開および有料の非公開パッケージが保存され、Webサイトから検索できる
  • 今回の事件は、NPMの自動依存関係管理の仕組みが攻撃に悪用され得ることを示す事例として指摘されている

その他の言及

  • 記事の末尾では、不要なJavaScriptの実行をブロックすべきだという意見に言及
    • しかし今回の攻撃は、必須のJavaScriptコードすら悪用された事例だと指摘されている

2件のコメント

 
developerjhp 2025-11-25

リアルタイムスキャナースクリプトを作ってみました。

疑わしいリポジトリのpathで
npx sha1-hulud-scanner
を入力すれば大丈夫です。

ソースコード : https://github.com/developerjhp/sha1-hulud-scanner

 
GN⁺ 2025-10-31
Hacker Newsのコメント
  • 最近、自分は npm コマンドを Dockerコンテナ内で実行するように alias を設定している
    こうすると環境変数を露出せず、現在のディレクトリ外のファイルにもアクセスせず、.bashrc のような設定ファイルにも触れられない
    参考: Run tools inside Docker

    • それはサンドボックス化としてはやりすぎに思える。どうせ npm はすぐに実行される 任意コード をダウンロードするのだから
      その代わり pnpm を勧める。デフォルトで lifecycle スクリプトを実行せず、許可するスクリプトを ホワイトリスト 指定できる
    • post-install スクリプトを悪者扱いするのは 誤った安全幻想 を与えるだけだ
      本当に保護したいなら、インストールだけでなく実行全体をサンドボックス内で回すべきだ
      今のように post-install だけを止めるのは半端な対策にすぎない。サプライチェーン攻撃はますます危険になっている
    • 攻撃ベクトルは多すぎる。悪意があるなら人気の プラグインや LSP の名前をタイポスクワッティングして、エディタ起動時に自動でコードが実行されるようにできる
      neovimvscode が感染すれば、すでにユーザー権限で十分危険なことができる
    • 自分は sandbox-run を使っている
      単純な alias は node/npm には効くが、他のプログラムには適用しづらい。コンテナに必要なリソースをマウントしなければならないからだ
    • それでも結局 悪意あるパッケージ をダウンロードしうるのでは?
      依存関係自体が感染しているかもしれない
  • 前から不思議だった。なぜ人は平然と npm をシステム上で動かすのか
    make のような 再現可能なビルド に慣れている立場からすると、npm が毎回違うものをダウンロードし、違う結果を出すのは衝撃だった
    CSS 生成すら npm 依存に結びつけるのは妙だった。だから Docker の中に npm 環境を丸ごと 固定(freeze) してみたが、結局は負け戦のように思える

    • 今ではどのパッケージマネージャもそんなものだ。mavennugetpipnpm はみな同じだ
      昔のようにディストリビューションのパッケージマネージャに依存していたら、今のような 高速なエコシステム は不可能だっただろう
      ただしセキュリティを強化した新しいパッケージマネージャも登場している。理由を理解せずに手段だけを非難するのは正しくない
    • フロントエンド開発はまるで 「信じてくれよ兄弟」式のワイルドウェスト のようだ。ブラウザの進化の過程上、どうしてもガムテープのように継ぎはぎした感じがある
    • npm を Docker に固定したなら、依存関係を更新するたびにその環境を 検証 したのか聞きたい
      実際には npmpnpm はすでにデフォルトで lock ファイル によって依存関係を固定している
    • 問題は “npm install thing” があまりにも簡単で安いことだ
      多くのオープンソースが 品質より履歴書向けコード で埋まり、結局は巨大企業の広告トラッカーやウォレットアプリのようなものを作るのに使われる
  • npm install は単にパッケージをダウンロードするのではなく コードを実行する
    package.json の preinstall、install、postinstall フックが実際に実行される
    合法的にインストール過程で任意コマンドを実行しなければならない理由とは何だろう?
    関連レポート: PhantomRaven npm malware
    別の事例: Socket.devブログ

    • 実際こうした構造は古いパッケージマネージャ(DEB、RPM)にもあった
      たとえば Linux カーネルパッケージは、インストール後に initramfs の再生成、GRUB の更新 などのため post-install スクリプトを実行する
      ほとんどの DEB/RPM パッケージにこうしたスクリプトが含まれている。つまり設計自体の問題だ
    • 問題は npm誰でもパッケージを公開できること
      Linux ディストリビューションには信頼できる メンテナ体制 があり、PGP ベースのルート・オブ・トラストを自前で構築することもある
      一方で npmpiprubygemscargo などは、実質的には “curl | bash” の洗練版にすぎない
    • たとえば Mediasoup プロジェクトは C++ で書かれたストリーミングライブラリだが、インストール時にソースを直接コンパイルする
      保守負担を減らすために、こうした post-install ビルドが必要だった
    • Swift Package ManagerPackage.swift ファイルを実際に実行する
      ただし強く サンドボックス化 されているので、悪用は難しいと聞く
      参考: SwiftPMドキュメント, PackageDescription
    • ちなみに pnpm v10 はデフォルトで全 lifecycle スクリプトを無効化しており、ユーザーが自分で許可しなければならない
      関連する議論
  • 最近の npm 攻撃を見ると、もう npm で開発するのは 安全なのか と思ってしまう
    React プロジェクトを始めるたびに数百個のパッケージが入るのに、何をしているのか分からない
    バックエンドでは必要なパッケージだけを明示的に入れるが、フロントエンドは 脆弱性のパンドラの箱 のようだ

    • 実際、どの言語エコシステムも似たようなものだ。ただ npm が一番大きく、ニュースになりやすいだけだ
    • Rust の jj をインストールしたら 470 個、Python の wan2gp は 211 個のパッケージが入った。みな似たり寄ったりだ
    • JavaScript エコシステムは構造的に攻撃に弱い
      xz 事件のように、各依存関係が 見ず知らずの個人 に委ねられており、その人たちがソーシャルエンジニアリング攻撃に遭わないと信じるしかない
    • 依存関係は少ないほどいい。0 個なら完璧 だ。それが本当の勝利だ
    • ちなみに PyPI も安全ではない。GitHub Actions のハックによって 正規パッケージに悪性コードが挿入された事例 もある
  • Angular や Vue のようなフレームワークで開発するたびに不安になる
    node_modules の中の何千もの依存関係を見ると 災厄の前触れ のように感じる
    オープンソース開発者が 1 人フィッシングに引っかかれば、すぐ感染するかもしれない
    JavaScript エコシステムは 根本的に壊れている。タイプミス 1 つでサプライチェーン攻撃にさらされる
    NuGet や Maven でも不可能ではないが、あちらは 標準ライブラリ が大きく、依存関係が少ないので統制感がある

    • Go はパッケージ名ではなく repo URL を使うので、タイポスクワッティングを減らせる
      完璧ではないが、それでも一段ましだ
    • Deno はこうした問題を解決している。Node.js / npm の構造的問題
  • 86,000 回のダウンロードの大半は、実ユーザーではなく 自動化スキャナやボット である可能性が高い
    新バージョンを上げると 1、2 日で数百回ダウンロードされるが、実際の人間ではないかもしれない
    つまり感染したユーザーはほとんどいない可能性もある

    • 自分もライブラリを公開したとき、最初は週 300 回、その後は 100 回ほどダウンロードされた
      AI チャットボットが 幻覚で作り出したパッケージ名 を狙った攻撃も多い。単純な統計以上の話だ
    • あるいは誰かの ゾンビ CI がダウンロードし続けているのかもしれない
    • しかし LLM が作った偽のパッケージ名を狙った攻撃なら、実際に多くの開発者が感染した可能性もある
  • より詳しい攻撃の説明は BleepingComputerの記事 を参照

  • npm install 中に HTTP URL を依存関係として使うパッケージを検出またはフィルタリングする方法はあるだろうか
    リクエスターごとに異なるペイロードを送れるため、一般的なスキャナでは検出が難しい

  • 趣味の開発者として、こうした サプライチェーン攻撃への備え をどうすべきか悩んでいる
    有名なチュートリアルに従って依存関係を入れていくうちに、いつの間にかセキュリティへの注意が薄れてしまう
    自分のホームラボでも複数のサービスを動かしているが、もしボットが侵入したらと心配だ。どこから始めればいいだろう?

    • コンテナや VM の中でサービスを分離して動かせば、被害を 隔離 できる
      完璧な保証ではないが、サーバー全体を突破されるよりはずっとましだ
    • すべての依存関係を 潜在的なセキュリティリスク と見なし、本当に必要なときだけ使うべきだ
      必要なコードだけを自分でコピーして使うのも、良い学習になり安全な方法だ
    • 人気があり、1年以上経ったリリース を使うのが安全だ。問題があればすでに見つかっている可能性が高い
    • FreeBSD のようにシステムパッケージマネージャを使う OS もある
      こうした構造なら、何百万ものユーザーが直接検証しなくても ディストリビューションレベルで信頼性を確保 できる
    • 週 100 万回以上ダウンロードされ、依存関係のないパッケージ を好む
      例: Hono, Zod
      自分は最近 Bun に移行したが、DB ドライバや S3 クライアントのようなものが標準で組み込まれていて、追加ダウンロードが減る
  • lifecycle フックで依存関係を持ってくる構造は、いつでも 攻撃の転換点 になりうる
    今は正常でも、後で所有者がハックされたり気が変わったりすれば、悪性コードに変わる可能性がある
    この種のインストールフックは結局 持続不可能な設計