From 08c5442ed1e7df1cb2424951f08fa8030d40e053 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Sun, 18 Oct 2026 09:46:01 +0200 Subject: [PATCH] docs: describe the DoS-hardening work from engine rounds 166-173 The Security section only covered the raster-image megapixel cap and the dial-time SSRF guard. It said nothing about the DOM-depth stack-overflow caps or the cloneNode/innerHTML memory-exhaustion caps shipped since, so a reader checking what the engine guards against got an incomplete picture. Co-Authored-By: Claude Sonnet 5 --- docs/index.md | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index 42477f6..94fb260 100644 --- a/docs/index.md +++ b/docs/index.md @@ -82,8 +82,30 @@ destinations itself, so rendering an untrusted page from a machine with access t private networks can reach internal addresses. Embedding the engine directly means adding a dial-time guard through `Engine.Client` that refuses loopback, private and link-local addresses; the [browserproxy](https://github.com/go-webengine/browserproxy) -service ships one. Decoding is bounded: raster images declaring more than 25 -megapixels are refused, and every fetch is size-capped. +service ships one. + +Since a renderer's whole job is turning arbitrary, untrusted page content into +output, several unrelated kinds of pathological input have been found and +capped, each confirmed live against a synthetic reproduction: + +- **Decoding**: raster images declaring more than 25 megapixels are refused + before decode; every fetch is size-capped. +- **Tree-depth recursion**: a script-built DOM tree past 512 levels used to + crash the whole process with an unrecoverable stack overflow in the CSS + cascade, layout, `cloneNode`/`isEqualNode`, and three CSS parsers (`calc()`, + `:not()`/`:has()`/`:host()`, `:is()`/`:where()`/`:matches()`). All are now + capped at 512 or a generous output budget. +- **Memory exhaustion**: a single `innerHTML` assignment, or a `cloneNode` + call repeated in a loop, could previously allocate tens of gigabytes of + real memory from a few lines of ordinary-looking script. `cloneNode` and + the HTML→DOM conversion shared by `Parse`/`ParseFragment`/`innerHTML` now + cap total node count per call; the rendered canvas is capped by pixel + count. + +See the [engine's `FIDELITY.md`](https://github.com/go-webengine/engine/blob/main/FIDELITY.md) +for the full measured writeups. None of this changes how a well-formed page +renders — only how a pathological one degrades (truncated output, never a +crash or unbounded allocation). ## Where to next