FlawOpen

flawopen.com/Teardowns/cve-2026-102422-shell-quote-comment-line-terminator-injection

● CVE-2026-102422 · CVSS 8.1 · 高
セキュリティ研究 · FlawOpen

CVE-2026-102422: shell-quote のコメントトークン注入

shell-quote 1.11.0 より前では、コメントトークンの後に改行終端文字を含む文字列が続くと、引用済み出力を POSIX シェルに渡した際に意味が変わる可能性がありました。攻撃者がトークンに影響でき、アプリが quote() を呼び、その出力をシェルで実行することが条件です。1.11.0 以降へ更新してください。

💡 わかりやすい解説 (ELI5)

荷札のコメントは、その行の残りを隠せます。次の部分に改行が含まれると、コメントがそこで終わり、その後の内容が再び見えるようになります。この不具合では、後続トークンがシェル向けの引用出力でその状態を作れてしまいました。

主要な概念と専門用語

shell-quote
シェル形式のトークンを解析・引用する JavaScript パッケージです。出力はシェル構文向けであり、汎用の安全な文字列形式ではありません。
コメントトークン
シェルのコメント構文を表すトークンです。行終端文字が現れるまで後続テキストに影響します。
行終端文字
CR、LF、U+2028、U+2029 などの行境界で、シェルはコメントの終わりとして扱うことがあります。
CWE-78
OS コマンド内の特殊要素を適切に無害化できていない問題です。

フレームワーク対応

  • このガイドで説明する弱点の CWE 参照: CWE-78

根本原因の分析 (Root Cause)

影響を受ける quote() の経路は、コメントトークン自体に含まれる行終端文字を拒否していましたが、コメントを出力した状態を記録していませんでした。そのため後続の文字列トークンに行終端文字を含められました。攻撃者が影響できるトークンが quote() に渡され、返されたテキストが POSIX シェルで実行されると、行境界がコメントを終わらせ、後続テキストがシェル構文として解析されます。上流修正はコメント状態を記録し、それ以降のすべての文字列トークンで行終端文字を拒否します。これは、コメントトークン自体の行終端文字を拒否した CVE-2026-9277 の修正とは別の問題です。メンテナーは High / CVSS 3.1 8.1 と評価し、Ubuntu は別途 CVSS 4.0 9.2 Critical と評価しています。CVSS の版が異なるため、数値を同列に扱えません。

ステップ・バイ・ステップの攻撃フロー

ステップ 1

トークンが引用関数に届く

アプリがコメントと後続文字列を含むトークン列を作ります。攻撃者がその列に影響できる必要があります。

ステップ 2

関数がコメント構文を出力する

1.11.0 より前の quote() はコメント本文を検査しますが、その後に文字列が続くことを記録しませんでした。

ステップ 3

後続トークンに行境界が含まれる

CR、LF、U+2028、U+2029 によってシェルコメントが終わる可能性があります。

ステップ 4

アプリが出力をシェルで実行する

文書化された解釈の対象は、出力を POSIX シェルに渡す呼び出し元です。

ステップ 5

更新版が危険な列を拒否する

1.11.0 はコメント状態を記録し、後続文字列に行終端文字があれば例外を発生させます。

ソースコード比較:脆弱 vs 堅牢化

脆弱な抜粋はコメントトークン内の行終端文字を検査しますが、後続文字列の状態を記録しません。上流の変更ではコメントを出力した状態を記録し、行終端文字を含む後続文字列を拒否します。この抜粋は解析と引用の境界を示すもので、エクスプロイトやシェルコマンドではありません。

ソース抜粋: quote.js — focused upstream diff hunks

脆弱な実装
// commit 6002b2e 適用前の quote.js — コメントトークン部分の抜粋
if ('comment' in s && typeof s.comment === 'string') {
  if (LINE_TERMINATORS.test(s.comment)) {
    throw new TypeError('`comment` must not contain line terminators');
  }
  return '#' + s.comment;
}
堅牢化されたセキュアパッチ
// commit 6002b2e 適用後の quote.js — 追加されたガードとコメント状態の正確な抜粋
var sawComment = false;
return xs.map(function (s) {
  if (sawComment && typeof s === 'string' && LINE_TERMINATORS.test(s)) {
    throw new TypeError('a token after a `comment` must not contain line terminators');
  }
  if ('comment' in s && typeof s.comment === 'string') {
    if (LINE_TERMINATORS.test(s.comment)) {
      throw new TypeError('`comment` must not contain line terminators');
    }
    sawComment = true;
    return '#' + s.comment;
  }
});

エンジニアリング&システム堅牢化チェックリスト

参考資料