背景
#210 (proof の mode による XSS) の修正作業中に見つかった、同種の構造。
tabState.language は proof.json の language フィールド由来で、無検証のまま採用されている:
packages/verify/src/services/JsonFileProcessor.ts:47 — parsed.language ?? 'unknown'
packages/verify/src/services/ZipFileProcessor.ts:201 — 同上
これが ResultPanel の
codeEl.className = `language-${language} hljs with-line-numbers`;
に到達する。
影響
XSS ではない。 innerHTML ではなく className への代入なので、マークアップ注入は起こらない。攻撃者ができるのは code 要素に任意の CSS クラス名を足すことだけで、現状 verify の CSS に汎用ユーティリティクラス (.hidden など) が無いため実害も確認されていない。
問題は構造のほうで、#210 とまったく同じ「TypeScript の型を信用して proof 由来の値をそのまま使う」パターンが残っていること。将来 verify の CSS にユーティリティクラスが入ると、表示を隠す / 崩すといった悪用が成立しうる。
修正案
mode に対して #210 で入れた normalizeProofMode と同じ方針で、language も allowlist (シンタックスハイライトが対応する言語 ID) で正規化し、未知値は 'unknown' に落とす。
packages/verify/src/services/proofMode.ts (#210 で追加) と同じ場所に置くと、「proof 由来の自己申告ラベルは正規化してから使う」という方針が 1 箇所にまとまる。
あわせて、proof 由来の値を型キャストだけで採用している箇所が他に無いか洗うとよい。
出典
2026-08-02 のプロジェクト全体レビューの follow-up (#210 の修正中に発見)。
背景
#210 (proof の
modeによる XSS) の修正作業中に見つかった、同種の構造。tabState.languageは proof.json のlanguageフィールド由来で、無検証のまま採用されている:packages/verify/src/services/JsonFileProcessor.ts:47—parsed.language ?? 'unknown'packages/verify/src/services/ZipFileProcessor.ts:201— 同上これが
ResultPanelのに到達する。
影響
XSS ではない。
innerHTMLではなくclassNameへの代入なので、マークアップ注入は起こらない。攻撃者ができるのはcode要素に任意の CSS クラス名を足すことだけで、現状 verify の CSS に汎用ユーティリティクラス (.hiddenなど) が無いため実害も確認されていない。問題は構造のほうで、#210 とまったく同じ「TypeScript の型を信用して proof 由来の値をそのまま使う」パターンが残っていること。将来 verify の CSS にユーティリティクラスが入ると、表示を隠す / 崩すといった悪用が成立しうる。
修正案
modeに対して #210 で入れたnormalizeProofModeと同じ方針で、languageも allowlist (シンタックスハイライトが対応する言語 ID) で正規化し、未知値は'unknown'に落とす。packages/verify/src/services/proofMode.ts(#210 で追加) と同じ場所に置くと、「proof 由来の自己申告ラベルは正規化してから使う」という方針が 1 箇所にまとまる。あわせて、proof 由来の値を型キャストだけで採用している箇所が他に無いか洗うとよい。
出典
2026-08-02 のプロジェクト全体レビューの follow-up (#210 の修正中に発見)。