Skip to content

Harden chat HTML sanitiser: poster/background/cite, inline style, remote media src - #3866

Merged
mstomar125 merged 2 commits into
mainfrom
issue-3864-sanitiser-hardening
Oct 22, 2026
Merged

mstomar125 merged 2 commits into
mainfrom
issue-3864-sanitiser-hardening

Conversation

@mstomar125

@mstomar125 mstomar125 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Refs #3864

Defence in depth for the chat HTML sanitiser (the CSP already blocks these at load time in the shipped app).

Changes

  • poster, background and cite are now covered. cite is held to the link allow-list; poster and background fetch on their own, so they follow the media rule below.
  • Inline style is removed (DOMPurify FORBID_ATTR) rather than filtered. Chat markdown never emits inline style, so there is nothing to keep, and a filter for url(), image-set() and position:fixed would be a second parser to get wrong.
  • Attributes the browser fetches without a click (src, poster, background) now accept only a relative reference. img (and poster/background) may also carry data:image/(png|jpeg|gif|webp). Remote https:// on img, audio, video, source and track is dropped. href behaviour is unchanged.
  • href / xlink:href on anything other than a and area (svg image, feImage, use) is fetched by the browser, so it follows the same relative / data:image rule as src. Anchors keep the link allow-list.
  • <style> elements are forbidden (FORBID_TAGS), including inside svg; app styles live in the Svelte component, not in message HTML.
  • action / formaction are dropped.
  • daemon_setup.rs: the "bundle changed while it was being installed" re-check after the rename is now ensure_bundle_unchanged, with a unit test (changed size, vanished bundle, unchanged passes).

User-visible change

Remote markdown images (![alt](https://...)) and remote <img> in AI replies no longer render. This is the intended privacy trade: no tracking pixel or IP leak from a message.

Tests

Browser vitest (real Chromium + DOMPurify) for each point; each was mutation-checked (cite, poster/background, style, remote-src, data-image-on-non-img) and fails without its change. The Rust test fails when the check is stubbed out.

Not done

  • ping, longdesc and data attributes are unchanged (srcset was already dropped).
  • The race itself (bundle replaced mid-install) is not reproduced end to end; only the check is tested.

🤖 Generated with Claude Code

mstomar125 and others added 2 commits October 22, 2026 06:39
…ote media src

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…rm targets

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant