← Back to Feed CACHED · 2026-09-03 02:19:31 · CACHE_KEY CVE-2026-84394
CVE-2026-84394 · CWE-436 · Disclosed 2026-09-02

fast-uri vulnerable to host confusion via an unclosed bracket in the URI authority

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

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-compilerajv 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.

"Parser differential matters only if you use fast-uri as an SSRF gate — most don't."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify a fast-uri–gated endpoint

The attacker locates an application endpoint that accepts a user-supplied URL, parses it with 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.
Conditions required:
  • Application exposes an endpoint accepting user-controlled URLs
  • Application uses fast-uri (not Node's URL) for host-based security filtering
Where this breaks in practice:
  • 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()
STEP 02

Craft a bracket-malformed URI

The attacker constructs a URI whose authority starts with [ 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.
Conditions required:
  • fast-uri version ≤ 2.4.5 / ≤ 3.1.6 / ≤ 4.1.3
Where this breaks in practice:
  • Trivial to construct — no tooling needed beyond a browser or curl
Detection/coverage: Static analysis rules checking for fast-uri.parse() output used in security-sensitive comparisons could flag this pattern.
STEP 03

Bypass the host-based policy

Because the parsed host from fast-uri does not match the denylist entry, the application allows the request. The original URL string is then forwarded to the downstream HTTP client (Node 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).
Conditions required:
  • 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
Where this breaks in practice:
  • 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
Detection/coverage: Runtime SSRF detection (e.g., outbound request monitoring for metadata IP ranges) catches the actual request regardless of parser bypass.
STEP 04

Reach internal or metadata target

The HTTP request lands on the cloud metadata service (169.254.169.254), an internal microservice, or a loopback address. The attacker exfiltrates IAM credentials, internal API responses, or other sensitive data accessible from the server's network position. Impact is bounded by the server's network access and IAM role — typically read-only metadata or limited internal API access.
Conditions required:
  • Target server has network access to sensitive internal endpoints
  • Cloud metadata service is not hardened with IMDSv2 or equivalent
Where this breaks in practice:
  • AWS IMDSv2 requires a PUT-based token exchange that most SSRF payloads cannot perform
  • Network segmentation and metadata endpoint hardening are increasingly standard
Detection/coverage: Cloud provider metadata access logs (e.g., AWS CloudTrail for IMDS) and VPC flow logs detect anomalous internal access patterns.
03 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNo evidence. Not listed in CISA KEV. No known campaigns or threat actor usage as of 2026-09-03.
Proof of conceptNo 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 scoreNot yet scored — CVE published September 2, 2026; EPSS data typically lags 1–2 weeks for new entries.
KEV statusNot listed. No CISA KEV entry as of 2026-09-03.
CVSS vectorCVSS: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 versionsfast-uri ≤ 2.4.5 (v2 branch), ≤ 3.1.6 (v3 branch), ≤ 4.1.3 (v4 branch)
Fixed versions2.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 footprintfast-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 date2026-09-02 (reserved 2026-09-01)
ReporterYashvantHange (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.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (5.3/10)

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.

HIGH Vulnerability existence and affected version ranges confirmed via vendor advisory
MEDIUM Exploitable population estimate (small fraction of install base uses fast-uri for security decisions)
LOW EPSS and in-the-wild status (CVE too new for EPSS scoring; absence of evidence ≠ evidence of absence)

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.

05 · Compensating Control

What to do — in priority order.

  1. Audit codebases for direct fast-uri security use — Search for require('fast-uri') or import … from 'fast-uri' where the parsed host field 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.
  2. 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).hostname which applies WHATWG normalization consistent with what fetch and http.request use. This eliminates the parser differential entirely, regardless of fast-uri version.
  3. 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.
  4. 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.
  5. 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 fix or npm update. Per noisgate remediation SLA for MEDIUM, complete within 365 days.
What doesn't work
  • 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.
06 · Verification

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

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

If you remember one thing.

TL;DR
This is a MEDIUM severity parser-differential bug that matters only if your application uses fast-uri directly for SSRF filtering or host-based security decisions — the vast majority of consumers (Ajv/Fastify transitive users) are unaffected in practice. Start by auditing for direct 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

  1. GHSA-58mr-gqgx-xq4g — GitHub Security Advisory
  2. CVE-2026-84394 — ThreatInt CVE Database
  3. fast-uri npm package
  4. fast-uri GitHub repository
  5. @fastify/ajv-compiler — npm (primary consumer of fast-uri)
  6. GitLab Advisory Database — fast-uri CVE-2026-16221 (related host confusion)
  7. fast-uri security overview — 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.