The patch for the front-door lock introduced a second keyhole that opens the same door
CVE-2026-75899 is a double percent-decoding flaw in fast-uri's normalize() and resolve() functions. The fix for CVE-2026-6322 (encoded authority-delimiter confusion) introduced a second decode pass. When an attacker supplies a double-encoded hostname like %256c%256f%2563%2561%256c%2568%256f%2573%2574 (which decodes to %6c%6f%63%61%6c%68%6f%73%74, then to localhost), fast-uri's normalization pipeline decodes it twice and emits the final hostname as localhost. Affected version ranges are 2.4.1–2.4.4, 3.1.2–3.1.5, and 4.0.0–4.1.2 — note these are exactly the versions that shipped the CVE-2026-6322 fix. Patched versions are 2.4.5, 3.1.6, and 4.1.3, published August 23, 2026.
The vendor rates this HIGH at CVSS 7.5. That score describes the theoretical maximum: unauthenticated, network-reachable, no user interaction, high integrity impact. In isolation those vector components are accurate. But the score assumes the consuming application uses fast-uri's normalize() or resolve() output for security-relevant URL allowlist/denylist enforcement *before* making outbound requests. The overwhelming majority of fast-uri's 115K+ npm dependents consume it through AJV and Fastify for JSON Schema $ref resolution — a context where double-decoded hostnames don't translate into SSRF. The vendor severity is therefore overstated for most deployments and noisgate downgrades it to MEDIUM.
4 steps from start to impact.
Identify a target application using fast-uri for URL policy enforcement
normalize() before checking the hostname against an allowlist or denylist. This is the critical precondition — without it, the double-decode has no security impact. The attacker can fingerprint by submitting double-encoded hostnames and observing redirect or fetch behavior.- Application uses fast-uri normalize() or resolve() for URL validation
- Application runs affected version (2.4.1–2.4.4, 3.1.2–3.1.5, or 4.0.0–4.1.2)
- Most fast-uri consumers use it via AJV/Fastify for schema $ref resolution, not URL policy enforcement
- No public enumeration of which apps use fast-uri for allowlist checks
Craft double-encoded hostname payload
localhost (cloud metadata endpoint), the attacker sends http://%2531%2536%2539%252e%2532%2535%2534%252e%2531%2536%2539%252e%2532%2535%2534/latest/meta-data/. After fast-uri's first decode the hostname still looks encoded; after the second decode it resolves to 169.254.169.254. The payload is trivial to construct — no tooling beyond a URL encoder is needed.- Attacker can supply arbitrary URL to the application's input
- Payload construction is trivial — no exploit code or tooling required
%25 sequences in the Host component can flag this pattern.Bypass allowlist / denylist check
%256c%256f%2563%2561%256c%2568%256f%2573%2574) and does not match it against blocked entries like localhost or 169.254.169.254. The double-decoded output from fast-uri is then used to construct the outbound HTTP request, which reaches the attacker-chosen host.- Application performs allowlist check BEFORE fast-uri normalization fully decodes the hostname
- Application uses the normalized output for the actual outbound request
- Applications that check the hostname AFTER normalization, or that use a different URL parser for the outbound request, are not affected
- Node.js built-in URL parser does not double-decode, so apps using new URL() for the fetch step may not be vulnerable
Achieve SSRF to internal resources
- Internal services or metadata endpoints are reachable from the application server
- Cloud providers increasingly require IMDSv2 (hop-limited, token-required), which blocks basic SSRF to metadata
- Network segmentation and egress filtering limit lateral reach
The supporting signals.
| In-the-Wild Exploitation | No known exploitation. Not listed on CISA KEV. No reports of active campaigns targeting this CVE as of 2026-08-24. |
|---|---|
| Proof of Concept | The advisory itself contains a working PoC: normalize('http://%256c%256f%2563%2561%256c%2568%256f%2573%2574/') → http://localhost/. Trivial to adapt. No weaponized exploit repos identified yet (disclosed 2026-08-23). |
| EPSS Score | Not yet scored (disclosed <48 hours ago). Sibling CVE-2026-6322 has EPSS 0.00029 (~low probability). Expect similar or lower given narrower affected population. |
| KEV Status | Not listed. No CISA KEV entry. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N — Network/no-auth/no-interaction. Integrity-only impact. Scope unchanged (no pivot across trust boundaries at the library level). |
| Affected Versions | 2.4.1–2.4.4, 3.1.2–3.1.5, 4.0.0–4.1.2. These are the versions that shipped the CVE-2026-6322 fix — the patch *caused* this regression. |
| Fixed Versions | 2.4.5, 3.1.6, 4.1.3 (all released 2026-08-23). |
| Scanning / Exposure | fast-uri has ~465M weekly npm downloads and 115K+ dependents. The vulnerable population is a subset: only those on the specific affected version ranges who applied the CVE-2026-6322 fix. Shodan/Censys are not relevant (library, not a service). |
| Disclosure Date | 2026-08-23 (coordinated disclosure via GitHub Security Advisory GHSA-fph4-wmhf-6fwf). |
| Credit | Reported by NotAFlightRisk. Fix by mcollina (Matteo Collina, Fastify lead). Reviewed by UlisesGascon. |
noisgate verdict.
The single most decisive factor driving the downgrade is that exploitation requires the consuming application to use fast-uri for URL policy enforcement before outbound requests — a minority use case among fast-uri's 115K+ dependents, the vast majority of which consume it through AJV/Fastify for JSON Schema $ref resolution where double-decoded hostnames have no security impact. The theoretical SSRF chain is real but the reachable population is a small fraction of the installed base.
Why this verdict
- Narrow exploitable use case: fast-uri is overwhelmingly consumed for JSON Schema $ref resolution via AJV and Fastify. URL allowlist enforcement — the only context where this double-decode matters — is a minority pattern among dependents.
- Regression-only population: Only versions 2.4.1+, 3.1.2+, and 4.0.0+ are affected — these are specifically the versions that shipped the CVE-2026-6322 fix. Users who never patched CVE-2026-6322 are *not* affected by this CVE (though they have the earlier bug).
- No scope change: CVSS Scope is Unchanged. The SSRF impact is bounded by the consuming application's network position and egress controls. Modern cloud environments with IMDSv2 and network segmentation further limit blast radius.
- Role multiplier: fast-uri is a utility library, not a canonically high-value-role component. It could theoretically appear in any role, but the exploitable scenario (URL allowlist bypass) is most relevant in web application tiers acting as SSRF gateways. In a CI/CD pipeline or identity provider context, fast-uri would typically be used for schema validation, not URL policy — the high-value role chain does not succeed in practice. Blast radius: host-level (the application server that makes the forged request), not fleet or domain scale.
- No exploitation evidence: No KEV listing, no known campaigns, no weaponized exploit repos. Disclosed <48 hours ago with a same-day patch available.
Why not higher?
Upgrading to HIGH would require either active exploitation evidence or a broader exploitable population. The vulnerability is in a library consumed overwhelmingly for schema validation, not URL security enforcement. The attack chain requires a specific application architecture (fast-uri normalize → allowlist check → outbound fetch using normalized output) that represents a minority of real-world deployments. Without evidence that a significant fraction of the 115K dependents use fast-uri this way, HIGH is not warranted.
Why not lower?
Dropping to LOW would undercount the risk for the subset of applications that *do* use fast-uri for URL validation. For those apps, the exploit is trivial (no auth, no interaction, simple double-encoding), the payload is already documented in the advisory, and SSRF to cloud metadata or internal services is a proven high-impact outcome. The 465M weekly download footprint means even a small percentage of vulnerable use cases is a non-trivial absolute number.
What to do — in priority order.
- Reject URLs containing
%25in the host component — The advisory's recommended workaround. Add input validation that rejects any URL whose host portion contains%25(the encoding of%) before passing it to fast-uri. This eliminates the double-decode vector at the input boundary. Deploy within the noisgate remediation SLA of 365 days, or sooner if your application uses fast-uri for URL policy enforcement. - Upgrade fast-uri to 2.4.5, 3.1.6, or 4.1.3 — The definitive fix. Run
npm audit fixor pin the patched version in package.json / package-lock.json. This is the remediation action — target the 365-day noisgate remediation SLA window. - Use Node.js built-in URL parser for security checks — If your application enforces URL allowlists, perform the hostname extraction using
new URL()(WHATWG parser) rather than fast-uri'snormalize(). The built-in parser does not double-decode. This architectural change eliminates the entire class of fast-uri parsing confusion bugs. - Enforce IMDSv2 on cloud instances — If your concern is SSRF to cloud metadata, requiring IMDSv2 (AWS) or equivalent token-based metadata access blocks the most common SSRF target. This doesn't fix the fast-uri bug but limits the blast radius of any SSRF.
- Deploy egress filtering / network segmentation — Restrict outbound connections from application servers to only known-good destinations. This limits what an SSRF attacker can reach even if the URL validation bypass succeeds.
- WAF rules matching
localhostor169.254.169.254in the URL — the double-encoded payload will not match these literal strings at the WAF layer; it only resolves after fast-uri processes it. - Upgrading to the CVE-2026-6322 fix versions (3.1.2–3.1.5) — those versions *are* the affected versions for this CVE. You need 3.1.6+, 2.4.5+, or 4.1.3+.
- Generic SSRF denylist in the application — if the denylist check runs against the fast-uri normalized output, the double-decoded hostname *will* match. But if it runs against the raw input, the encoded hostname bypasses it. The issue is check ordering, not the denylist itself.
Crowdsourced verification payload.
Run this on any machine with Node.js installed. It checks whether the installed fast-uri version is in the affected range. Invoke with: bash check_cve_2026_75899.sh /path/to/your/project. No special privileges required.
#!/usr/bin/env bash
# check_cve_2026_75899.sh — Detect CVE-2026-75899 in fast-uri
# Usage: bash check_cve_2026_75899.sh [project_dir]
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -euo pipefail
PROJECT_DIR="${1:-.}"
if [ ! -d "$PROJECT_DIR/node_modules/fast-uri" ]; then
echo "UNKNOWN — fast-uri not found in $PROJECT_DIR/node_modules/"
exit 2
fi
VERSION=$(node -e "console.log(require('$PROJECT_DIR/node_modules/fast-uri/package.json').version)" 2>/dev/null)
if [ -z "$VERSION" ]; then
echo "UNKNOWN — could not read fast-uri version"
exit 2
fi
echo "Detected fast-uri version: $VERSION"
# Check if version is in affected ranges using node semver comparison
RESULT=$(node -e "
const v = '$VERSION';
const [major, minor, patch] = v.split('.').map(Number);
let affected = false;
// 2.4.1 - 2.4.4
if (major === 2 && minor === 4 && patch >= 1 && patch <= 4) affected = true;
// 3.1.2 - 3.1.5
if (major === 3 && minor === 1 && patch >= 2 && patch <= 5) affected = true;
// 4.0.0 - 4.1.2
if (major === 4 && (minor === 0 || (minor === 1 && patch <= 2))) affected = true;
console.log(affected ? 'VULNERABLE' : 'PATCHED');
" 2>/dev/null)
if [ "$RESULT" = "VULNERABLE" ]; then
echo "VULNERABLE — fast-uri $VERSION is affected by CVE-2026-75899"
echo "Upgrade to 2.4.5, 3.1.6, or 4.1.3+"
exit 1
elif [ "$RESULT" = "PATCHED" ]; then
echo "PATCHED — fast-uri $VERSION is not in the affected range"
exit 0
else
echo "UNKNOWN — could not determine vulnerability status"
exit 2
fiIf you remember one thing.
normalize() or resolve() for URL allowlist enforcement — most Fastify/AJV consumers do not. First, run npm audit across your estate to identify projects pulling in affected versions (2.4.1–2.4.4, 3.1.2–3.1.5, 4.0.0–4.1.2). Second, for any application that *does* use fast-uri for URL security validation, treat this as urgent: reject %25 in hostnames immediately and upgrade to 4.1.3 / 3.1.6 / 2.4.5 this week. Third, for the majority of projects where fast-uri is a transitive AJV/Fastify dependency used only for schema $ref resolution, this falls under the noisgate MEDIUM remediation SLA — no mitigation SLA applies, go straight to the 365-day remediation window by scheduling the dependency bump into your next quarterly update cycle. There is no noisgate mitigation SLA for MEDIUM-severity findings. If you discover active exploitation targeting your stack, override to immediate patching.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.