streaming-markdown@0.2.15 preserves arbitrary URL schemes in href/src.
Verified with a Node + jsdom harness:
IN : [click](javascript:alert(1))
OUT: <p><a href="javascript:alert(1">click</a>)</p> ← XSS vector
Confirmed unsafe for: javascript:, vbscript:, data:text/html, file://.
The library uses only safe DOM primitives (createElement/appendChild/
createTextNode — no innerHTML/eval), so <script> tags are escaped as
text, but URL-scheme filtering is absent. The existing renderMd() path
implicitly filtered to http(s) via its regex, so this is a regression
the moment streaming markdown is enabled.
Attack path: agent echoes prompt-injection content containing a
markdown link with javascript: href → smd renders it live → user clicks
during the streaming window → JS executes in webui origin → session
cookie, API calls, etc.
Fix: walk the live DOM after each parser_write (and again after
parser_end) and remove href/src attributes whose scheme isn't on the
safe allowlist (http, https, mailto, tel, and relative/anchor paths).
Blocked anchors keep their text content but lose href; blocked images
lose src and get data-blocked-scheme="1" for debugging.
Harness confirms all 10 tested cases behave correctly — javascript:,
vbscript:, data:text/html, file:// all stripped; https://, /path,
#anchor, mailto:, tel: all preserved.
Added 5 regression tests in TestSmdUrlSchemeSanitization that lock:
- the sanitize helper exists
- the allowlist regex permits https? and forbids javascript/vbscript/data:
- _smdWrite invokes sanitize after parser_write
- _smdEndParser invokes sanitize after parser_end
- the sanitizer covers both <a href> and <img src>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>