Modern Frontend CVEs

対象CVE: CVE-2026-106102

[技術解説] Quasar Framework SSRにおけるCriticalなXSS脆弱性 (CVE-2026-106102)

Quasar FrameworkのSSR機能におけるHTMLエスケープ処理の不備により、重要度の高いXSS脆弱性が発見されました。ユーザー入力が直接HTMLに埋め込まれることで、セッションハイジャックなどの重大な被害に繋がる可能性があります。

はじめに

日本のフロントエンドエンジニアの皆さん、こんにちは。今回は、人気のあるVue.jsフレームワーク、Quasar Frameworkのサーバーサイドレンダリング (SSR) 機能に発見された、深刻度「Critical」なクロスサイトスクリプティング (XSS) 脆弱性 (GHSA-pq96-jpmf-w254 / CVE-2026-106102) について技術的な解説を行います。Quasarを利用している方はもちろん、一般的なSSRアプリケーションを開発している方にとっても、非常に重要な情報となります。

脆弱性の概要と問題点

この脆弱性は、「Quasar Framework: Stored/Reflected XSS via unescaped SSR meta tag rendering in getHead()」と題されており、QuasarのSSR処理において、メタタグ(`<title>`, `<meta>`, `<link>`, `<script>`など)のレンダリング時にHTMLエンティティエスケープが適切に行われていなかったことに起因します。具体的には、`ui/src/plugins/meta/Meta.js` ファイル内の `getHead()` および `getAttr()` 関数が問題の箇所でした。

Quasarでは、ページタイトルやメタディスクリプションなどを設定するために `useMeta()` コンポーザブルを提供しています。このコンポーザブルで設定されたデータは、クライアントサイドでは `document.createElement(...)` や `tag.setAttribute(att, val)` といったDOM APIを通じて処理されます。DOM APIは属性値を自動的にエスケープするため、クライアントサイドのパスは安全でした。しかし、SSR時には `getHead()` 関数がテンプレートリテラルと文字列結合によって生でHTML文字列を構築しており、この際にHTMLエンティティエスケープが全く行われていませんでした。

これにより、`title`、`meta.*.content`、`link.*.href`、その他の属性値として提供された文字列に `</title>`、`"`、`>` などの特殊文字が含まれていると、本来のHTMLコンテキストから逸脱し、任意のHTMLマークアップやスクリプトが注入されてしまう状態でした。

攻撃シナリオと深刻なインパクト

この脆弱性を悪用した攻撃は、以下のようなシナリオで発生し得ます。

1. Quasar SSRアプリケーションが、ブログ記事のタイトルや製品の説明など、動的なコンテンツを `useMeta()` を使ってページメタデータとしてレンダリングします。

2. 攻撃者が、その動的コンテンツ(例: ブログ記事のタイトル、ユーザーのプロフィール名など)に悪意のある文字列(例: `My Post</title><script>alert(document.cookie)</script>`) を挿入します。

3. 被害者が、攻撃者のコンテンツを含むページにアクセスすると、QuasarのSSR処理によって `getHead()` が悪意のある文字列をエスケープせずにHTMLレスポンスの `<head>` に埋め込みます。

4. 被害者のブラウザは、この生で注入されたスクリプトを、ハイドレーション前(アプリケーションが完全にロードされる前)に実行します。これにより、攻撃者は被害者のセッションCookieを盗んだり、クレデンシャルを詐取するフィッシングオーバーレイを表示させたり、アカウントを乗っ取ったり、ウェブサイトを改ざんしたりと、様々な重大な被害を引き起こすことが可能になります。

この脆弱性は認証不要で悪用可能であり、ブログのタイトル、製品名、ユーザーの表示名など、非常に一般的なユーザー入力がトリガーになり得るため、影響範囲が非常に広いのが特徴です。CWE-79 (Cross-Site Scripting) に分類されます。

脆弱性のあるコードの例

以下は、脆弱性のある `ui/src/plugins/meta/Meta.js` の関連部分です。`getAttr` や `getHead` 関数内で、`val` や `meta.title` がエスケープされずに直接HTML文字列に埋め込まれていることが問題でした。

```js function getAttr(seed) { return att => { const val = seed[att] return att + (val !== true && val !== void 0 ? `="${val}"` : '') } } function getHead(meta) { let output = '' if (meta.title) { output += `<title>${meta.title}</title>` } ;['meta', 'link', 'script'].forEach(type => { const metaType = meta[type] for (const att in metaType) { const attrs = Object.keys(metaType[att]) .filter(item => item !== 'innerHTML') .map(getAttr(metaType[att])) output += `<${type} ${attrs.join(' ')} data-qmeta="${att}">` if (type === 'script') { output += (metaType[att].innerHTML || '') + '</script>' } } }) return output } ```

推奨される修正と対策

この脆弱性に対する修正は、HTMLエンティティエスケープを行うヘルパー関数 `escapeHtml()` を導入し、タイトルや属性値に適用することです。これにより、特殊文字がそのままHTMLとして解釈されるのを防ぎます。

```js function escapeHtml(val) { return String(val) .replaceAll('&', '&amp;') .replaceAll('<', '&lt;') .replaceAll('>', '&gt;') .replaceAll('"', '&quot;') } function getAttr(seed) { return att => { const val = seed[att] return att + (val !== true && val !== void 0 ? `="${escapeHtml(val)}"` : '') } } function getHead(meta) { let output = '' if (meta.title) { output += `<title>${escapeHtml(meta.title)}</title>` } // ... rest unchanged, script innerHTML intentionally left raw (JSON-LD use case) } ```

修正点としては、特に `escapeHtml(val)` が `val` に適用されていることが重要です。これにより、例えば `title` や属性値に含まれる `"` が `&quot;` に変換され、属性値のコンテキストから抜け出すことができなくなります。`script` タグ内の `innerHTML` は、JSON-LDなどの正規な用途を考慮して意図的にエスケープされていませんが、これを利用する際は別途セキュリティ対策が必要です。

日本のフロントエンドエンジニアへの提言

現在Quasar Frameworkを利用しているプロジェクトでは、直ちにQuasarを修正済みの最新バージョンにアップデートすることを強く推奨します。公式アナウンスを確認し、速やかに対応してください。特にSSRを利用しているアプリケーションは優先度高く対応が必要です。

今回の件は、Quasarに限らず、SSRを利用するあらゆるフレームワークや自作のレンダリングロジックにおいて教訓となります。以下の点を再認識し、安全なアプリケーション開発に努めましょう。

1. **出力時のエスケープを徹底する**: ユーザーから入力されたデータや、信頼できない外部ソースからのデータは、HTMLに表示する前に必ず適切なHTMLエンティティエスケープを施す必要があります。特にSSRでは、クライアントサイドのDOM APIのような自動エスケープ機構がない場合が多いため、開発者自身が責任を持ってエスケープ処理を実装・確認する必要があります。

2. **クライアントサイドとSSRの動作の違いを理解する**: クライアントサイドとSSRでは、HTMLの生成方法やセキュリティに関する前提が異なることがあります。両者の違いを理解し、それぞれに合ったセキュリティ対策を講じることが重要です。

3. **フレームワークの内部実装にも目を向ける**: フレームワークが提供する便利な機能であっても、その内部でどのような処理が行われているかを理解することで、潜在的な脆弱性に気づくことができます。今回のように、一見安全に見える `useMeta()` のようなAPIのSSR実装に問題があったケースもあります。

4. **セキュリティ診断・コードレビューの実施**: 静的解析ツールやセキュリティ専門家による診断、そして開発チーム内でのコードレビューを通じて、セキュリティ上の問題点を早期に発見する体制を構築することが重要です。

まとめ

Quasar FrameworkのSSRにおけるXSS脆弱性は、HTMLエスケープ処理の不備という基本的なミスから生じたものです。しかし、その影響は非常に大きく、ユーザーのセッションハイジャックなど、取り返しのつかない被害に繋がりかねません。日本のフロントエンドエンジニアとして、常に最新の脆弱性情報にアンテナを張り、開発しているアプリケーションのセキュリティ強度を高める努力を続けていきましょう。

← ブログ一覧に戻る