Modern Frontend CVEs

対象CVE: GHSA-g6g7-pvmx-m74p

[緊急警告] npmパッケージ「9router」に認証バイパスとOSコマンドインジェクションの重大な脆弱性(GHSA-g6g7-pvmx-m74p)

npmパッケージ「9router」のv0.4.39以前のバージョンに、認証バイパスとOSコマンドインジェクションの組み合わせによるリモートコード実行(RCE)の脆弱性が発見されました。特にNode.jsプロセスがroot権限で動作している環境では、認証なしでサーバーが乗っ取られる深刻な影響があります。

はじめに:なぜフロントエンドエンジニアも注意すべきなのか

こんにちは、日本のフロントエンドエンジニアの皆さん。今回は、普段の開発で利用するNode.jsエコシステムに潜む深刻な脆弱性について解説します。対象は「9router」というnpmパッケージで、この脆弱性は、認証なしでサーバー上で任意のコマンドを実行できる(リモートコード実行、RCE)という、極めて危険なものです。Node.jsでアプリケーションを構築している、あるいはこのパッケージを間接的に利用している可能性がある皆さんは、ぜひ最後まで読んで、ご自身のプロジェクトを確認してください。

9routerとは?

9routerは、Next.jsベースで構築されたオープンソースのルーター/プロキシ/API管理ツールです。主にVPNやトンネル接続の管理、CLIツールとの連携などを目的として設計されています。Webインターフェースを通じて簡単に設定できることが特徴です。

脆弱性の詳細:認証バイパス (CWE-862) とOSコマンドインジェクション (CWE-78)

この脆弱性は、大きく分けて二つの問題が複合的に発生することで成立します。

9routerはNext.jsのミドルウェア機能を利用して認証を実装していますが、特定のAPIパス(具体的には /api/tunnel/* 系のエンドポイント)がミドルウェアのmatcherリストに含まれていませんでした。これにより、本来認証が必要なはずの /api/tunnel/tailscale-install エンドポイントに、クッキーやJWT、CLIトークンなどの認証情報を一切なしでアクセスできてしまいます。

認証がバイパスされた /api/tunnel/tailscale-install エンドポイントでは、Tailscaleのインストール処理が行われます。この処理中に、リクエストボディから渡される sudoPassword の値が、直接 sudo -S sh コマンドの標準入力に渡されてしまいます。通常、sudo -S sh はパスワードを標準入力から受け取りますが、以下のような特定の条件下では、この動作が悪用されます。

特に危険なシナリオは以下の通りです。

・Node.jsプロセスがroot権限で実行されている場合(例:DockerコンテナでUSERディレクティブを設定していない、systemdユニットでUser=を指定していない場合など)

・Node.jsプロセスが通常のユーザーで実行されているが、そのユーザーが sudo NOPASSWD 設定を持っている場合

これらの条件下では、sudo -S sh はパスワードを要求せずに sh を直接実行します。この際、リクエストボディから渡された sudoPassword の値が sh プロセスの最初のコマンドとして解釈されてしまいます。攻撃者はここに任意のコマンド(例: id > /tmp/pwned.txt; exit 0 のようなペイロード)を挿入することで、サーバー上で好きなコマンドを実行できてしまうのです。

具体的な影響

この脆弱性が悪用されると、攻撃者は認証なしで対象の9routerが動作しているシステム上で、OSコマンドをリモートから実行できてしまいます。特に、Node.jsプロセスがroot権限で動作している場合、システム全体を完全に制御される、最悪のシナリオ(リモートからのroot権限奪取)につながります。

開発環境、CI/CD環境、または本番環境で9routerを使用している場合、機密情報の漏洩、データの改ざん・破壊、マルウェアの埋め込みなど、多大な損害が発生する可能性があります。

脆弱性の再現例 (PoC)

提供されたPoCでは、Dockerコンテナ内でroot権限で9router v0.4.39を起動し、以下のcurlコマンドを実行することで、任意のコマンドが実行されることを示しています。

攻撃コマンドの例: `curl -sN -X POST http://127.0.0.1:20129/api/tunnel/tailscale-install -H 'Content-Type: application/json' -d '{"sudoPassword":"id > /tmp/pwned.txt; exit 0"}'`

このコマンドを実行すると、9routerが動作しているコンテナ内の /tmp/pwned.txt ファイルに、実行ユーザーの情報(root権限で実行されていれば uid=0(root) gid=0(root) groups=0(root) など)が書き込まれます。これは、リクエストボディに含めた id > /tmp/pwned.txt; exit 0 というコマンドが実際に実行されたことを意味します。

直ちにとるべき対策

9routerを使用している、または依存関係に9routerが含まれている場合は、以下の対策を直ちに検討してください。

現時点(GHSA-g6g7-pvmx-m74pの公開時点)で、この脆弱性に対する公式なパッチバージョンに関する具体的な情報はありません。そのため、9routerを使用している場合は、一時的に利用を停止するか、公式な修正バージョンがリリースされるまで代替手段を検討することを強く推奨します。公式のGitHubリポジトリやnpmページで最新情報を確認し、修正版がリリースされ次第、速やかにアップデートしてください。

これは本脆弱性に関わらず、すべてのアプリケーション実行における基本的なセキュリティプラクティスです。Dockerコンテナを使用している場合は、Dockerfileに USER ディレクティブを追加し、root以外のユーザーでプロセスを実行するように設定してください。systemdなどのサービス管理ツールを使用している場合も、サービスユニットファイルで User= を適切に設定し、必要最小限の権限でアプリケーションを動作させることが極めて重要です。

もしアプリケーションを開発している立場であれば、ユーザーからの入力値を信頼せず、常に厳格なバリデーションとサニタイズを行うようにしてください。特にコマンド実行につながる可能性のある入力に対しては、ホワイトリスト方式でのチェックを徹底しましょう。

使用しているすべてのnpmパッケージやその他のライブラリについて、定期的に脆弱性スキャンを実施し、常に最新のセキュリティ情報を把握するように心がけましょう。dependabotやSnykなどのツールを活用することも有効です。

まとめ

「9router」の認証バイパスとOSコマンドインジェクションの組み合わせは、認証なしのリモートコード実行という非常に危険な結果をもたらします。Node.jsアプリケーションを運用する際は、使用するパッケージの選定だけでなく、アプリケーションが動作する環境(実行権限など)にも十分な注意を払うことが不可欠です。本記事を参考に、皆さんのプロジェクトのセキュリティ体制を見直すきっかけにしていただければ幸いです。

← ブログ一覧に戻る