Public mode

No access to your tenant or devices. Every item links to its source. What this means

Some sources, documents or advisories need attention: 275/275 feeds/APIs · 469/469 docs · 8/9 advisories · checked 05:48 UTC Customize Public modeDiscuss ChangeIntel on Discord

decode-uri-component vulnerable to denial of service via quadratic replacement of percent-encoded runs

Exact source revision recorded 29 Oct 2026 18:12:46 UTC. It does not establish the source's current position. Latest evidence.

osv · GHSA-qr28-fpjm-wq7f

Published

### Summary `decodeUriComponent()` takes quadratic time on malformed input that has many distinct percent-encoded runs. A single unauthenticated request of about 224 KB can block the Node.js event loop for about 20 seconds. Version 0.5.0, the release that fixed CVE-2026-45822, is affected. ### Details When native decodeURIComponent throws, `decodeUriComponent()` falls back to `customDecodeURIComponent` (`index.js:122`). That function: 1. Scans the input for every run of percent-encoded bytes (e.g. `%C3%A5`) and stores each distinct run, with its decoded value, in a lookup table (`index.js:130-144`). 2. Runs one full-string `input.replace(new RegExp(key, 'g'), …)` per table entry (`index.js:154`). With K distinct runs in an input of length L, that's K regex compilations and K full scans of the string, so O(K·L). An attacker controls both K and L, and K grows with L. One malformed sequence such as a trailing `%zz` is enough to force the fallback path. The 0.5.0 fix for CVE-2026-45822 (`fa479da`) replaced the recursive `decode()` routine with a linear scanner, but left this replacement loop unchanged. ### Proof of concept Running the following code takes ~20 seconds. ```js import decodeUriComponent from 'decode-uri-component'; let payload = ''; for (let i = 0; i < 32000; i++) { const high = Math.floor(i / 256).toString(16).padStart(2, '0'); const low = (i % 256).toString(16).padStart(2, '0'); payload += `%${high}%${low}x`; // distinct run each iteration } payload += '%zz'; // forces the fallback decoder console.time('decode'); decodeUriComponent(payload); // ~224 KB console.timeEnd('decode'); ``` ### Impact This is an availability issue only and there's no confidentiality or integrity impact. Any application that passes untrusted input to `decodeUriComponent()`, directly or through a dependency such as `query-string`, can be made unresponsive. Because Node.js runs on one thread, one request stalls every other client. The worst case needs input well beyond URL length limits. Node's default 16 KB header limit keeps payloads passed in via a URL query string to roughly 40 ms per request. Applications that decode request bodies are fully exposed, for example form bodies parsed with `query-string.parse()`.

Source published
29 Oct 2026 16:41:28 UTC
Source modified
29 Oct 2026 17:00:04 UTC
Observed here
29 Oct 2026 18:12:46 UTC
Source terms
GitHub Advisory Database · CC-BY-4.0

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · GitHub Advisory Database · CC-BY-4.0. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS_V4 · 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

Publisher rating · HIGH

ChangeIntel

An IT change radar: releases, security, known issues, retirements, documentation changes, and service status from public sources. Every item links to supporting evidence; dates and statuses can change after they are read.

Sources read 7 Nov 05:48 UTC · 275 of 275 readable · 274 fully read · documentation 469/469 current