From a21e5a5a8f700af7516bf13f866d0f60c8fdf1fe Mon Sep 17 00:00:00 2001 From: tannevaled Date: Fri, 9 Oct 2026 14:49:10 +0200 Subject: [PATCH] security: cap DOM-walk recursion depth to stop a script-built tree from crashing the process golang.org/x/net/html already refuses to parse markup nested past 512 levels, but that guard lives in the parser alone: a page's own script can still build an arbitrarily deep tree at runtime (createElement + appendChild in a loop), since dom.AppendChild has no depth check of its own. Four unbounded recursive DOM walks (css.StylesheetLinks, styleElementText, css.Cascade's element walk, and layout's place/ contents) then hit an unrecoverable "fatal error: stack overflow" (not a panic -- recover() cannot catch it) between roughly 150,000 and 200,000 levels, killing the whole embedding process rather than just the one render. Each walk now caps its recursion at 512 (matching the parser's own bound) and stops descending past it instead of crashing. Co-Authored-By: Claude Sonnet 5 --- FIDELITY.md | 9 +++++++++ css/cascade.go | 45 +++++++++++++++++++++++++++++++++---------- css/cascade_test.go | 33 +++++++++++++++++++++++++++++++ css/external.go | 15 +++++++++++---- css/external_test.go | 35 +++++++++++++++++++++++++++++++++ css/vars.go | 15 +++++++++++++++ layout/layout.go | 29 ++++++++++++++++++++++++++++ layout/layout_test.go | 40 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 207 insertions(+), 14 deletions(-) diff --git a/FIDELITY.md b/FIDELITY.md index 1d20521..f42f7a6 100644 --- a/FIDELITY.md +++ b/FIDELITY.md @@ -18,6 +18,15 @@ The committed PNGs under `testdata/renders/` back every claim here. Reproduce them with the commands at the bottom. The measured-vs-Chrome numbers live in [`bench/REPORT.md`](bench/REPORT.md). +## 2026-10-07 (round 166) — a script-built DOM tree far deeper than any real page crashed every whole-document tree walk with an unrecoverable stack overflow, not a panic (security audit, patch) + +Continuing this session's "audit de sécurité" pass after the rotate-crash fix below: checked for ReDoS and stack-overflow risk from pathological input. Go's `regexp` package is RE2-based (confirmed: every custom pattern in this repo — `svg.go`, `css/supports.go`, `css/selector.go`, `css/container.go`, `css/parse.go` — compiles under `regexp.MustCompile`, never a backtracking engine), so ReDoS is structurally impossible here, same category of finding as round 161's XXE check. Stack-overflow risk was real. + +- **Finding**: `golang.org/x/net/html` already refuses to *parse* markup nested past 512 levels (`html: open stack of elements exceeds 512 nodes`), so a page's raw HTML can never build a pathologically deep tree. But that guard lives in the parser alone — `dom.AppendChild`/`InsertBefore` have no depth check of their own, by design (they are generic tree-mutation primitives, not a parser), so a page's own `