stream-md renders untrusted text from LLMs. The default posture is:
- URL sanitizer is on, by default, with no opt-out for
javascript:andvbscript:. These schemes are always rejected from links, images, and autolinks. data:URIs are allowed only for images (and onlydata:image/...;base64,...). All otherdata:schemes (text/html, text/javascript, …) are rejected.- Raw HTML in markdown is disabled by default. Set
allowHtml: trueto opt in; even then, content is rendered into a<pre>(nodangerouslySetInnerHTML). - Inline parser recursion is hard-capped (default 4 levels) to prevent stack overflow from adversarial nesting.
- Document length is hard-capped (default 1 MB) to prevent denial-of-service from oversize input.
- External links receive
target="_blank",rel="noopener noreferrer", andreferrerPolicy="no-referrer"by default to prevent tabnabbing and referrer leaks. - Tables avoid inline
styleattributes — alignment is conveyed via classes (smd-align-left|center|right) so strict CSPs (no'unsafe-inline'for styles) work.
- It does not sanitize raw HTML even when
allowHtml: true. If you need to allow user-authored HTML safely, run it through DOMPurify yourself first. - It does not validate that a URL points at a reachable host. A sanitized URL is one with a known-safe scheme; the destination is still attacker-controlled.
import { sanitizeUrl } from 'stream-md';
sanitizeUrl('javascript:alert(1)'); // null (rejected)
sanitizeUrl('https://x.com'); // 'https://x.com'
sanitizeUrl('weird:thing', { allowedProtocols: ['weird'] }); // 'weird:thing'For images:
import { sanitizeImageUrl } from 'stream-md';
sanitizeImageUrl('data:image/png;base64,…'); // allowed
sanitizeImageUrl('data:image/png;base64,…', { allowDataImages: false }); // nullPlease email security reports to the maintainer at the address listed in package.json#funding rather than filing a public GitHub issue. We aim to acknowledge within 72 hours and ship a fix within 14 days for high-severity issues.