---
id: "CVE-2026-110180"
kind: "vulnerability"
aliases: ["CVE-2026-110180", "GHSA-wjr9-j795-jxcr"]
title: "fast-uri vulnerable to host confusion via unchecked WHATWG host canonicalization"
severity: "medium"
cvss: 4.8
epss: 0.00208
exploited: false
status: "open"
category: "package"
products: [{"name": "fast-uri", "fixed": ["2.4.8"], "affected": ">= 2.4.2, < 2.4.8", "ecosystem": "npm"}, {"name": "fast-uri", "fixed": ["3.1.9"], "affected": ">= 3.1.3, < 3.1.9", "ecosystem": "npm"}, {"name": "fast-uri", "fixed": ["4.2.3"], "affected": ">= 4.0.1, < 4.2.3", "ecosystem": "npm"}]
ecosystems: ["npm"]
tags: ["cwe-20", "cwe-436", "node.js", "npm", "package", "ssrf-defense", "url-validation"]
not_affected_if: ["fast-uri-not-installed", "fast-uri-outside-2.4.2-to-4.2.2-range", "no-host-based-policy"]
published_at: "2026-10-20T07:17:08+00:00"
first_seen_at: "2026-10-23T21:39:59+00:00"
updated_at: "2026-10-23T21:57:20+00:00"
sources: [{"source": "ghsa", "url": "https://github.com/advisories/GHSA-wjr9-j795-jxcr", "first_seen_at": "2026-10-23T21:39:59+00:00"}, {"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-110180", "first_seen_at": "2026-10-23T21:57:20+00:00"}]
---

# fast-uri vulnerable to host confusion via unchecked WHATWG host canonicalization

fast-uri rewrites the host of http, https, ws and wss URLs without checking the whole input was a valid host, so an authority like 'a@b@evil.example' or one with a hidden TAB, CR or LF is silently turned into a different host. An application that checks hosts on one parse and connects using another can be steered to an unintended destination.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- npm:fast-uri affected >= 2.4.2, < 2.4.8 fixed 2.4.8
- npm:fast-uri affected >= 3.1.3, < 3.1.9 fixed 3.1.9
- npm:fast-uri affected >= 4.0.1, < 4.2.3 fixed 4.2.3

## How to check

Run: npm ls fast-uri
Look for fast-uri versions >= 2.4.2 <= 2.4.7, >= 3.1.3 <= 3.1.8, or >= 4.0.1 <= 4.2.2 in the output.
Check code that uses fast-uri for host allowlists, denylists, redirect validation or proxy routing.

## Fix

Upgrade fast-uri to 2.4.8, 3.1.9, or 4.2.3 (match your major line).
If you cannot upgrade, reject URIs with more than one '@' or any TAB, CR or LF in the authority before calling fast-uri.

## Timeline

- 2026-10-23T21:39:59+00:00 ghsa https://github.com/advisories/GHSA-wjr9-j795-jxcr
- 2026-10-23T21:57:20+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-110180

## From the sources

### Impact

`fast-uri` versions `>= 2.4.2, <= 2.4.7`, `>= 3.1.3, <= 3.1.8`, and `>= 4.0.1, <= 4.2.2` can silently rewrite the host of an HTTP-family URL (`http`, `https`, `ws`, `wss`, or any scheme with `domainHost: true`). For those schemes `canonicalizeHost()` passes the parsed host to the WHATWG `URL` parser and adopts its `.hostname` without checking that the parser read the whole input as a host. RFC 3986 permits `@` inside the host group and the WHATWG parser strips TAB, LF, and CR, so the authority `fast-uri` reports is rewritten by that second parser with no `error` set: data before an `@` is dropped and whitespace is removed.

For example, `fast-uri` parses `http://a@b@evil.example/` to host `evil.example` (dropping the `b` segment), and a host containing a raw TAB, CR, or LF has those characters stripped. `equal()` then treats a whitespace-smuggled host as the same as the clean one, and `resolve()` rewrites the authority the same way.

Applications that use `fast-uri` to enforce host-based policy (denylists, loopback filtering, redirect validation, outbound proxy routing) on one representation, such as the raw input, see a policy/use desync: the canonical host `fast-uri` returns differs from what was checked, and traffic can be steered to an unintended destination.

### Patches

Upgrade to `fast-uri` `2.4.8`, `3.1.9`, or `4.2.3`.

### Workarounds

Reject URIs whose authority contains more than one `@`, or contains TAB, CR, or LF, before calling `fast-uri`. Alternatively, treat any non-empty `parse(x).error` as fatal, and compare hosts only from the same `parse()` result.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
