From b80e577a5feed0eb866fa3f48308300e14ec4b7f Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 12 Oct 2026 06:04:46 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]=20Fi?= =?UTF-8?q?x=20mXSS=20vulnerabilities=20in=20manual=20SVG=20sanitization?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: bobdivx <6737167+bobdivx@users.noreply.github.com> --- .jules/sentinel.md | 4 ++++ apps/web/src/lib/markdown-rich.test.tsx | 3 +-- apps/web/src/lib/sanitize-svg.ts | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 .jules/sentinel.md diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000000..ffc0bd2ced --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2026-10-12 - [Improved SVG Sanitization against mXSS] +**Vulnerability:** The manual SVG sanitizer `apps/web/src/lib/sanitize-svg.ts` used an insufficient allowlist/blocklist. It allowed ``, ``, ``, ``, ``, and `` which could lead to mutation XSS (mXSS) and other attack vectors when rendering untrusted Mermaid or Math blocks. +**Learning:** Manual DOM tree sanitization is notoriously hard to get right because attackers can hide active elements (e.g. `` tags with `javascript:` payloads) inside grandchild trees (like ``) or use SVG-specific tricks (like ``) which naive list-based cleaners overlook. +**Prevention:** Rather than adding heavy third-party dependencies (like DOMPurify) against explicit project instructions, expanding the `BLOCKED` Set to include these structural injection vectors provides a robust, zero-dependency mitigation. Future expansions should verify nested elements carefully. diff --git a/apps/web/src/lib/markdown-rich.test.tsx b/apps/web/src/lib/markdown-rich.test.tsx index 64655ecb4a..9d06cb7b64 100644 --- a/apps/web/src/lib/markdown-rich.test.tsx +++ b/apps/web/src/lib/markdown-rich.test.tsx @@ -72,7 +72,6 @@ describe('Markdown riche (P5-01)', () => { it('sanitizeSvg retire scripts et gestionnaires', () => { const out = sanitizeSvg(''); - expect(out).not.toMatch(/script|onload|javascript/); - expect(out).toContain('href="https://e.x/a.png"'); + expect(out).not.toMatch(/script|onload|javascript|image/); }); }); diff --git a/apps/web/src/lib/sanitize-svg.ts b/apps/web/src/lib/sanitize-svg.ts index a2810cb344..349367a1fa 100644 --- a/apps/web/src/lib/sanitize-svg.ts +++ b/apps/web/src/lib/sanitize-svg.ts @@ -2,7 +2,7 @@ * Nettoyage défensif d'un SVG produit par mermaid (déjà en `securityLevel: 'strict'`) : * pas de script, pas de gestionnaire `on*`, pas de lien hors ancre/http(s). */ -const BLOCKED = new Set(['script', 'iframe', 'object', 'embed', 'link', 'meta', 'base', 'form', 'input', 'textarea', 'button']); +const BLOCKED = new Set(['script', 'iframe', 'object', 'embed', 'link', 'meta', 'base', 'form', 'input', 'textarea', 'button', 'foreignobject', 'use', 'animate', 'set', 'image', 'math']); const SAFE_LINK = /^(#|https?:\/\/)/i; export function sanitizeSvg(svg: string): string {