[高深刻度RCE] Nuxt Server Islandにおけるランタイムテンプレートインジェクションの脆弱性について
はじめに
Nuxtアプリケーション開発者の皆さん、重要なセキュリティ情報です。NuxtのServer Island機能に、高深刻度(High Severity)のリモートコード実行(RCE)を可能にする脆弱性(GHSA-9473-5f9j-94wq / CVE-2026-71320)が報告されました。この脆弱性は、特定の条件下で攻撃者がNuxtサーバープロセス上で任意のコードを実行できてしまう可能性があります。この記事では、脆弱性の詳細、影響を受ける条件、そして対応策について、日本のフロントエンドエンジニア向けに分かりやすく解説します。
脆弱性の概要:Nuxt Server Islandのテンプレートインジェクション
この脆弱性は、NuxtのServer Island機能が`/__nuxt_island/`エンドポイント経由でプロップスを受け取る際に発生します。具体的には、攻撃者がプロップスに悪意のある`template`キーを注入できてしまうというものです。
もし`vue.runtimeCompiler: true`が有効な場合(デフォルトでは`false`)、注入された`template`の内容がVueのランタイムテンプレートコンパイラによってサーバープロセス内でコンパイル・実行されてしまいます。これにより、Nuxtサーバー上で任意のコードを実行するサーバーサイドのリモートコード実行(RCE)が可能となります。
脆弱性の発生条件と影響
この脆弱性が実際に悪用されるには、以下の**2つの主要な条件**が同時に満たされる必要があります。
1. **`vue.runtimeCompiler: true` が有効であること**
Nuxtではデフォルトで`vue.runtimeCompiler: false`に設定されています。したがって、ほとんどのNuxtアプリケーションはこの条件を満たさないため、影響を受けません。しかし、明示的に`true`に設定している場合は注意が必要です。
2. **Server Islandが動的コンポーネント解決にプロップスを渡していること**
アプリケーション内に、攻撃者から制御可能な値をVueの動的コンポーネント解決(例: `<component :is>`, `resolveDynamicComponent`, `h()`、または`@nuxt/ui`などのライブラリが提供する`as`/`asChild`プロップスなど)に渡しているServer Islandコンポーネントが存在する場合に、この条件が満たされます。
重要な点として、開発者が明示的にプロップスを転送していなくても、アイランドコンポーネントのルート要素が多態的なプロップス(`as` / `asChild`など)を受け入れる場合、未宣言のアイランドプロップスが属性としてフォールスルーする(標準のVue属性継承)ため、脆弱性が発生する可能性があります。例えば、`@nuxt/ui`の`UButton`をルートに持つシンプルなServer Islandでも、この経路で脆弱になる可能性があります。
例:以下のようなServer Islandは、`as`プロップスがフォールスルーする可能性があり、注意が必要です。
```vue\n<!-- components/MyWidget.server.vue -->\n<template>\n <UButton>Save</UButton>\n</template>\n```
これらの条件が満たされると、攻撃者は`/__nuxt_island/`エンドポイントに対して特別なJSONペイロード(例: `{"as": {"template": "<attacker-controlled>"}}`)を送信することで、Nuxtサーバープロセス上で任意のJavaScriptコードを実行できてしまいます。これは極めて危険な状態です。
影響を受けるNuxtのバージョン
この脆弱性の影響を受けるのは以下のNuxtバージョンです。
- Nuxt `>=3.4.0` から `<3.21.10`
- Nuxt `>=4.0.0` から `<4.5.1`
また、これらのバージョンであっても、`vue.runtimeCompiler: true`が有効であり、かつServer Islandが使用されている場合にのみ影響を受けます。Nuxt 2系はServer Island機能がないため影響を受けません。
対応策:すぐにアップグレードを!
最も推奨される対応策は、**Nuxtを修正済みバージョンにアップグレードすること**です。
- Nuxt `4.x`系をご利用の場合: `nuxt@4.5.1` 以上にアップグレード
- Nuxt `3.x`系をご利用の場合: `nuxt@3.21.10` 以上にアップグレード
修正済みバージョンでは、`vue.runtimeCompiler`が有効な場合、デコードされたプロップスに`template`キーが含まれているリクエストをHTTP 400エラーで拒否するガードが実装されています。これにより、不正なテンプレートインジェクションを防ぎます。
アップグレードが困難な場合の回避策
すぐにアップグレードできない場合でも、以下の回避策を適用することでリスクを軽減できます。
1. **`vue.runtimeCompiler` を `false` に設定する**
これが最も効果的な回避策です。アプリケーションの設定で`vue.runtimeCompiler: false`になっていることを確認してください。デフォルト設定であれば、この脆弱性の主要な前提条件を満たしません。
2. **動的コンポーネント解決へのプロップス転送を制限する**
Server Islandコンポーネント内で、攻撃者から渡される可能性のあるプロップスを、`<component :is>`, `resolveDynamicComponent`, `h()`、またはポリモーフィックな`as`/`asChild`プロップスに直接渡さないようにコードを見直してください。もし渡す必要がある場合は、厳密なサニタイズ処理を実装してください。
3. **WAF (Web Application Firewall) を導入する(防御的措置)**
WAFを導入し、`/__nuxt_island/`パスへのリクエストにおいて、URLデコードおよびJSONパースされたプロップス値に`template`または`render`という名前のプロパティが含まれている場合に、そのリクエストをブロックするルールを設定します。ただし、この方法はエッジレベルでの防御に過ぎず、SSR内部のアイランドレンダリングには適用されないため、完全な解決策ではないことに注意してください。
まとめ
このNuxtの脆弱性は、特定の限定的な条件下でリモートコード実行という深刻な影響をもたらす可能性があります。特に、開発環境や本番環境で`vue.runtimeCompiler: true`を設定しているアプリケーションは、速やかに対応状況を確認し、アップグレードまたは回避策を適用することが強く推奨されます。
フロントエンド開発においても、依存ライブラリの脆弱性情報には常にアンテナを張り、迅速な対応を心がけましょう。