Home/ Blog/ Security news/ Article
Blog · Security news

A crafted link can stall millions of Node apps, and the patch will not reach most of them

decode-uri-component, the npm decoder behind query-string and millions of apps, has a denial-of-service bug (CVE-2026-45822). Why npm update won't install the

A tiny cog jammed between the teeth of large interlocking gears

One crafted web address can take a busy Node.js server offline for tens of seconds at a time, and the cause is a package most teams have never heard of and never install on purpose. decode-uri-component is a small helper that turns percent-encoded text back into readable characters. It rides into millions of applications as a dependency of query-string, one of the most widely used URL parsers on npm, and it draws more than 20 million downloads a week on its own.

On June 30, 2026, the patch vendor Seal Security assigned CVE-2026-45822 to a denial-of-service flaw in every release up to and including 0.4.1. It is rated 6.6 (medium) and filed under uncontrolled resource consumption and inefficient algorithmic complexity. There is no confidentiality or integrity impact, and no public exploit has been reported. What it costs you is availability, and on a single-threaded runtime like Node.js, that is enough to matter.

What actually breaks

The decoder splits its input apart on every percent sign and then re-decodes each piece. The catch is that the work grows far faster than the input does. Hand it a string packed with percent-encoded fragments and the parse time climbs super-linearly, so a request that should finish in microseconds instead spins the processor for seconds. Because Node.js runs your request handlers on a single event loop, that spin freezes every other request in flight. One attacker, one oversized query string, and the whole process stops answering.

Crafted inputApprox. parse time
200 fragments~0.7 seconds
700 fragments~6 seconds
1,400 fragments~33 seconds
Parse time grows super-linearly with input size. Source: CVE-2026-45822 (Seal Security).

The measurements above come from the advisory itself: 200 fragments already cost about 0.7 seconds, 700 push past six, and 1,400 reach roughly 33. A modest amount of crafted input, repeated across a handful of connections, keeps a worker pinned with very little effort on the attacker's side.

We have been here before

This is the second denial-of-service CVE in the same small package. In 2022, CVE-2022-38900 flagged the same class of slowdown, and the maintainer shipped 0.2.1 to address it. That release narrowed the problem without closing it. The new finding shows the decoder still degrades badly on hostile input, which is why the real remedy this time was not another tweak to the old logic but a full rewrite. Version 0.5.0, published to npm on June 29, 2026, replaces the recursive splitting with a single-pass scanner that reads the string once, in linear time.

How to actually get the fixed version

Here is the part that catches teams out. Patching is not as simple as npm update, because almost nobody depends on this package directly. query-string at version 9.4.1 declares its dependency as "decode-uri-component": "^0.4.1". For a release below 1.0.0, that caret range means the 0.4.x line only, anything up to but not including 0.5.0. The fixed release sits one step outside the window your dependency tree is allowed to choose, so a routine update quietly leaves you on the vulnerable 0.4.1.

To pull the patched version today, force it with a dependency override instead of waiting for the upstream range to widen. In npm or pnpm, add an overrides entry; in Yarn, a resolutions entry, each pinning decode-uri-component to 0.5.0. Reinstall, then confirm the resolved version in your lockfile rather than trusting the command to have done it. If you maintain a package that depends on query-string, watch for a release that loosens its range so the fix can flow downstream on its own.

If you cannot patch immediately

The exposure is real only where attacker-controlled text reaches the decoder, which in practice means query strings and URL fragments parsed on the server. Cap the size of incoming query strings at the edge: a reverse proxy or web application firewall rule that rejects absurdly long URLs removes the cheap version of this attack. Watch for request handlers that suddenly run for whole seconds, and for event-loop lag climbing under load. Those are the signs that someone is feeding your parser oversized input on purpose.

None of this is dramatic on its own. It is a medium-severity bug in an unglamorous utility. But it is a clean example of how supply-chain risk actually lands: not through the package you picked, but through the one it quietly picked for you, governed by a version range you never set.

Topics

Frequently asked questions

Is CVE-2026-45822 being exploited in the wild?

No public exploit or in-the-wild exploitation has been reported, and it is not on CISA's known-exploited list. The CVE is rated medium (6.6) and affects availability only. Treat it as a patch-soon hardening item, not an emergency, but do not ignore the transitive-dependency twist.

Which versions of decode-uri-component are affected and fixed?

Versions 0.1.0 through 0.4.1 are vulnerable to the denial-of-service flaw. Version 0.5.0, published to npm on June 29, 2026, fixes it by rewriting the decoder as a single-pass linear-time scanner. There is no safe configuration on 0.4.1; upgrading is the fix.

Why won't npm update install the 0.5.0 fix?

Most apps get the package transitively through query-string, which pins it as ^0.4.1. For versions below 1.0.0, that caret range means 0.4.x only and excludes 0.5.0. So npm resolves to the vulnerable 0.4.1, and a routine update cannot move past the range query-string set.

How do I force the patched version into my project?

Add a dependency override pinning decode-uri-component to 0.5.0: an overrides entry in npm or pnpm, or a resolutions entry in Yarn. Reinstall, then confirm the resolved version in your lockfile. This bypasses query-string's range until an upstream release widens it.

How serious is a denial-of-service bug in a decoder?

On Node.js it matters more than the medium rating suggests, because requests share one event loop. A single crafted input that pins the CPU for seconds blocks every other request on that worker. It will not leak data, but it can take a service offline with little attacker effort.

Ready to meet the Guardians?

Deploys fast - agentless for monitoring and cloud, a lightweight agent for deep endpoint security. Just Suriq, standing watch.