LiquidJSにDoSの脆弱性 (GHSA-g357-x5c3-c72p / CVE-2026-55575) が発覚 - フロントエンド開発者は要確認
はじめに
日本のフロントエンドエンジニアの皆さん、こんにちは!Node.js環境での開発において、LiquidJSのようなテンプレートエンジンはサーバーサイドレンダリングや静的サイトジェネレーターなどで活用されることも多いかと思います。今回は、そのLiquidJSに報告された深刻度「High」の脆弱性(GHSA-g357-x5c3-c72p / CVE-2026-55575)について解説します。この脆弱性は、適切に対処しないとサービス拒否(DoS)攻撃につながる可能性があるため、LiquidJSをプロジェクトで利用している方はぜひご一読ください。
脆弱性の概要と仕組み
LiquidJSには、テンプレートのレンダリングが過剰なメモリを消費するのを防ぐために`memoryLimit`という設定が設けられています。これにより、悪意のある入力によってサーバーのメモリが枯渇するのを防ぐ役割があります。しかし、今回問題となっているのは配列の末尾から要素を削除する`| pop`フィルターの挙動です。
`| pop`フィルターは、内部で入力配列の完全なコピーを作成する際に、そのコピーにかかるメモリ使用量を`memoryLimit`に報告する処理が漏れていることが判明しました。他の同様の配列操作フィルター(例:`| shift`)は正しくメモリ使用量を報告するのに対し、`| pop`フィルターはこの報告を怠っていたため、意図しない見落としとして脆弱性となってしまったのです。
結果として、たとえ`memoryLimit`が厳しく設定されていても、攻撃者が長さを操作できる非常に大きな配列(例:数百万要素)に対して`{{ user_input_array | pop }}`のようなテンプレートが適用されると、メモリ制限を無視して大量のメモリが消費されてしまいます。これによりNode.jsプロセスのヒープメモリが枯渇し、最終的にはサーバーがクラッシュするサービス拒否(DoS)攻撃が引き起こされる可能性があります。
影響を受ける条件とリスクシナリオ
この脆弱性は、現在の`| pop`フィルター実装を搭載するすべてのLiquidJSバージョン(`10.27.0`以降のバージョンも含む)に影響します。特に、以下のような条件下でリスクが高まります。
1. サーバーが、ユーザーからの入力など、信頼できないソースによって長さが影響を受ける配列をテンプレートのコンテキストとして渡している場合。 2. そのテンプレート内で`| pop`フィルターが使用されている場合。
攻撃者は、これらの条件を満たすシステムに対し、意図的に非常に長い配列をサーバーに送信することで、テンプレートのレンダリング時に大量のメモリを消費させ、DoS攻撃を成功させることができます。これは、単にCPU使用率を高めるDoS攻撃とは異なり、サーバーリソースの根幹を狙うため、より深刻な問題と言えるでしょう。
具体的な対策
LiquidJS本体の根本的な修正がリリースされるまでの間、以下のいずれかの方法で対応を検討してください。
最も手軽な対策として、信頼できない長さの配列を入力とするテンプレートでの`| pop`フィルターの使用を避けることです。配列の最後の要素を取り除きたい場合、以下のように他のフィルターを組み合わせて代替することが可能です。
代わりに、`{{ user_input_array | slice: 0, (user_input_array.size | minus: 1) }}` のように、`| slice`フィルターと`| minus`フィルターを組み合わせて、末尾の要素を除外した配列を作成します。これにより、メモリ使用量が適切に管理されます。
LiquidJSの`liquid.registerFilter`機能を使用して、既存の`| pop`フィルターを上書きし、メモリ課金処理を追加したカスタムフィルターを登録する方法です。これにより、LiquidJSの`memoryLimit`設定が正しく機能するようになります。
以下に、カスタムフィルターの登録例を示します。Node.jsでLiquidJSインスタンスを作成している箇所に追記してください。 ```javascript const { Liquid } = require('liquidjs'); const liquid = new Liquid(); // カスタムpopフィルターを登録し、メモリ課金処理を追加 liquid.registerFilter('pop', function (arr) { // 配列でない場合は元のLiquidJSの動作に合わせるか、適切にハンドリング if (!Array.isArray(arr)) { return arr; } // 配列のコピーを作成する前に、そのメモリ使用量を報告 // これによりmemoryLimitが適切にチェックされます this.context.memoryLimit.use(arr.length); // 元のpopフィルターと同様に、末尾の要素を除いた新しい配列を返す const newArr = arr.slice(0, arr.length - 1); return newArr; }); ``` この修正により、`memoryLimit`を超過するような巨大な配列が`| pop`フィルターに渡された場合、標準の`memory alloc limit exceeded`例外がスローされ、DoS攻撃を防ぐことができます。
根本的な解決策(将来的な修正)
最終的な解決策としては、LiquidJS本体の`| pop`フィルターに`this.context.memoryLimit.use(array.length)`の1行を追加する修正が必要です。この修正は現在、コミュニティによって検討・実装が進められていると予想されます。そのため、LiquidJSの公式アップデートを継続的に監視し、修正がリリースされ次第、バージョンアップを適用することが最も確実な対策となります。
まとめ
LiquidJSを使用しているフロントエンドエンジニアの皆さんは、今回解説したDoS脆弱性(GHSA-g357-x5c3-c72p / CVE-2026-55575)を認識し、プロジェクトへの影響を確認することが非常に重要です。特に、ユーザー入力がLiquidJSのテンプレートで処理され、かつ`| pop`フィルターが使われている箇所がないかを確認してください。
当面の対策として、テンプレートの修正またはカスタムフィルターの適用を速やかに検討し、サーバーの安定稼働を守りましょう。また、ライブラリのセキュリティ情報は常にキャッチアップし、最新バージョンへのアップデートを怠らないことが、継続的なセキュリティ対策の鍵となります。