Apply safe_href scheme allowlist to images in safe_mode#714
Conversation
process_anchor() validates link URLs against _safe_href (allowlist: http(s)/ftp/mailto/tel) in safe_mode, but process_image() only ran the src through _protect_url(), which escapes <>"' but does not restrict the URL scheme. As a result, in safe_mode an image like `)` rendered as `<img src="javascript:alert(1)">` — inconsistent with how `<a href>` is handled. This is defense-in-depth (javascript: does not execute in <img src> on modern browsers), but the inconsistency is surprising for a sanitizer and could matter for non-browser / legacy HTML consumers. Apply the same allowlist to images; legitimate absolute/relative image URLs are unaffected, and default (non-safe) mode is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Sounds sane but has some failing tests that look a bit concerning |
The previous version applied the full `_safe_href` allowlist to images, which stripped legitimate `data:image/...` and quote-escaped `http` src values that markdown2 intentionally supports (broke data_urls_in_safe_mode, basic_safe_mode, issue603_xss). Keep markdown2's existing image model (quote-escaping via _protect_url) and only neutralize `javascript:`/`vbscript:` schemes, which are never valid for an <img src> and exist purely as XSS vectors. All 234 tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Good catch, thanks — you were right to be wary. The original diff was too broad: it applied the full I have narrowed it to keep markdown2's existing image model (quote-escaping via To be transparent: this is defense-in-depth — 🤖 Addressed by Claude Code |
Summary
In
safe_mode,process_anchor()validates link URLs against_safe_href(allowlist:
http(s),ftp,mailto,tel), butprocess_image()only passesthe
srcthrough_protect_url(), which escapes<>"'but does not restrict theURL scheme. So in
safe_mode:while the equivalent link is correctly neutralized to
href="#". This is aninconsistency within the sanitizer's own model.
Impact
To be clear, this is not an exploitable XSS:
javascript:/data:URIs do notexecute in
<img src>on modern browsers. I'm raising it as defense-in-depth /consistency — the behavior is surprising for a sanitizer and could matter for
non-browser or legacy HTML consumers of the output.
Fix
Apply the same
_safe_hrefscheme allowlist to images that links already use.Behavior before/after (
safe_mode='escape'))src="javascript:alert(1)"src=""src=""safe_mode)Legitimate absolute/relative image URLs are unaffected, and default (non-safe) mode
is unchanged.