Leaving a bracket dangling so the bouncer reads a different name on your ID than the one the taxi driver sees
CVE-2026-84394 is a parser-differential bug in fast-uri, the dependency-free RFC 3986 URI toolbox maintained under the Fastify GitHub org. When a URI authority contains an opening bracket [ without a matching closing bracket ] — e.g. http://@127.0.0.1/path — fast-uri's parse() neither validates it as an IPv6 literal nor flags an error. It returns the malformed string as the host with error: undefined. Node's built-in WHATWG URL constructor and HTTP clients like fetch or axios resolve that same string to a *different* host. The bug affects fast-uri ≤ 2.4.5, ≤ 3.1.6, and ≤ 4.1.3, and is fixed in 2.4.6, 3.1.7, and 4.1.4. Published September 2, 2026 under [GHSA-58mr-gqgx-xq4g.
The vendor rates this HIGH at CVSS 7.5 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N). That score is technically correct *if* the application uses fast-uri output to make a host-based security decision (SSRF denylist, redirect allowlist, proxy routing) and then hands the original URL to a different parser for the actual HTTP request. In practice, the overwhelming majority of fast-uri's 100M+ weekly npm downloads arrive transitively through @fastify/ajv-compiler → ajv for JSON Schema $ref resolution and format: "uri" validation, where host extraction has zero security relevance. The exploitable population — apps that use fast-uri directly as an SSRF gate — is a tiny fraction of the install base, which makes the vendor score misleadingly broad.
4 steps from start to impact.
Identify a fast-uri–gated endpoint
fast-uri.parse(), and uses the returned host field to enforce a security policy (e.g., blocking requests to 127.0.0.1, 169.254.169.254, or internal RFC 1918 ranges). This is the architectural prerequisite — without it, the parser differential has no security impact.- Application exposes an endpoint accepting user-controlled URLs
- Application uses fast-uri (not Node's URL) for host-based security filtering
- Most fast-uri consumers use it transitively via Ajv for schema validation, not URL security
- Developers building SSRF filters more commonly use Node's built-in URL or well-known libraries like
new URL()
Craft a bracket-malformed URI
[ but omits the closing ], such as http://[@169.254.169.254/latest/meta-data/. fast-uri returns the raw malformed string as the host (e.g., [@169.254.169.254) without setting an error, so the denylist check compares against a string that does not match 169.254.169.254.- fast-uri version ≤ 2.4.5 / ≤ 3.1.6 / ≤ 4.1.3
- Trivial to construct — no tooling needed beyond a browser or curl
fast-uri.parse() output used in security-sensitive comparisons could flag this pattern.Bypass the host-based policy
http.request, fetch, axios, etc.), which applies WHATWG URL parsing and resolves the host differently — landing on the attacker's intended target (e.g., the cloud metadata endpoint or an internal service).- Application passes the *original* URL (not fast-uri's serialized output) to the HTTP client
- Downstream HTTP client resolves the malformed host to the attacker's intended destination
- If the app re-serializes via fast-uri before making the request, the malformed host propagates and the HTTP client may reject it
- WAFs or API gateways upstream may independently block requests to metadata IPs
Reach internal or metadata target
- Target server has network access to sensitive internal endpoints
- Cloud metadata service is not hardened with IMDSv2 or equivalent
- AWS IMDSv2 requires a PUT-based token exchange that most SSRF payloads cannot perform
- Network segmentation and metadata endpoint hardening are increasingly standard
The supporting signals.
| In-the-wild exploitation | No evidence. Not listed in CISA KEV. No known campaigns or threat actor usage as of 2026-09-03. |
|---|---|
| Proof of concept | No weaponized PoC published. The advisory describes the payload pattern ([@127.0.0.1) which is trivially reproducible but requires a vulnerable application architecture to have security impact. |
| EPSS score | Not yet scored — CVE published September 2, 2026; EPSS data typically lags 1–2 weeks for new entries. |
| KEV status | Not listed. No CISA KEV entry as of 2026-09-03. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N — Network-accessible, no privileges or interaction needed, high integrity impact, no confidentiality or availability impact. |
| Affected versions | fast-uri ≤ 2.4.5 (v2 branch), ≤ 3.1.6 (v3 branch), ≤ 4.1.3 (v4 branch) |
| Fixed versions | 2.4.6, 3.1.7, 4.1.4 — parse() now returns URI host is malformed. for any host containing a bracket that is not a valid [IPv6] literal. |
| Exposure footprint | fast-uri has ~100M+ weekly npm downloads, but the vast majority arrive as a transitive dependency of @fastify/ajv-compiler for JSON Schema validation. Direct use as a URL security filter is a small fraction of the install base. |
| Disclosure date | 2026-09-02 (reserved 2026-09-01) |
| Reporter | YashvantHange (reporter); mcollina (remediation developer); UlisesGascon (reviewer). Part of a broader fast-uri host-confusion audit that produced CVE-2026-6322, CVE-2026-13676, CVE-2026-16221, CVE-2026-18446, and others. |
noisgate verdict.
The single most decisive factor driving this downgrade is the narrow exploitable population: while fast-uri has 100M+ weekly downloads, the overwhelming majority are transitive Ajv/Fastify schema-validation consumers where host parsing has no security relevance — only the small subset of applications that use fast-uri output as an SSRF denylist or redirect allowlist are affected. The impact ceiling is SSRF (integrity-only, no RCE), bounded by downstream network segmentation and cloud metadata hardening.
Why this verdict
- Narrow exploitable architecture: The bug only has security impact when an application uses
fast-uri.parse()for host-based security decisions (SSRF denylist, redirect allowlist) AND passes the original URL to a different parser for the HTTP request. Most of the 100M+ weekly downloads flow through Ajv for JSON Schema validation, where host extraction is irrelevant. - No RCE, integrity-only impact: The CVSS vector confirms C:N/I:H/A:N — the worst case is SSRF to internal endpoints. There is no code execution, privilege escalation, or data destruction path from this bug alone.
- Modern cloud hardening reduces blast radius: AWS IMDSv2, GCP metadata concealment, and Azure IMDS token requirements mean the classic SSRF-to-credential-theft chain is increasingly blocked even when the parser bypass succeeds.
- Role multiplier: fast-uri is a utility library, not a product that canonically occupies a high-value infrastructure role. In theory, a Fastify-based API gateway or webhook proxy *could* use fast-uri for SSRF filtering, putting it in a network-edge-adjacent role — but this is an atypical deployment pattern, not the default. The blast radius in the typical role (schema validation in a web app) is zero. In the worst-case atypical role (SSRF gate in an API proxy), the blast radius is tenant-level SSRF, not fleet or domain compromise.
- No exploitation evidence or weaponized tooling: No KEV listing, no known campaigns, no public exploit tooling. The payload pattern is trivial to construct but requires identifying a vulnerable application architecture first.
Why not higher?
To warrant HIGH, the exploitable population would need to be a significant fraction of the install base, or the impact would need to reach beyond SSRF to RCE or domain-level compromise. Neither condition holds: the vast majority of fast-uri consumers are Ajv schema validators with no security-relevant host parsing, and the impact ceiling is bounded SSRF without code execution.
Why not lower?
Despite the narrow exploitable population, the parser differential is real, trivially triggered (no authentication, no user interaction), and the SSRF bypass pattern is a well-understood attack class. Any application that *does* use fast-uri as an SSRF gate is fully exposed with no friction once the architectural prerequisite is met. The bug also sits in a library with enormous reach, so even a small percentage of direct consumers represents a non-trivial number of applications.
What to do — in priority order.
- Audit codebases for direct fast-uri security use — Search for
require('fast-uri')orimport … from 'fast-uri'where the parsedhostfield is used in denylist/allowlist comparisons, proxy routing, or redirect validation. If found, those are your priority targets. Most Ajv/Fastify transitive consumers are not affected and can follow the standard 365-day remediation window. - Switch SSRF validation to Node's built-in URL constructor — If your application uses fast-uri for host-based security decisions, replace the parsing step with
new URL(input).hostnamewhich applies WHATWG normalization consistent with whatfetchandhttp.requestuse. This eliminates the parser differential entirely, regardless of fast-uri version. - Enforce IMDSv2 and metadata endpoint hardening — On AWS, require IMDSv2 (hop limit = 1, PUT token required). On GCP, enable metadata concealment. On Azure, use managed identity token endpoints. This reduces the blast radius of any SSRF bypass to near-zero for the most common high-value target.
- Deploy outbound request monitoring — Monitor for HTTP requests from application servers to RFC 1918 ranges, link-local (169.254.x.x), and loopback addresses. Alert on unexpected internal access patterns regardless of how the SSRF filter was bypassed.
- Update fast-uri to patched versions — Upgrade to fast-uri 2.4.6, 3.1.7, or 4.1.4. For most consumers this is a transitive dependency update via
npm audit fixornpm update. Per noisgate remediation SLA for MEDIUM, complete within 365 days.
- WAF URL normalization rules — most WAFs inspect the inbound HTTP request URL, not the URL *parameter value* that the application will later use for an outbound SSRF request. The malformed bracket is in the parameter payload, not the request path.
- Input length or character-set restrictions — the payload (
[@169.254.169.254) uses only ASCII characters and is short enough to fit any reasonable URL parameter limit. - Upgrading Fastify alone — if your application directly imports fast-uri (not via Ajv), upgrading Fastify won't change the fast-uri version your code resolves. Check your direct dependency tree.
Crowdsourced verification payload.
Run on any host with Node.js ≥ 14 and npm/yarn available, in the root of the project you want to check. No special privileges needed. Example: bash check_fast_uri.sh /path/to/your/project
#!/usr/bin/env bash
# check_fast_uri.sh — Detect CVE-2026-84394 (fast-uri unclosed bracket host confusion)
# Usage: bash check_fast_uri.sh [/path/to/project]
# Exit codes: 0 = PATCHED/NOT_PRESENT, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
PROJECT_DIR="${1:-.}"
if [ ! -d "$PROJECT_DIR/node_modules" ]; then
echo "UNKNOWN — no node_modules found in $PROJECT_DIR. Run npm install first."
exit 2
fi
# Find all installed fast-uri versions
FOUND=0
VULN=0
while IFS= read -r pkg_json; do
version=$(node -e "console.log(require('$pkg_json').version)" 2>/dev/null || echo "unknown")
if [ "$version" = "unknown" ]; then
continue
fi
FOUND=1
major=$(echo "$version" | cut -d. -f1)
minor=$(echo "$version" | cut -d. -f2)
patch=$(echo "$version" | cut -d. -f3)
vulnerable=false
case $major in
2)
if [ "$minor" -lt 4 ] || ([ "$minor" -eq 4 ] && [ "$patch" -le 5 ]); then
vulnerable=true
fi
;;
3)
if [ "$minor" -lt 1 ] || ([ "$minor" -eq 1 ] && [ "$patch" -le 6 ]); then
vulnerable=true
fi
;;
4)
if [ "$minor" -lt 1 ] || ([ "$minor" -eq 1 ] && [ "$patch" -le 3 ]); then
vulnerable=true
fi
;;
1|0)
vulnerable=true
;;
esac
if [ "$vulnerable" = true ]; then
echo "VULNERABLE — fast-uri $version found at $pkg_json"
VULN=1
else
echo "PATCHED — fast-uri $version found at $pkg_json"
fi
done < <(find "$PROJECT_DIR/node_modules" -path '*/fast-uri/package.json' -not -path '*/node_modules/.cache/*' 2>/dev/null)
if [ "$FOUND" -eq 0 ]; then
echo "PATCHED — fast-uri not found in $PROJECT_DIR (not a dependency)."
exit 0
fi
if [ "$VULN" -gt 0 ]; then
exit 1
else
exit 0
fiIf you remember one thing.
fast-uri.parse() usage in security-sensitive code paths; if you find none, this is routine dependency hygiene. There is no noisgate mitigation SLA for MEDIUM — go straight to the 365-day noisgate remediation SLA and roll the update (npm update fast-uri or pin to ≥ 2.4.6 / ≥ 3.1.7 / ≥ 4.1.4) into your next scheduled dependency refresh cycle. If you *do* find fast-uri used as an SSRF gate, treat those specific services as HIGH-priority: switch host validation to new URL().hostname immediately and patch within 30 days. No active exploitation or KEV listing exists, so there is no override requiring emergency action.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.