Visitar URL original
Deeply nested HTML stalls Angular SSR worker during sanitization · Issue #71195 · angular/angular · GitHub
Skip to content

Deeply nested HTML stalls Angular SSR worker during sanitization #71195

Description

@BlueIridium

Which @angular/* package(s) are the source of the bug?

core, platform-server

Is this a regression?

No known unaffected version; I did not identify an introduction commit.

Description

An Angular SSR application that displays user-submitted rich text through a normal [innerHTML] binding can spend several seconds synchronously parsing a small, deeply nested HTML article. The server-side sanitizer creates a Domino template, assigns the untrusted HTML to template.innerHTML, and reads it back during its stability check. With 8,000 well-nested <div> levels, the pinned Domino parser overflows the stack in recursivelySetOwner().

The reproduction accepts an unauthenticated Markdown submission (184 KB, below its 1 MiB limit). Marked 18.0.11 preserves the raw HTML, and an ordinary AngularNodeAppEngine request renders the stored article. It does not use bypassSecurityTrustHtml, a private parser API, modified Angular packages, or direct server state changes. optimization.styles.inlineCritical is set to false to isolate this sanitizer path from critical-CSS processing.

Expected: sanitization either renders or rejects an over-deep article without a long synchronous worker stall.

Actual: the article GET returns HTTP 200 with an empty article after a stack error; another request arriving at the same single-worker server during parsing waits behind it. The stored article triggers the same error on later GETs. The Node process stays alive.

In a fresh Linux arm64 container with Node 24.21.0 and released Angular 22.2.0 packages:

Input (fresh worker each) Article GET Unrelated GET started 2 s later Outcome
184 KB shallow, same byte count 644 ms 14 ms Article rendered; no stack error
184 KB, 8,000 levels plus inner children, run 1 10,025 ms 8,017 ms Empty article; RangeError
Same nested input, run 2 10,097 ms 8,091 ms Empty article; RangeError

This demonstrates a repeatable single-worker availability problem and article render failure. It does not establish a process crash or multiworker service outage. The application must accept raw HTML in lower-trust content and render it on SSR; applications that strip raw HTML, limit depth, or do not SSR that content are outside this path.

Please provide a link to a minimal reproduction of the bug

https://github.com/BlueIridium-Security/angular-ssr-nested-html-worker-stall-repro

The repository has a pinned package lock and a one-command Docker validator:

docker build -t angular-ssr-nested-html-repro .
docker run --rm angular-ssr-nested-html-repro

The validator starts a new server for each case, sends the article through HTTP, measures a concurrent unrelated request, checks the empty-vs-rendered article, and requires the Domino stack error in both nested runs.

Please provide the exception or error you saw

RangeError: Maximum call stack size exceeded

The generated server log maps this stack to Domino's recursive owner assignment. The request is caught by the SSR renderer, which returns a 200 page with an empty article.

Please provide the environment you discovered this bug in

Angular core / platform-server / SSR: 22.2.0
Angular CLI / build: 22.2.0
Marked: 18.0.11
Node: 24.21.0
npm: 11.19.0
OS: Linux arm64 (node:24.21.0-bookworm-slim container)

Anything else?

The relevant source path is _sanitizeHtml() reading inert innerHTML, InertDocumentHelper assigning the template, and Domino's recursive recursivelySetOwner(). The framework source path remains present on the current official main commit 7d96a37af4f7b7dd9dc9a2b9b90cc043c7da2a31; the reproduction uses released packages so it can be installed independently.

This is separate from #70926, whose mis-nested formatting input grows through active-formatting reconstruction and produces a heap OOM. This input uses only well-nested div elements and overflows Domino's owner-assignment recursion. Critical-CSS inlining is disabled, so the critical-CSS scanner is not involved.

Activity

  1. added
    area: serverIssues related to server-side rendering
    gemini-triagedLabel noting that an issue has been triaged by gemini
    on Oct 5, 2026
  2. added this to the needsTriage milestone on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: serverIssues related to server-side renderinggemini-triagedLabel noting that an issue has been triaged by gemini

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions