Skip to content

CVE-2026-6321: Verified Repro With Script Download

CVE-2026-6321: fast-uri: path traversal via percent-encoded segments decoded before normalization

CVE-2026-6321 is verified against fast-uri · npm. Affected versions: <= 3.1.0. Fixed in 3.1.1. Vulnerability class: Path Traversal. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00145.

REPRO-2026-00145 fast-uri · npm Path Traversal May 22, 2026 CVE entry ↗ .txt
Severity
HIGH
CVSS
7.5
Reproduced in
10m 8s
Tool calls
154
Spend
$1.20
01 · Overview

What Is CVE-2026-6321?

CVE-2026-6321 (GHSA-q3j6-qgpj-74h6) is a high-severity path-traversal vulnerability (CWE-22) in the fast-uri npm package's normalize() and equal() functions, which decode percent-encoded path segments before applying RFC 3986 dot-segment removal. Pruva reproduced it (reproduction REPRO-2026-00145).

02 · Severity & CVSS

CVE-2026-6321 Severity & CVSS Score

CVE-2026-6321 is rated high severity, with a CVSS base score of 7.5 out of 10.

HIGH threat level
7.5 / 10 CVSS base
03 · Affected Versions

Affected fast-uri Versions

fast-uri · npm versions <= 3.1.0 are affected.

How to Reproduce CVE-2026-6321

$ pruva-verify REPRO-2026-00145
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00145/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-6321

Reproduced by Pruva's autonomous agents — 154 tool calls over 10 min. Full root-cause analysis and the complete transcript are below.

How the agent worked 557 events · 154 tool calls · 10 min
10 minDuration
154Tool calls
133Reasoning steps
557Events
1Dead-ends
Agent activity over 10 min
Support
26
Repro
182
Variant
344
0:0010:08

Root Cause and Exploit Chain for CVE-2026-6321

Summary

fast-uri versions 3.1.0 and earlier decode percent-encoded path separators (%2F) and dot segments (%2E) before applying RFC 3986 dot-segment removal during URI normalization. This allows an attacker to bypass path-prefix allowlist checks: an encoded traversal sequence such as %2e%2e%2f is first decoded into literal ../, then processed as a real dot segment, causing the normalized path to escape the intended prefix. The equal() function suffers the same flaw, incorrectly reporting two distinct URIs as equal when one uses encoded traversal.

Impact

  • Package: fast-uri (npm)
  • Affected versions: <= 3.1.0
  • Fixed version: 3.1.1
  • CVE: CVE-2026-6321
  • CWE: CWE-22 (Path Traversal)
  • Severity: High (CVSS 7.5)
  • Consequences: Any authorization logic that relies on fast-uri.normalize() or fast-uri.equal() to validate a path prefix can be bypassed. An attacker-supplied URI may normalize to a path outside the intended directory, leading to unauthorized access.

Root Cause

The vulnerability stems from the order of operations in the parse() and serialize() pipeline:

  1. Vulnerable (v3.1.0): parse() calls parsed.path = escape(unescape(parsed.path)). The built-in unescape() converts %2e to . and %2f to /, so %2e%2e%2f becomes the literal string ../. When serialize() later calls removeDotSegments() on this already-decoded path, the sequence is treated as a real parent-directory traversal instruction, collapsing public/../admin to admin.

  2. Fixed (v3.1.1): The code replaces the blanket escape(unescape(...)) with normalizePathEncoding(), which deliberately preserves reserved path escapes such as %2F and %2E. Because these remain encoded, removeDotSegments() sees them as ordinary path data, not as dot segments, and the path stays confined.

The fix commit changes index.js and lib/utils.js and adds a regression test (test/security-normalization.test.js) that asserts %2E%2E stays encoded during normalization and that equal() no longer conflates encoded and literal separators.

Reproduction Steps

The reproduction is fully automated by repro/reproduction_steps.sh.

What the script does:

  1. Creates two isolated npm projects.
  2. Installs fast-uri@3.1.0 (vulnerable) in one project.
  3. Runs a Node.js script that calls normalize() and equal() on URIs containing encoded traversal sequences (%2e%2e, %2f).
  4. Installs fast-uri@3.1.1 (fixed) in the second project.
  5. Runs the identical test script.
  6. Compares the outputs and writes a JSON verdict.

Expected evidence:

  • Vulnerable: normalize('http://example.com/public/%2e%2e/admin') returns http://example.com/admin.
  • Fixed: normalize('http://example.com/public/%2e%2e/admin') returns http://example.com/public/%2E%2E/admin.
  • Vulnerable: equal('http://example.com/public/%2e%2e/admin', 'http://example.com/admin') returns true.
  • Fixed: equal(...) returns false.

Evidence

  • Vulnerable output log: logs/vuln-output.txt
  • Fixed output log: logs/fixed-output.txt
  • Validation verdict: logs/validation_verdict.json

Key excerpts from the vulnerable run:

INPUT:  http://example.com/public/%2e%2e/admin
OUTPUT: http://example.com/admin

equal('http://example.com/public/%2e%2e/admin', 'http://example.com/admin') => true

Key excerpts from the fixed run:

INPUT:  http://example.com/public/%2e%2e/admin
OUTPUT: http://example.com/public/%2E%2E/admin

equal('http://example.com/public/%2e%2e/admin', 'http://example.com/admin') => false

Environment:

  • Node.js runtime (any recent LTS)
  • No external services, databases, or browsers required
  • Pure in-process JavaScript test

Recommendations / Next Steps

  1. Upgrade immediately to fast-uri@3.1.1 or later.
  2. Audit existing code that uses normalize() or equal() for path-prefix or URI-allowlist decisions. Replace any ad-hoc workarounds with the patched library.
  3. Add regression tests for encoded traversal sequences (%2e%2e%2f, %2e%2e, %2f) in your own URI-handling logic.
  4. Consider defense in depth: wherever possible, validate resolved filesystem paths (e.g., using path.resolve() and checking the result is under a trusted root) rather than relying solely on URI normalization.

Additional Notes

  • Idempotency: The reproduction script was executed twice consecutively with identical results, confirming idempotency.
  • Edge cases tested: single encoded slash (%2f), double encoded dot-dot (%2e%2e), chained sequences (%2e%2e/%2e%2e), and the equal() false-positive case. All behaved consistently with the vulnerability description.

CVE-2026-6321 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:000:40
0:00
session startedaccounts/fireworks/models/kimi-k2p6 · cve-2026-6321 · cve-2026
0:09
0:11
0:12
web search
0:14
0:15
web search
0:17
0:19
0:20
web search
0:21
0:22
0:36
0:36
extract_facts
no facts extracted
0:37
0:37
0:37
supportrepro
0:38
0:39
0:39
0:39
0:40

Artifacts and Evidence for CVE-2026-6321

Scripts, logs, diffs, and output captured during the reproduction.

No artifacts available

08 · How to Fix

How to Fix CVE-2026-6321

Upgrade fast-uri · npm to 3.1.1 or later.

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-6321 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-6321

How does the CVE-2026-6321 traversal bypass work in practice?

Any authorization logic that calls fast-uri's normalize() or equal() to validate that a URI's path stays under an allowed prefix can be bypassed: an attacker supplies a URI containing an encoded traversal sequence such as %2e%2e%2f, which fast-uri decodes into '../' and then collapses via dot-segment removal, causing the normalized result to escape the allowlisted prefix. equal() suffers the identical flaw, incorrectly treating two distinct URIs as equal when one uses the encoded traversal form.

Which fast-uri versions are affected by CVE-2026-6321, and where is it fixed?

fast-uri versions <= 3.1.0 are affected. It is fixed in 3.1.1.

How severe is CVE-2026-6321?

It is rated high severity with a CVSS score of 7.5: any authorization decision built on fast-uri's normalize() or equal() path-prefix comparison can be bypassed, leading to unauthorized access outside the intended directory.

How can I reproduce CVE-2026-6321?

Download the verified script from this page and run it in an isolated environment against fast-uri <= 3.1.0. It builds a path-prefix allowlist check on top of normalize()/equal(), supplies a URI with an encoded %2e%2e%2f traversal sequence, and shows the normalized path escaping the allowed prefix on the vulnerable build while 3.1.1 correctly rejects it.
11 · References

References for CVE-2026-6321

Authoritative sources for CVE-2026-6321 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.