世界を動かす技術を、日本語で。

SVGのサニタイズに関する悩み

2026年4月28日原文(muffin.ink)

概要

  • Scratch はSVG関連の脆弱性を長年抱えている
  • SVGの サニタイズ 対策は毎年新たな問題が発覚し続けている
  • XSSや HTTPリーク など多様な攻撃手法が発見されてきた
  • 複雑化する サニタイズ処理 でも完全な安全性は実現できていない
  • 今後も 新たな脆弱性 が発生し続ける可能性が高い

ScratchにおけるSVGサニタイズの歴史と課題

  • Scratch はユーザー生成SVGをDOMに挿入し、信頼性の高いバウンディングボックス計測などの目的で利用
  • SVGのDOM挿入はどんなに短時間でも 根本的に危険な操作
  • サニタイズのために複雑なパーサやフィルタを増築するアプローチを採用
  • しかし 根本的な解決には至らず、毎年新しい抜け道が発見される状況

2019年:scriptタグによるXSS

  • SVG内の <script>タグ でJavaScriptが実行され、XSSが発生
  • 攻撃者は他ユーザーの権限でコメント投稿・プロジェクト削除等が可能
  • Scratch Desktopでは Node.js統合 により任意コード実行にも発展
  • 正規表現でscriptタグ除去することで一時的に対策

2020年:正規表現の不備によるXSS(CVE-2020-7750)

  • 大文字<SCRIPT> やイベントハンドラ属性(onerror等)で回避可能
  • DOMPurify導入でscript除去を強化

2022年:image要素のhrefによるHTTPリーク

  • <image>要素の href属性 で外部リクエスト発生
  • DOMPurifyは実行コードは除去するがHTTPリークは防げず
  • IPアドレス漏洩 や位置情報推測が可能
  • DOMPurifyのフックで外部URLのhrefを除去することで対策

2023年:CSS @importによるHTTPリーク

  • <style>内の **@import** で外部リクエスト誘発
  • JavaScript製CSSパーサを導入し、@importを除去

2024年:Paper.js経由のXSS

  • サニタイズ前のSVGが Paper.js (コスチュームエディタ用ライブラリ)に渡されXSS
  • scratch-svg-rendererだけでなくPaper.js読み込み時にもサニタイズ適用
  • サーバー側でも何らかの保護があるとされるが詳細不明

2025年:CSS url()によるHTTPリーク

  • CSSの url() 関数で外部リクエスト発生
  • style属性や<style>内のurl()を検出し除去する処理を追加

2026年:サニタイズコードのバグによるHTTPリーク

  • エスケープコード によるurl()の回避
  • style属性内で複数のurl()がある場合の不備
  • CSS変数(var(--name))経由のurl()参照
  • さらなる複雑なサニタイズ処理追加で対応

2026年:長大なCSSトランジションによる全ページ再スタイリング

  • SVG内の 長いtransition と全要素へのtransform適用で、ページ全体のスタイルを攻撃者が操作可能
  • reportボタン非表示、likeボタン巨大化、偽の案内表示など フィッシング 等の悪用例
  • 現在も未修正

2026年:image-set()によるHTTPリーク

  • CSSの image-set() 関数で外部リクエスト発生
  • url()以外の方法でHTTPリークが可能
  • 現時点で未修正

20XX年:新しいCSS仕様による将来的なHTTPリーク

  • CSS Units Level 4やCSS Images Level 4など 新仕様 の実装進展で、また新たな攻撃手法が登場する可能性

サニタイズの限界と今後の展望

  • SVGサニタイズの複雑化 は進むが、イタチごっこの様相
  • SVG仕様・CSS仕様の拡張やブラウザ実装の変化により 新たな抜け道 が定期的に発生
  • 根本的な安全性確保は困難 であり、SVGのDOM挿入自体を極力避ける設計が望ましい
  • Scratchに限らず、 ユーザー生成SVG を扱う全てのサービスで同様のリスクが存在

Hackerたちの意見

ちなみに、Google スライドが SVG サポートを持っていない理由は、15 年近く前からその機能をリクエストするチケットがあるのにね。

ワークアラウンド: https://simonsocolow.com/tech/uploading-svg-to-google-slides...

彼らは完全にサニタイズできるはずなのに、ガジェットプロキシの時と同じように、古いリクエストを修正することを選ばないんだ。私のシートにデータURLサポートを追加するためのチケットみたいに、毎年先送りにされてる。

最初に思ったのは、「実際の使用ケースの90%をカバーするかもしれない小さなサブセットの SVG をサポートする」ってこと。SVGには「塗りつぶしのあるパスの集まり」と「ちょっと危険な賢いもの」の2種類があると思うけど、ほとんどの実際のSVGは前者だよね。これについて120秒以上考えた人に否定されるのを期待してるよ。 :)

ちなみに、同じことを考えたよ。好きな部分をパース(検証はしない)して、入力を再構築または拒否するって感じ。

これがブラウザレベルで新しいフォーマットとして実装されるのが一番いいんじゃないかな。そうじゃないと、「ユーザースペース」で扱うのはすごく遅くて面倒になると思う。

アニメーション付きの SVG は、サニタイズ後にアニメーションが全部消えちゃうことが多い気がする。

あなたの言う通りだと思うけど、こういうことに対する業界標準がないのが致命的だね。人々は、自分が使っているツールから出力された SVG をブラウザに入れたいと思っている。それは不当なリクエストじゃないよね。でも、ツールが何かの obscure SVG 機能を使っている場合、それがフィルタリングされない保証はない。OpenGL と OpenGL ES のような合意された標準が SVG にもあればいいな。SVG-ES。静的でスクリプトなしの要素についてはみんな合意していると思う。

誰かがもう君のアイデアを実装したみたいだよ。 https://tinyvg.tech/

最初に思ったのは「おそらく90%の実際の使用ケースをカバーする小さなサブセットのSVGをサポートすること」だね。リンク先の投稿は、ホワイトリストの代わりにブラックリストを使っている人についてだったみたい。認識できないものを通すなら、サブセットがどんなに小さくても関係ないよ。ほとんどのSVGは安全だし、危険な部分はかなり明白だよ。スクリプトタグ、イメージタグ、feImageタグ、onで始まる属性、HTMLを埋め込むこと、DTDトリック、名前空間トリック、外部のものを読み込むCSS(プレゼンテーション属性も考慮してね。スタイル属性/タグだけじゃないから)。残りはかなり安全だよ。

BIMI/VMCのように、一部の実装で使われているSVG Tinyプロファイルがあるよ。

大人がいないとこうなるんだよね、プロジェクトの過剰拡張が起きる。SVGはスクリプティングをサポートするべきじゃなかった。SVGでスクリプティングが必要なら、別のファイルフォーマットにすればいい。ほとんどのユーザーがロゴをシャープに見せる方法を探していただけなのに、どれだけの時間が無駄になったか想像もつかないよ。

Hacker Newsで議論の続きを見る