---
id: CVE-2026-101895
aliases:
  - GHSA-f67j-2jqw-jpq7
title: 'Angular SSR: Denial of Service (DoS) via Infinite Loop on Malformed DOCTYPE'
summary: 'Angular SSR: Denial of Service (DoS) via Infinite Loop on Malformed DOCTYPE'
severity: high
cwe:
  - CWE-400
  - CWE-835
vendor: angular
product: '@angular/platform-server'
ecosystem: npm
affected:
  - '@angular/platform-server >= 22.0.0, < 22.1.6'
  - '@angular/platform-server >= 21.0.0, < 21.2.23'
  - '@angular/platform-server >= 20.0.0, < 20.3.31'
  - '@angular/platform-server <= 19.2.25'
patched:
  - '@angular/platform-server 22.1.6'
  - '@angular/platform-server 21.2.23'
  - '@angular/platform-server 20.3.31'
published: '2026-09-28'
updated: '2026-09-28'
sourceUpdated: '2026-09-28T21:31:22Z'
source: GHSA
sourceUrl: 'https://github.com/advisories/GHSA-f67j-2jqw-jpq7'
references:
  - url: 'https://github.com/angular/angular/security/advisories/GHSA-f67j-2jqw-jpq7'
  - url: 'https://github.com/advisories/GHSA-f67j-2jqw-jpq7'
tags:
  - ghsa
  - npm
ingestedAt: '2026-09-28T22:22:13.612Z'
---

## Overview

A Denial of Service (DoS) vulnerability exists in `@angular/platform-server`'s DOM emulation parser (`domino`). When processing untrusted user input containing an incomplete DOCTYPE declaration ending with whitespace before EOF (such as `<!DOCTYPE html `), the HTML parser enters an infinite synchronous loop, pegging CPU utilization at 100% and completely freezing the Node.js server process.

### Technical Description
In Angular Server-Side Rendering (SSR), `@angular/platform-server` uses `domino` to parse and sanitize HTML bound through template bindings (such as `[innerHTML]`) or manipulated via DOM APIs.

In Domino's HTML parser (`lib/HTMLParser.js`), tokenizer states that specify fixed lookahead—such as `after_doctype_name_state` (`lookahead = 6`)—rely on the state handler function to explicitly advance the character index pointer (`nextchar`). While branches for whitespace, `>`, and keyword matching advance `nextchar`, the EOF branch (`case -1: // EOF`) emitted doctype and EOF tokens without advancing `nextchar` or transitioning out of the state:

```javascript
case -1: // EOF
  forcequirks();
  emitDoctype();
  emitEOF();
  break;
```

Because `nextchar` remained unchanged pointing to the EOF marker character (`\uFFFF`), the scanner loop (`while (nextchar < numchars)`) repeatedly re-invoked `after_doctype_name_state` with `codepoint = EOF` indefinitely. In Node.js's single-threaded runtime, this synchronous loop starves the event loop entirely.

### Impact & Reachability
* **Reachability**: The vulnerability is reachable in any Angular SSR application where untrusted user input is bound to `[innerHTML]`, interpolated into markup, or sanitized on the server.
* **Impact**: Successful exploitation allows an unauthenticated remote attacker to cause an immediate Denial of Service (DoS) by sending a payload containing an incomplete DOCTYPE (e.g., `<!DOCTYPE html `). The Node.js SSR process locks up at 100% CPU and ceases responding to all concurrent and subsequent HTTP requests.

**Proof of Concept:**
```ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `<div [innerHTML]="payload"></div>`,
})
export class AppComponent {
  // Attacker-controlled input containing an incomplete DOCTYPE ending with whitespace
  payload = '<!DOCTYPE html ';
}
```

### Workarounds
* Avoid binding untrusted user input directly to `[innerHTML]` in server-rendered templates; use standard text interpolation (`{{ userInput }}`) or `[textContent]` when raw HTML rendering is not required.
* Validate or sanitize user input before passing it to `[innerHTML]` on the server by stripping or rejecting strings matching `/^<!DOCTYPE/i`.

## Affected packages

- `@angular/platform-server >= 22.0.0, < 22.1.6`
- `@angular/platform-server >= 21.0.0, < 21.2.23`
- `@angular/platform-server >= 20.0.0, < 20.3.31`
- `@angular/platform-server <= 19.2.25`

## Remediation

Upgrade to a patched release:

- `@angular/platform-server 22.1.6`
- `@angular/platform-server 21.2.23`
- `@angular/platform-server 20.3.31`
