← Back to Feed CACHED · 2026-08-24 10:04:15 · CACHE_KEY CVE-2026-75899
CVE-2026-75899 · CWE-174 · Disclosed 2026-08-23

fast-uri vulnerable to server-side request forgery via repeated hostname percent-decoding

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

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.

"Library-level double-decode SSRF that only fires when apps use fast-uri for URL policy enforcement."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify a target application using fast-uri for URL policy enforcement

The attacker locates a web application or API that accepts user-supplied URLs and passes them through fast-uri's 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.
Conditions required:
  • 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)
Where this breaks in practice:
  • 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
Detection/coverage: npm audit and Snyk will flag the vulnerable fast-uri version in the dependency tree.
STEP 02

Craft double-encoded hostname payload

The attacker constructs a URL where the hostname is double percent-encoded. For example, to target 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.
Conditions required:
  • Attacker can supply arbitrary URL to the application's input
Where this breaks in practice:
  • Payload construction is trivial — no exploit code or tooling required
Detection/coverage: WAF rules matching %25 sequences in the Host component can flag this pattern.
STEP 03

Bypass allowlist / denylist check

The application's allowlist check sees the still-encoded hostname (e.g., %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.
Conditions required:
  • Application performs allowlist check BEFORE fast-uri normalization fully decodes the hostname
  • Application uses the normalized output for the actual outbound request
Where this breaks in practice:
  • 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
STEP 04

Achieve SSRF to internal resources

The outbound request reaches the attacker's target: internal services, cloud metadata endpoints (169.254.169.254), or other hosts behind the allowlist. Impact is limited to what the SSRF can reach — typically read-only metadata, internal API responses, or in worst cases credential harvesting from cloud IMDS. The CVSS vector correctly notes C:N/I:H/A:N — integrity impact (request forgery) without direct confidentiality or availability impact at the fast-uri layer.
Conditions required:
  • Internal services or metadata endpoints are reachable from the application server
Where this breaks in practice:
  • Cloud providers increasingly require IMDSv2 (hop-limited, token-required), which blocks basic SSRF to metadata
  • Network segmentation and egress filtering limit lateral reach
Detection/coverage: Cloud-native SSRF detection (e.g., GuardDuty for AWS metadata access anomalies) can catch exploitation.
03 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNo known exploitation. Not listed on CISA KEV. No reports of active campaigns targeting this CVE as of 2026-08-24.
Proof of ConceptThe 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 ScoreNot 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 StatusNot listed. No CISA KEV entry.
CVSS VectorCVSS: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 Versions2.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 Versions2.4.5, 3.1.6, 4.1.3 (all released 2026-08-23).
Scanning / Exposurefast-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 Date2026-08-23 (coordinated disclosure via GitHub Security Advisory GHSA-fph4-wmhf-6fwf).
CreditReported by NotAFlightRisk. Fix by mcollina (Matteo Collina, Fastify lead). Reviewed by UlisesGascon.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (5.5/10)

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.

HIGH Vulnerability mechanism and affected versions confirmed via vendor advisory
MEDIUM Fraction of dependents using fast-uri for URL policy enforcement (estimated minority, no hard data)
LOW EPSS and exploitation likelihood (CVE is <48 hours old)

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.

05 · Compensating Control

What to do — in priority order.

  1. Reject URLs containing %25 in 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.
  2. Upgrade fast-uri to 2.4.5, 3.1.6, or 4.1.3 — The definitive fix. Run npm audit fix or pin the patched version in package.json / package-lock.json. This is the remediation action — target the 365-day noisgate remediation SLA window.
  3. 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's normalize(). The built-in parser does not double-decode. This architectural change eliminates the entire class of fast-uri parsing confusion bugs.
  4. 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.
  5. 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.
What doesn't work
  • WAF rules matching localhost or 169.254.169.254 in 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.
06 · Verification

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.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/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
fi
07 · Bottom Line

If you remember one thing.

TL;DR
CVE-2026-75899 is a real double-decode SSRF bypass in fast-uri, but its exploitability hinges on whether your application uses fast-uri's 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

  1. GitHub Security Advisory GHSA-fph4-wmhf-6fwf
  2. fast-uri Security Advisories (all)
  3. CVE-2026-6322 — predecessor vulnerability (GHSA-v39h-62p7-jpjc)
  4. CWE-174: Double Decoding of the Same Data
  5. fast-uri on npm
  6. OWASP SSRF Prevention Cheat Sheet
  7. fast-uri releases (GitHub)
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.