Like a locked door with a fake keyhole that only opens if someone hands the burglar the key slot itself
CVE-2026-84292 affects the fast-uri npm package — a dependency-free RFC 3986 URI toolbox maintained by the Fastify project and consumed by AJV for JSON Schema validation. The serialize(), normalize(), and equal() functions escape userinfo and host components but concatenate the port value verbatim. An attacker who can inject a non-digit string into the port field of a URI components object can insert authority delimiters (@, :) that demote the intended host to userinfo and redirect the authority to an attacker-controlled host. Both fast-uri and Node's built-in URL class parse the poisoned output as the attacker's host with no error, so downstream re-validation is useless. Affected versions: <2.4.6, 3.0.0–3.1.6, and 4.0.0–4.1.3. Fixed in 2.4.6, 3.1.7, and 4.1.4.
The vendor rates this HIGH at 7.5 with an integrity-only vector (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N). That score assumes an unauthenticated, network-reachable attacker can trivially reach the vulnerable code path. In reality, the attacker must control the port field specifically of a URI components object passed to serialize() — not a parsed URL string, not a query parameter, but an object property that most applications either hardcode or derive from a prior parse() call on a full URL. The dominant consumer of fast-uri (~130M weekly downloads) is AJV via @fastify/ajv-compiler, where it resolves JSON Schema $ref URIs that are author-defined, not user-supplied. The vendor severity overstates the real-world exposure for the vast majority of installations.
4 steps from start to impact.
Identify an application passing untrusted input to port
fast-uri.serialize() (or normalize() / equal()) and feeds user-controlled data into the port property of the URI components object. This is not a typical code pattern — most apps either parse full URL strings or use constant ports. The attacker needs source code review, error message leakage, or fuzzing to discover this.- Application uses fast-uri serialize/normalize/equal with object input
- User-controlled data reaches the
portproperty specifically
- Most fast-uri consumers use it via AJV for schema validation where URIs are developer-defined
- Typical web apps parse full URL strings rather than building URI components objects from user input
- The port field is almost always an integer or omitted entirely
Craft malicious port payload
@attacker.com:8080 or :@evil.com. When fast-uri concatenates this without validation, the serialized URI becomes something like https://legitimate-host:@attacker.com:8080/path, which standard URL parsers interpret as attacker.com:8080 being the real host with legitimate-host demoted to userinfo.- No input validation on the port value before passing to fast-uri
- Many applications validate port as an integer before using it
- Type-checking (TypeScript strict mode) would catch a non-number port in many codebases
@ characters in port-position fields could catch this, though it requires custom rules.Application makes outbound request to poisoned URI
- Application uses the serialized URI to make an outbound HTTP request or redirect
- No additional URL validation between serialization and use
- Applications that only use fast-uri for schema validation (AJV) never make requests to the resulting URIs
- Security-conscious apps re-parse and validate outbound URLs, but note that re-parsing also reads the attacker's host
Achieve SSRF or open redirect
- Server-side request or redirect follows the poisoned URI
- Target network allows outbound connections or internal pivoting
- Cloud environments with IMDSv2 block unauthenticated metadata access
- Egress filtering and network segmentation limit SSRF impact
- Open redirect alone is typically low-severity
The supporting signals.
| In-the-wild exploitation | No known exploitation as of 2026-09-03. Not listed in CISA KEV. Disclosed one day ago (2026-09-02). |
|---|---|
| Proof-of-concept | No public standalone PoC repository yet. The advisory description itself is essentially a PoC recipe: pass @attacker.com:8080 as the port to serialize(). Trivial to reproduce. |
| EPSS score | Not yet scored — CVE disclosed <48 hours ago. Expected to be low given the unusual prerequisite. |
| KEV status | Not listed in CISA KEV 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 vector, low complexity, no privileges, integrity-only impact. The AC:L is generous; real-world attack complexity is higher due to the specific code pattern needed. |
| Affected versions | fast-uri <2.4.6, 3.0.0–3.1.6, 4.0.0–4.1.3 |
| Fixed versions | 2.4.6, 3.1.7, 4.1.4 — fix validates port is digit-only per RFC 3986 |
| Install base / exposure | ~130M weekly npm downloads. Primary consumer is AJV (JSON Schema validation) via @fastify/ajv-compiler. Most installs are transitive dependencies where the vulnerable code path is not reachable. |
| Disclosure date | 2026-09-02 via GitHub Security Advisory (OpenJS Foundation CNA) |
| Reporter | YashvantHange — reported to OpenJS Foundation |
noisgate verdict.
The single most decisive factor driving the downgrade is the narrow triggering code pattern: the attacker must control the port property of a URI components object passed to serialize(), a pattern that the dominant consumer (AJV schema validation, representing the vast majority of the 130M weekly installs) never exercises with untrusted input. While SSRF impact can be severe, the reachable population is a small fraction of the installed base.
Why this verdict
- Triggering prerequisite is rare: The attacker must control the
portproperty of a URI components *object* — not a URL string, not a query param. Most applications either hardcode ports, parse full URLs, or validate port as an integer. This eliminates the vast majority of the 130M weekly download install base from exploitability. - Dominant consumer is not exploitable: AJV and Fastify use fast-uri to resolve JSON Schema
$refURIs. These are developer-defined schema references, not user-supplied input. The vulnerableserialize()path is not reachable in this usage pattern. - No exploitation evidence: Disclosed <48 hours ago, no KEV listing, no known campaigns, no weaponized PoC tooling. The advisory description is clear enough to reproduce, but no attacker has been observed leveraging it.
- Role multiplier: fast-uri runs in Node.js application servers. (a) *Low-value role*: dev tooling, linters, test runners using AJV — not exploitable, port field is never user-controlled. (b) *Typical role*: Fastify API servers using AJV for request validation — port field comes from schema definitions, not user input; chain does not succeed. (c) *High-value role*: A custom application that builds outbound URLs from user-controlled parts using
serialize()and makes server-side requests — this could be an API gateway or proxy service. If exploitable in this role, blast radius is SSRF → cloud metadata / internal service access (host-level, possibly tenant-level). However, this represents a small fraction (<5%) of the installed base, and the outcome is host/tenant-level, not fleet/domain-level. The floor check is satisfied at MEDIUM — no domain/fleet/supply-chain outcome is plausible from this chain alone.
Why not higher?
Upgrading to HIGH would require either active exploitation evidence or a code pattern where the majority of installations expose the vulnerable path. Neither condition is met. The dominant AJV/Fastify usage never passes untrusted data to the port field. Even in the worst-case SSRF scenario, the blast radius is bounded to the compromised host's network position, not fleet-scale.
Why not lower?
The sheer install base (130M weekly downloads) means even a small exploitable fraction represents thousands of applications. The authority injection bypasses re-validation (both fast-uri and Node URL parse the poisoned output as the attacker's host), which is a particularly insidious property. An active PoC is trivial to construct from the advisory text. Dropping below MEDIUM would understate the risk for the minority of apps that do build URIs from user-controlled parts.
What to do — in priority order.
- Validate port as integer before passing to fast-uri — Add
if (!Number.isInteger(Number(port)) || Number(port) < 0 || Number(port) > 65535) throwbefore any call toserialize(),normalize(), orequal()with user input. This neutralizes the injection regardless of fast-uri version. No SLA-driven deadline — go straight to the 365-day remediation window per noisgate MEDIUM SLA. - Upgrade fast-uri to patched version — Run
npm audit fixor pin fast-uri to >=2.4.6 (v2), >=3.1.7 (v3), or >=4.1.4 (v4). For transitive dependencies via AJV/@fastify/ajv-compiler, update the parent package. This is the remediation action — complete within 365 days per noisgate remediation SLA. - Audit codebase for serialize() with user input — Use
grep -rn 'serialize\|normalize\|equal' node_modules/fast-uriin your app code (not node_modules) to find direct fast-uri usage. If your app only consumes fast-uri transitively via AJV, the vulnerable path is almost certainly not reachable. Confirm and document. - Enforce egress filtering and IMDSv2 — If any application does have an SSRF-exploitable path, egress proxy rules and AWS IMDSv2 (or equivalent cloud metadata hardening) limit the blast radius of successful exploitation. These are defense-in-depth controls you should already have.
- WAF rules on inbound URLs — The injection happens in the *port field of a programmatic object*, not in a URL string the WAF sees. The WAF never inspects the internal
serialize()call. - Content-Security-Policy headers — CSP governs browser-side resource loading. This vulnerability is server-side URI construction; CSP is irrelevant.
- Pinning fast-uri to a specific version without upgrading — Pinning the vulnerable version prevents breakage but also prevents the fix. You need to pin to the *patched* version.
Crowdsourced verification payload.
Run this on any host or CI runner with Node.js installed and access to the project's node_modules. No special privileges needed. Example: bash check_fasturl_cve2026_84292.sh /path/to/your/project
#!/usr/bin/env bash
# check_fasturl_cve2026_84292.sh
# Checks whether fast-uri is vulnerable to CVE-2026-84292 (port authority injection)
# Usage: bash check_fasturl_cve2026_84292.sh [project_dir]
# Exit codes: 0 = PATCHED, 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"
exit 2
fi
# Find all installed fast-uri versions
FOUND=0
VULN=0
while IFS= read -r pkg_json; do
dir=$(dirname "$pkg_json")
name=$(node -e "try{console.log(require('$pkg_json').name)}catch(e){console.log('')}" 2>/dev/null)
version=$(node -e "try{console.log(require('$pkg_json').version)}catch(e){console.log('')}" 2>/dev/null)
if [ "$name" = "fast-uri" ] && [ -n "$version" ]; then
FOUND=1
# Parse major.minor.patch
IFS='.' read -r major minor patch <<< "$version"
major=${major:-0}; minor=${minor:-0}; patch=${patch:-0}
SAFE=0
if [ "$major" -eq 2 ] && [ "$minor" -gt 4 ]; then SAFE=1; fi
if [ "$major" -eq 2 ] && [ "$minor" -eq 4 ] && [ "$patch" -ge 6 ]; then SAFE=1; fi
if [ "$major" -eq 3 ] && [ "$minor" -gt 1 ]; then SAFE=1; fi
if [ "$major" -eq 3 ] && [ "$minor" -eq 1 ] && [ "$patch" -ge 7 ]; then SAFE=1; fi
if [ "$major" -eq 4 ] && [ "$minor" -gt 1 ]; then SAFE=1; fi
if [ "$major" -eq 4 ] && [ "$minor" -eq 1 ] && [ "$patch" -ge 4 ]; then SAFE=1; fi
if [ "$major" -gt 4 ]; then SAFE=1; fi
if [ "$SAFE" -eq 1 ]; then
echo "PATCHED — fast-uri $version at $dir"
else
echo "VULNERABLE — fast-uri $version at $dir"
VULN=1
fi
fi
done < <(find "$PROJECT_DIR/node_modules" -name package.json -maxdepth 5 2>/dev/null)
if [ "$FOUND" -eq 0 ]; then
echo "UNKNOWN — fast-uri not found in $PROJECT_DIR/node_modules"
exit 2
fi
if [ "$VULN" -eq 1 ]; then
exit 1
else
exit 0
fiIf you remember one thing.
npm audit across your Node.js projects to identify which ones carry a vulnerable fast-uri version. Then audit those projects for direct serialize(), normalize(), or equal() calls with user-controlled input — if none exist, you are not exploitable and this is pure backlog hygiene. There is no mitigation SLA for MEDIUM — go straight to the 365-day noisgate remediation SLA and roll the patched version (2.4.6 / 3.1.7 / 4.1.4) into your next scheduled dependency update cycle. If you do find a code path where untrusted data reaches the port field, add integer validation immediately and prioritize the upgrade.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.