Safeguard
Vulnerability Analysis

CVE-2022-24999: Prototype pollution / DoS in qs querystri...

CVE-2022-24999 exposes a prototype pollution and denial-of-service flaw in the qs querystring library used across the Node.js ecosystem.

Aman Khan
AppSec Engineer
7 min read

CVE-2022-24999 is a prototype pollution and denial-of-service (DoS) vulnerability in qs, the querystring parsing library that underpins Express.js and a large share of the Node.js ecosystem. The flaw allows an attacker to send a specially crafted query string that bypasses qs's existing prototype-pollution protections, driving the Node.js process into excessive object allocation and CPU consumption. In practice, this means a single malicious HTTP request can hang or crash a vulnerable server — no authentication, user interaction, or complex setup required.

qs is not a niche dependency. It ships as a transitive dependency of body-parser and express, which together sit underneath an enormous fraction of production Node.js applications. A vulnerability this deep in the dependency graph doesn't just affect the handful of teams who import qs directly — it silently affects everyone downstream who parses query strings or URL-encoded bodies through Express, whether or not they know qs is even in their tree. That's the recurring lesson of npm-ecosystem CVEs: risk lives in the transitive graph, not just the top-level package.json.

What actually goes wrong

qs had already hardened its parser against classic prototype pollution — the technique where an attacker submits a key like __proto__ or constructor.prototype in a query string and gets it merged onto Object.prototype, corrupting the object model for every request that touches that prototype afterward. CVE-2022-24999 (tracked upstream as GHSA-hrpp-h998-j3pp) is notable because it is a bypass of that existing mitigation combined with a resource-exhaustion angle: rather than (or in addition to) achieving clean pollution, an attacker can craft input that forces qs's parser into pathological behavior, causing the Node process to allocate far more objects/memory than the size of the input would suggest and effectively hang.

This is the pattern that makes prototype-pollution bugs in parsing libraries dangerous even when full remote code execution isn't achievable: the availability impact alone is enough to take a service down, and because the trigger is a single crafted request, it's cheap for an attacker and expensive for the defender to detect after the fact.

Affected versions and components

  • Component: qs npm package (query string parser)
  • Vulnerability class: CWE-1321 (Prototype Pollution) combined with CWE-400 (Uncontrolled Resource Consumption / DoS)
  • Fixed versions: The qs maintainers patched the issue across every actively maintained release line, shipping fixes in 6.10.3, 6.9.7, 6.8.3, 6.7.3, 6.6.1, 6.5.3, 6.4.1, 6.3.3, and 6.2.4. Anything older than the fixed release on its respective branch is considered vulnerable.
  • Indirect exposure: Applications using express or body-parser inherit whichever qs version those packages pin or resolve to. Because of how npm's dependency resolution and lockfiles work, two projects using the "same" version of Express can end up with different, differently-patched qs versions depending on when their lockfile was generated.

If you don't import qs directly, don't assume you're clear — run npm ls qs (or the yarn/pnpm equivalent) to see every resolved copy in your tree, since it's common to find multiple versions nested under different dependencies.

Severity context

NVD scores CVE-2022-24999 as a high-severity issue, consistent with its pure denial-of-service impact profile: no confidentiality or integrity loss, but a significant availability impact achievable remotely, without privileges, and without user interaction. That combination — trivial to trigger, no auth required, service-ending outcome — is exactly why DoS-only findings in widely-used parsing libraries routinely get scored as high rather than "just" medium.

This CVE has not been added to CISA's Known Exploited Vulnerabilities (KEV) catalog, and there is no confirmed record of widespread active exploitation. EPSS-style exploitation-probability scoring for this class of dependency DoS bug is typically low, which tracks with the absence of KEV listing — but low observed exploitation is not the same as low risk. Prototype pollution bugs in foundational parsing libraries have a long history of being rediscovered and chained with other flaws months or years after initial disclosure, and unpatched instances remain exploitable indefinitely regardless of how much attention they're currently getting.

Timeline

  • qs's history of prototype-pollution hardening goes back several years, with earlier CVEs (e.g., in the 6.2.x–6.5.x era) addressing the original __proto__ merge issue.
  • CVE-2022-24999 was reported to the qs maintainers as a bypass of that earlier protection, showing that the parser could still be driven into pathological, resource-exhausting behavior under crafted input.
  • The maintainers responded by back-porting fixes across all supported release lines simultaneously (6.2.4 through 6.10.3), rather than patching only the latest branch — a sign of how seriously the maintainers treat a prototype-pollution regression in a library this widely depended upon.
  • The GitHub Security Advisory (GHSA-hrpp-h998-j3pp) and the corresponding NVD entry were published to formally track the issue and give the ecosystem a canonical identifier to scan for.

Remediation steps

  1. Identify every resolved copy of qs in your dependency tree, not just the top-level entry. Use npm ls qs, yarn why qs, or your SBOM/SCA tool to enumerate all nested versions, including those pulled in transitively via express, body-parser, or other middleware.
  2. Upgrade to a patched release on your branch line — 6.10.3, 6.9.7, 6.8.3, 6.7.3, 6.6.1, 6.5.3, 6.4.1, 6.3.3, or 6.2.4, whichever is closest to what you're already running, to minimize the blast radius of the upgrade.
  3. Upgrade Express/body-parser as needed if your lockfile resolves an outdated qs through those packages rather than a direct dependency; bumping the parent package (or forcing a resolution/override in your package manager) may be required to pull in the fix.
  4. Regenerate and commit your lockfile after upgrading so the fixed version is pinned for every future install, and re-run your dependency audit (npm audit, yarn audit, or your SCA scanner) to confirm the advisory clears.
  5. Add input-size and rate limits at the edge (reverse proxy, API gateway, or WAF) as defense-in-depth against resource-exhaustion attacks in general — this won't fix the underlying bug, but it reduces the impact of any similar parser-level DoS, patched or not-yet-discovered.
  6. Monitor for anomalous memory/CPU spikes correlated with request payloads so that a similar bypass, if it recurs in the future, shows up in your observability stack before it becomes an outage.

How Safeguard Helps

Vulnerabilities like CVE-2022-24999 are exactly the class of risk that gets missed when security review stops at the top level of package.json. The vulnerable code was several dependency hops away from most application manifests, resolved differently depending on lockfile age, and easy to overlook in a manual review. Safeguard's software supply chain security platform is built to close that gap:

  • Continuous SBOM and dependency graph visibility surfaces every resolved version of every transitive dependency — including nested, duplicate copies of packages like qs — so you know your true exposure instead of guessing from the top-level manifest.
  • Automated CVE and advisory correlation maps newly disclosed vulnerabilities like CVE-2022-24999 directly against your live dependency graph, flagging affected services within minutes of disclosure rather than waiting for the next scheduled scan.
  • Risk-prioritized remediation guidance distinguishes reachable, exploitable exposure from theoretical inclusion, so teams can fix the qs instances that actually sit in a request-parsing path first, rather than triaging every match with equal urgency.
  • Policy-driven build gating can block merges or deployments that introduce known-vulnerable versions of high-blast-radius packages like qs, express, and body-parser, preventing regressions from re-introducing a previously patched CVE.
  • Audit-ready evidence for SOC 2 and similar compliance programs, showing when a vulnerability was detected, when it was remediated, and which services were in scope — turning dependency hygiene into a demonstrable control rather than a one-off cleanup effort.

Prototype pollution and DoS bugs in ubiquitous parsing libraries will keep surfacing because the attack surface — untrusted input hitting a general-purpose parser — is inherent to how the web works. The defensible position isn't eliminating that risk entirely; it's knowing, continuously and automatically, exactly where every vulnerable version lives in your stack and closing the gap before it's exploited.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.