{"id":"GHSA-3rcm-vjrc-p45j","summary":"JustHTML has a Sanitizer Bypass (in Markdown)","details":"## Summary\n\n`to_markdown()` does not sufficiently escape text content that looks like HTML. As a result, untrusted input that is safe in `to_html()` can become raw HTML in Markdown output.\n\nThis is not specific to tokenizer raw-text states like `\u003ctitle\u003e`, `\u003cnoscript\u003e`, or `\u003cplaintext\u003e`, although those states can trigger the behavior. The root cause is broader: Markdown text serialization leaves angle brackets unescaped in text nodes.\n\n## Details\n\nWhen converting a parsed document to Markdown, text nodes are escaped for a small set of Markdown metacharacters, but HTML-significant characters such as `\u003c` and `\u003e` are preserved. That means content parsed as text, including entity-decoded text or text produced by RCDATA/RAWTEXT-style parsing, can be emitted into Markdown as raw HTML.\n\nExamples of affected input include:\n\n- Text produced from entity-decoded input such as `&lt;script&gt;...&lt;/script&gt;`\n- Text inside elements like `\u003ctitle\u003e`, `\u003ctextarea\u003e`, `\u003cnoscript\u003e` (when parsed as raw text), and `\u003cplaintext\u003e`\n\nThis is distinct from actual `\u003cscript\u003e` or `\u003cstyle\u003e` elements in the DOM. Those are already dropped by default in `to_markdown()` unless `html_passthrough=True`.\n\n## Proof of Concept\n\n### General case\n\n```python\nfrom justhtml import JustHTML\n\ndoc = JustHTML(\"\u003cp\u003e&lt;img src=x onerror=alert(1)&gt;\u003c/p\u003e\", fragment=True)\n\nprint(doc.to_html())\nprint()\nprint(doc.to_markdown())","aliases":["CVE-2026-8445"],"modified":"2026-08-24T03:56:00.500786004Z","published":"2026-03-18T20:19:56Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2026-03-18T20:19:56Z","nvd_published_at":null,"cwe_ids":["CWE-79"],"severity":"MODERATE"},"references":[{"type":"WEB","url":"https://github.com/EmilStenstrom/justhtml/security/advisories/GHSA-3rcm-vjrc-p45j"},{"type":"PACKAGE","url":"https://github.com/EmilStenstrom/justhtml"}],"affected":[{"package":{"name":"justhtml","ecosystem":"PyPI","purl":"pkg:pypi/justhtml"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"1.12.0"}]}],"versions":["0.1.0","0.10.0","0.11.0","0.12.0","0.13.0","0.13.1","0.14.0","0.15.0","0.16.0","0.17.0","0.18.0","0.19.0","0.2.0","0.20.0","0.21.0","0.22.0","0.23.0","0.24.0","0.25.0","0.26.0","0.27.0","0.28.0","0.29.0","0.3.0","0.30.0","0.31.0","0.32.0","0.33.0","0.34.0","0.35.0","0.36.0","0.37.0","0.38.0","0.39.0","0.4.0","0.40.0","0.5.0","0.5.1","0.5.2","0.6.0","0.7.0","0.8.0","0.9.0","1.0.0","1.1.0","1.10.0","1.11.0","1.2.0","1.3.0","1.4.0","1.5.0","1.6.0","1.7.0","1.8.0","1.9.0","1.9.1"],"database_specific":{"last_known_affected_version_range":"\u003c= 1.11.0","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/03/GHSA-3rcm-vjrc-p45j/GHSA-3rcm-vjrc-p45j.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N"}]}