Dev.to Security πŸ” Cybersecurity πŸ‘ 0 πŸ“– 4 min read

CVE-2026-118664: CVE-2026-118664: Quadratic Complexity Denial of Service in decode-uri-component

CVE-2026-118664: Quadratic Complexity Denial of Service in decode-uri-component Vulnerability ID: CVE-2026-118664 CVSS Score: 8.2 Published: 2026-10-29 An inefficient algorithmic complexity vulnerability exists in t

CVE-2026-118664: Quadratic Complexity Denial of Service in decode-uri-component

Vulnerability ID: CVE-2026-118664
CVSS Score: 8.2
Published: 2026-10-29

An inefficient algorithmic complexity vulnerability exists in the npm package decode-uri-component prior to version 0.5.1. When processing malformed URI strings containing invalid percent-escape sequences, the library falls back to a custom decoder that collects distinct percent-encoded runs into a dictionary and executes a full-string regular expression replacement for each entry. Supplying a payload with thousands of distinct percent-encoded sequences alongside a malformed escape triggers quadratic O(K * L) execution time, starving the single-threaded Node.js event loop and resulting in an unauthenticated Denial of Service.

TL;DR

Versions of decode-uri-component prior to 0.5.1 are vulnerable to an algorithmic complexity Denial of Service (CVE-2026-118664). By sending an unauthenticated payload of approximately 224 KB containing thousands of unique percent-encoded sequences and one malformed escape token, an attacker can force the fallback decoder into quadratic processing time, blocking the Node.js event loop for over 20 seconds per request.

⚠️ Exploit Status: POC

Technical Details

  • Vulnerability Type: Inefficient Algorithmic Complexity / Denial of Service
  • CWE ID: CWE-407 / CWE-400
  • CVSS v4.0 Score: 8.2 HIGH (CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N)
  • EPSS Score: 0.32% (24.75th percentile)
  • Attack Vector: Network (Unauthenticated HTTP Request)
  • Affected Component: decode-uri-component (< 0.5.1)
  • Patched Version: 0.5.1
  • CISA KEV Status: Not Listed

Affected Systems

  • decode-uri-component (npm package)
  • decode-uri-component: < 0.5.1 (Fixed in: 0.5.1)

Code Analysis

Commit: fad01d6

Replace multi-pass replaceMap regex loop with single-pass replacement in customDecodeURIComponent

diff --git a/index.js b/index.js
--- a/index.js
+++ b/index.js
@@ -79,6 +79,15 @@ function decode(input) {

            // Continuation byte or invalid lead byte β€” emit one `%XX` literally.
            if (sequenceLength === 0) {
+               const pair = input.slice(position, position + 6);
+
+               // UTF-16 BOM byte pairs become two replacement characters.
+               if (pair === '%FE%FF' || pair === '%FF%FE') {
+                   output += '\uFFFD\uFFFD';
+                   position += 6;
+                   continue;
+               }
+
                output += input.slice(position, position + 3);
                position += 3;
                continue;
@@ -111,7 +120,10 @@ function decode(input) {
            }

            // Missing continuation bytes or decode failure β€” emit the first byte literally.
-           output += input.slice(position, position + 3);
+           const literal = input.slice(position, position + 3);
+
+           // A truncated `%C2` becomes a replacement character.
+           output += literal === '%C2' ? '\uFFFD' : literal;
            position += 3;
        }

@@ -120,41 +132,8 @@ function decode(input) {
 }

 function customDecodeURIComponent(input) {
-   // Keep track of all the replacements and prefill the map with the `BOM`
-   const replaceMap = {
-       '%FE%FF': '\uFFFD\uFFFD',
-       '%FF%FE': '\uFFFD\uFFFD',
-   };
-
-   // Find percent-encoded runs separated by literal text or lone `%` characters.
-   let match = multiMatcher.exec(input);
-
-   while (match) {
-       try {
-           // Decode as big chunks as possible
-           replaceMap[match[0]] = decodeURIComponent(match[0]);
-       } catch {
-           const result = decode(match[0]);
-
-           if (result !== match[0]) {
-               replaceMap[match[0]] = result;
-           }
-       }
-
-       match = multiMatcher.exec(input);
-   }
-
-   // Add `%C2` at the end of the map to make sure it does not replace the combinator before everything else
-   replaceMap['%C2'] = '\uFFFD';
-
-   const entries = Object.keys(replaceMap);
-
-   for (const key of entries) {
-       // Replace all decoded components
-       input = input.replace(new RegExp(key, 'g'), replaceMap[key]);
-   }
-
-   return input;
+   // Decode each percent-encoded run in place in a single pass. Decoded output is never rescanned.
+   return input.replace(multiMatcher, run => decode(run));
 }

 export default function decodeUriComponent(encodedURI) {

Exploit Details

  • GitHub: Unit test in test.js demonstrating a 32,000-run (~224 KB) payload that triggers quadratic execution time on versions prior to 0.5.1.

Mitigation Strategies

  • Upgrade decode-uri-component to version 0.5.1 or later across all direct and transitive dependency trees.
  • Enforce strict size limits on HTTP query strings, headers, and URL-encoded request bodies at the reverse proxy and application middleware layers.
  • Use native decodeURIComponent() and reject malformed URI inputs with HTTP 400 responses if graceful fallback decoding of invalid escape sequences is not required.
  • Configure Web Application Firewalls (WAF) to detect and block payloads containing thousands of percent-encoded sequences combined with invalid hexadecimal escapes.

Remediation Steps:

  1. Run npm ls decode-uri-component or yarn why decode-uri-component to identify all direct and transitive instances of the package in your project.
  2. Update direct dependencies by executing npm install decode-uri-component@^0.5.1.
  3. If vulnerable versions are pulled transitively via older packages, add an overrides or resolutions entry in package.json forcing "decode-uri-component": "^0.5.1" and regenerate your lockfile.
  4. Verify the remediation by inspecting package-lock.json or yarn.lock to ensure no version prior to 0.5.1 remains installed.

References

Read the full report for CVE-2026-118664 on our website for more details including interactive diagrams and full exploit analysis.

πŸ“° Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.