Medium

H3 has an Open Redirect via Protocol-Relative Path in redirectBack() Referer Validation

  • Disclosed: 23.03.2026
  • Updated: 11.10.2026 10:22

Summary

The redirectBack() utility in h3 validates that the Referer header shares the same origin as the request before using its pathname as the redirect Location. However, the pathname is not sanitized for protocol-relative paths (starting with //). An attacker can craft a same-origin URL with a double-slash path segment that passes the origin check but produces a Location header interpreted by browsers as a protocol-relative redirect to an external domain.

Details

The vulnerable code is in src/utils/response.ts:89-97:

ts
export function redirectBack(
  event: H3Event,
  opts: { fallback?: string; status?: number; allowQuery?: boolean } = {},
): HTTPResponse {
  const referer = event.req.headers.get("referer");
  let location = opts.fallback ?? "/";
  if (referer && URL.canParse(referer)) {
    const refererURL = new URL(referer);
    if (refererURL.origin === event.url.origin) {
      // BUG: pathname can be "//evil.com/path" which browsers interpret
      // as a protocol-relative URL
      location = refererURL.pathname + (opts.allowQuery ? refererURL.search : "");
    }
  }
  return redirect(location, opts.status);
}

The root cause is a discrepancy between how the WHATWG URL parser and browsers handle double-slash paths:

  1. new URL("http://target.com//evil.com/path").origin → "http://target.com" — origin check passes
  2. new URL("http://target.com//evil.com/path").pathname → "//evil.com/path" — extracted as redirect location
  3. Browser receives Location: //evil.com/path → interprets as protocol-relative URL → redirects to evil.com

Attack scenario: The attacker shares a link like http://target.com//evil.com/page. If the target application has catch-all routes (common in SPAs built with h3/Nitro), the app serves its page at that URL. When the user navigates to an endpoint calling redirectBack(), the browser sends Referer: http://target.com//evil.com/page. The origin check passes, and the user is redirected to evil.com, which can host a phishing page mimicking the target.

PoC

bash
# 1. Create a minimal h3 app with redirectBack
cat > /tmp/h3-redirect-poc.ts << 'SCRIPT'
import { H3, redirectBack } from "h3";

const app = new H3();
app.post("/submit", (event) => redirectBack(event));

const res = await app.fetch(new Request("http://localhost/submit", {
  method: "POST",
  headers: { referer: "http://localhost//evil.com/steal" }
}));

console.log("Status:", res.status);
console.log("Location:", res.headers.get("location"));
// Expected: a same-origin path
// Actual: "//evil.com/steal" — protocol-relative redirect to evil.com
SCRIPT

# 2. Verify URL parsing behavior
node -e "
const u = new URL('http://localhost//evil.com/steal');
console.log('origin:', u.origin);         // http://localhost
console.log('pathname:', u.pathname);     // //evil.com/steal
console.log('origin matches localhost:', u.origin === 'http://localhost');  // true
"
# Output:
# origin: http://localhost
# pathname: //evil.com/steal
# origin matches localhost: true

Impact

An attacker can redirect users from a trusted application to an attacker-controlled domain. This enables:

  • Credential phishing: Redirect to a lookalike login page to harvest credentials
  • OAuth token theft: In OAuth flows using redirectBack(), steal authorization codes by redirecting to an attacker's callback
  • Trust exploitation: Users see the initial link points to the trusted domain, lowering suspicion

The vulnerability requires no authentication and affects any endpoint using redirectBack().

Recommended Fix

Sanitize the extracted pathname to prevent protocol-relative URLs. In src/utils/response.ts, after extracting the pathname from the referer:

ts
export function redirectBack(
  event: H3Event,
  opts: { fallback?: string; status?: number; allowQuery?: boolean } = {},
): HTTPResponse {
  const referer = event.req.headers.get("referer");
  let location = opts.fallback ?? "/";
  if (referer && URL.canParse(referer)) {
    const refererURL = new URL(referer);
    if (refererURL.origin === event.url.origin) {
      let pathname = refererURL.pathname;
      // Prevent protocol-relative open redirect (e.g., "//evil.com")
      if (pathname.startsWith("//")) {
        pathname = "/" + pathname.replace(/^\/+/, "");
      }
      location = pathname + (opts.allowQuery ? refererURL.search : "");
    }
  }
  return redirect(location, opts.status);
}

Affected software

Click a technology to see all vulnerabilities affecting it.

PlatformPackageVulnerable versionsFixed in
npm package h3 >= 2.0.1-rc.17, < 2.0.1-rc.18 2.0.1-rc.18

References

CVSS score 5.4/10
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N
Weakness (CWE)
CWE-601
Platform
npm
Package
h3
Disclosed
23.03.2026
Updated
11.10.2026 10:22

Sources and licenses

OSV / GitHub Advisory Database - GHSA-fp4x-ggrf-wmc6 - CC BY 4.0

Vulnerability history: h3

All published vulnerabilities of this package (npm package), newest first. Shows whether this is a one-off slip or a package that needs watching.

All (10) in the archive
Total entries
10
First → latest
01.2026 03.2026
Without a fix
0
Exploited in attacks
0

Severity breakdown

  • High 3
  • Medium 6
  • Low 1

Disclosures per year

  1. 2026: 10
Severity:
  1. H3 has an Open Redirect via Protocol-Relative Path in redirectBack() Referer Validation this entry
    Medium · 5.4 CVE-2026-86205 >= 2.0.1-rc.17, < 2.0.1-rc.18 2.0.1-rc.18
  2. High · 7.4 CVE-2026-33131 >= 2.0.0-0, < 2.0.1-rc.15 2.0.1-rc.15
  3. High · 7.5 CVE-2026-33128 >= 2.0.0, < 2.0.1-rc.15, < 1.15.6 2.0.1-rc.15, 1.15.6
  4. High · 8.9 CVE-2026-23527 < 1.15.5 1.15.5

Know which vulnerabilities affect your application

With the DockRay integration and software inventory enabled, DockRay checks reported component versions against known vulnerabilities and notifies you about confirmed matches. Coverage depends on the supported technology and available advisory data.

Connect your application
DockRay newsletter

Application security in your inbox

Important vulnerabilities, actionable guidance and practical advice for your applications. Choose your technologies and follow what matters to your project.

  • A daily digest of new vulnerabilities, critical ones included.
  • Notifications about important updates.
  • Practical advice on application security and monitoring.

Leave empty to receive updates for every technology.

Free to subscribe. Unsubscribe with one click in any email.