CSIRTS // UNIFIED SECURITY ADVISORY FEEDSYS ● ONLINE · POWERED BY INTELFUSIONS.COM

CVE-2026-9769

highCVSS 7.5covered by 2 sourcesfirst seen 2026-03-17
Summary justhtml through 1.9.1 allows denial of service via deeply nested HTML. During parsing, JustHTML.init() always reaches TreeBuilder.finish(), which unconditionally calls _populate_selectedcontent(). That function recursively traverses the DOM via _find_elements() / _find_element() without a depth bound, allowing attacker-controlled deeply nested input to trigger an unhandled RecursionError on CPython. Depending on the host application's exception handling, this can abort parsing, fail requests, or terminate a worker/process. Details TreeBuilder.finish() (treebuilder.py#L476) unconditionally calls _populate_selectedcontent(self.document) at line 494. _populate_selectedcontent() (treebuilder.py#L1243) calls _find_elements() (treebuilder.py#L1280) to recursively search the DOM tree for <select> elements: def _find_elements(self, node: Any, name: str, result: list[Any]) -> None: """Recursively find all elements with given name.""" if node.name == name: result.append(node) if node.has_child_nodes(): for child in node.children: self._find_elements(child, name, result) # recursive call When the DOM tree depth exceeds CPython's default recursion limit (1000), this raises an unhandled RecursionError. The full call path is: JustHTML(html) → tokenizer.run() → tree_builder.finish() → _populate_selectedcontent(document) → _find_elements(root, "select", selects) (recursive) Deeply nested DOM trees can be produced by nesting <div> tags ~1000 levels deep. On CPython with the default recursion limit, approximately 11 KB of <div> nesting is sufficient to trigger the error. The exact depth threshold is environment-dependent (CPython version, recursion limit setting, call stack depth at invocation). Additional recursive functions are affected on already-parsed deep trees: - Node.clone_node(deep=True) (node.py#L523) — called during sanitization - _node_to_html() (serialize.py#L580) — used by to_html(pretty=True) - _to_markdown_walk() (node.py#L817) — used by to_markdown()

⚡ Watch CVE-2026-9769

Get an email if CVE-2026-9769 is added to CISA KEV, gains public exploit code, or a new advisory cites it — max one per day, one-click unsubscribe.

Exploitation outlook

Advisory coverage (2)

External references

NVD record for CVE-2026-9769

CVE.org record

Embed the live status

CVE-2026-9769 live status badge — this badge updates automatically when the KEV or exploit status changes. How to embed it →

[![CVE-2026-9769 status](https://www.csirts.com/badge/CVE-2026-9769)](https://www.csirts.com/cve/CVE-2026-9769)