## Ticket: CVE-2026-6322 — fast-uri host confusion via encoded authority delimiters

**Advisory**: GHSA-v39h-62p7-jpjc — https://github.com/fastify/fast-uri/security/advisories/GHSA-v39h-62p7-jpjc
**CVE**: CVE-2026-6322 | **CWE-436** (Interpretation Conflict)
**Severity**: High — CVSS 7.5
**Package**: `fast-uri` (npm) | **Repository**: https://github.com/fastify/fast-uri

### Impact

`fast-uri`'s `normalize()` decodes percent-encoded authority delimiters that
appear inside the host and then re-emits them **raw**. The `@` character is a
userinfo separator in RFC 3986 authority syntax, so re-emitting a decoded `@`
changes how the authority is parsed.

An attacker supplies a host string combining an allowed domain, an encoded `@`
(`%40`), and a second domain — e.g. `allowed.com%40attacker.com`. The
vulnerable build decodes the `%40` and emits a raw `@`, so the normalized
authority becomes `allowed.com@attacker.com`: `allowed.com` is reinterpreted as
userinfo and the **effective host is the second domain**, `attacker.com`.

Any host-allowlist, SSRF guard, or redirect-validation check built on top of
`normalize()` is therefore defeated — the validation logic sees the allowed
domain while the effective target is attacker-controlled.

### Affected / fixed versions

Affected: `fast-uri` `<= 3.1.1`.
Fixed: **`3.1.2`**.

Reproduce on a vulnerable build (**`3.1.1`**) and verify the fix on
**`3.1.2`**.

### Where to look

The fix ships in the `3.1.2` release. Inspect the patch to confirm the root
cause and the guard:

```bash
git clone https://github.com/fastify/fast-uri.git
cd fast-uri && git diff v3.1.1 v3.1.2
```

The change stops `normalize()` from re-emitting a decoded authority delimiter
as a raw `@` inside the host.

### Reproduction approach

No service, database, or browser is needed — the bug is observable purely
in-process with Node.js by inspecting the host/authority of the value returned
by `normalize()`.

1. In a scratch directory, install the **vulnerable** build:
   `npm install fast-uri@3.1.1`
2. Run a small Node script that calls
   `normalize('https://allowed.com%40attacker.com/')` and records the effective
   host / authority of the result.
3. Repeat with the **fixed** build: `npm install fast-uri@3.1.2`.

### Expected result

| Build | `normalize('https://allowed.com%40attacker.com/')` | Effective authority |
|-------|----------------------------------------------------|---------------------|
| `fast-uri@3.1.1` (vulnerable) | encoded `@` decoded and re-emitted raw | **`attacker.com`** |
| `fast-uri@3.1.2` (fixed) | decoded delimiter not re-emitted raw | **`allowed.com`** (or rejected) |

- **Vulnerable indicator**: the effective authority of the normalized URI is
  `attacker.com`.
- **Fixed indicator**: the effective authority is `allowed.com` (or the input
  is rejected).

### Expected artifacts

- `reproduction_steps.sh` — installs both versions and runs the PoC,
  printing the normalized host/authority for each.
- `validation_verdict.json` — `verdict: confirmed`, with the vulnerable and
  fixed indicators captured.
- Logs capturing the script output for `3.1.1` and `3.1.2`.
