Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-45822

CVE-2026-45822: decode-uri-component DoS Vulnerability

CVE-2026-45822 is a denial of service vulnerability in decode-uri-component through version 0.4.1 that causes super-linear parsing time. This post covers the technical details, affected versions, and mitigation.

Published:

CVE-2026-45822 Overview

CVE-2026-45822 is a denial-of-service vulnerability in the decode-uri-component Node.js package through version 0.4.1. The decode() function splits input on the % character, producing N tokens that are passed to decodeComponents(). This parsing path exhibits super-linear time complexity relative to input size. Benchmarks show 200 %ab tokens take roughly 0.7 seconds, 700 tokens take approximately 6 seconds, and 1400 tokens take about 33 seconds. An unauthenticated attacker can submit crafted percent-encoded input to any endpoint that decodes URI components using this library, causing sustained CPU consumption and blocking the Node.js event loop. The weakness is tracked under [CWE-400] Uncontrolled Resource Consumption.

Critical Impact

Remote attackers can block the Node.js event loop and exhaust CPU by sending crafted URI-encoded input with many %XX tokens.

Affected Products

  • decode-uri-component npm package versions through 0.4.1
  • Node.js applications that call decodeUriComponent() on attacker-controlled input
  • Downstream libraries such as query-string and other parsers depending on decode-uri-component

Discovery Timeline

  • 2026-06-30 - CVE-2026-45822 published to NVD
  • 2026-06-30 - Last updated in NVD database

Technical Details for CVE-2026-45822

Vulnerability Analysis

The vulnerability resides in the decoder logic in index.js of the decode-uri-component package. The decoder combines two regular expressions, singleMatcher and multiMatcher, with a recursive fallback in decodeComponents(). When decodeURIComponent() throws on the concatenated input, the function splits the token array in half and recurses. Each recursion re-invokes decodeURIComponent() on progressively smaller slices, producing repeated work proportional to the number of %XX groups. The resulting runtime grows faster than linearly with input size, allowing small payloads to consume disproportionate CPU time.

Root Cause

The root cause is an algorithmic complexity flaw in the recursive decode-and-retry strategy. The library attempts to decode the full string first, then bisects on failure without deduplicating overlapping work. Combined with the multiMatcher regex evaluated over long percent-encoded runs, the parser reprocesses tokens across recursion depths.

Attack Vector

Exploitation requires no authentication and no user interaction. Any HTTP endpoint, query-string parser, or router that passes untrusted input through decode-uri-component is reachable over the network. An attacker submits a URL, header, or body containing thousands of %ab sequences to trigger event-loop stalls that degrade or halt service for all concurrent clients.

javascript
// Security patch: single-pass UTF-8 scanner replaces recursive decoder
// Matches one or more consecutive percent-encoded bytes (e.g. `%C3%A5`).
const token = '%[a-f0-9]{2}';
-const singleMatcher = new RegExp('(' + token + ')|([^%]+?)', 'gi');
-const multiMatcher = new RegExp('(' + token + ')+', 'gi');
+const multiMatcher = new RegExp(`(${token})+`, 'gi');

-function decodeComponents(components, split) {
-	try {
-		// Try to decode the entire string first
-		return [decodeURIComponent(components.join(''))];
-	} catch {
-		// Do nothing
-	}
-
-	if (components.length === 1) {
-		return components;
-	}
-
-	split = split || 1;
+const hexPair = /^[a-f\d]{2}$/i;
+
+// Read a `%XX` sequence at `position`, returning the byte value and where to continue scanning.
+function parsePercentByte(input, position) {
+	if (input.codePointAt(position) !== 37 || position + 3 > input.length) {
+		return;
+	}
+
+	const digits = input.slice(position + 1, position + 3);
+
+	if (!hexPair.test(digits)) {
+		return;
+	}
+
+	return {byte: Number.parseInt(digits, 16), next: position + 3};
}
// Source: https://github.com/SamVerschueren/decode-uri-component/commit/fa479dafeede7bedf04e5c89aa78f2a78c664005

The patch replaces the recursive splitter with a single-pass UTF-8 scanner. The new parsePercentByte() function reads each %XX sequence exactly once, eliminating the super-linear growth.

Detection Methods for CVE-2026-45822

Indicators of Compromise

  • HTTP requests containing hundreds or thousands of consecutive %XX sequences in URLs, headers, or bodies.
  • Node.js processes showing sustained 100% CPU usage on a single core with rising event-loop lag metrics.
  • Elevated request latency and timeouts across unrelated endpoints served by the same process.

Detection Strategies

  • Inspect application dependency trees with npm ls decode-uri-component to identify vulnerable versions at or below 0.4.1.
  • Deploy a WAF or reverse-proxy rule that rejects requests where the count of % characters exceeds a defined threshold, for example 200.
  • Instrument the Node.js runtime with an event-loop lag monitor and alert when lag exceeds normal baselines.

Monitoring Recommendations

  • Log request URI length, header size, and body size, then alert on outliers correlated with CPU spikes.
  • Track APM traces for decodeURIComponent call durations to surface anomalous parsing times.
  • Correlate reverse-proxy access logs with process CPU metrics to identify offending source addresses.

How to Mitigate CVE-2026-45822

Immediate Actions Required

  • Upgrade decode-uri-component to the patched release published after commit fa479da on the GitHub Commit History.
  • Audit transitive dependencies via npm audit and rebuild lockfiles to force the fixed version.
  • Add ingress-layer input size limits on any endpoint that decodes URI components from untrusted sources.

Patch Information

The maintainer rewrote the decoder as a single-pass UTF-8 scanner. The fix is available in the GitHub Code Repository and distributed through the NPM Package Information page. Update package.json to the patched version and regenerate package-lock.json.

Workarounds

  • Enforce a maximum request URI length at the reverse proxy, for example 8 KB, to bound parsing cost.
  • Reject inputs where percent-encoded token counts exceed application requirements before invoking the decoder.
  • Isolate URI decoding in a worker thread so a stalled parser does not block the main event loop.
bash
# Force the patched version and verify resolution
npm install decode-uri-component@latest
npm ls decode-uri-component
npm audit --production

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.