← Back to Feed CACHED · 2026-10-27 13:18:56 · CACHE_KEY CVE-2026-112362
CVE-2026-112362 · CWE-436 · Disclosed 2026-10-27

@fastify/express scoped middleware authentication bypass via absolute-form URL normalization

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

A toll booth that only works when the highway sign is right-side-up — flip one config flag and cars blow through unchecked

CVE-2026-112362 is an authentication-bypass flaw in @fastify/express versions 4.0.5 through 4.0.8, the bridge plugin that lets teams run Express middleware inside a Fastify server. When Fastify's ignoreDuplicateSlashes router option is enabled (it defaults to false), the plugin's path-matching logic normalizes duplicate slashes in a way that also collapses the :// separator in absolute-form HTTP request targets (e.g., GET http://host//admin/secret). Fastify's router resolves the request to the scoped route and executes the handler, but the Express middleware layer — which was supposed to enforce auth, authz, or rate-limiting on that path — never sees the match and silently steps aside. An unauthenticated remote attacker can reach any protected handler behind Express middleware with a single crafted HTTP request.

The vendor scored this CVSS 9.1 CRITICAL, treating Attack Complexity as Low. That overstates the real-world exposure. The ignoreDuplicateSlashes option defaults to false; you must opt in explicitly. @fastify/express itself is a transitional bridge library (~103K weekly npm downloads) — most Fastify deployments don't load it at all, and of those that do, only a minority flip ignoreDuplicateSlashes. The CVSS vector's AC:L does not reflect that non-default prerequisite. That said, when the stars align — the flag is on, Express middleware guards the route, and the service is internet-facing — the bypass is trivially exploitable with a one-liner curl, and the impact is full auth bypass with no user interaction. This is a genuine HIGH-severity issue for affected deployments, but calling it CRITICAL inflates priority across the fleet.

"Auth bypass is real but needs a non-default flag most Fastify apps never flip"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify a @fastify/express service with ignoreDuplicateSlashes

The attacker needs to find a target running @fastify/express 4.0.5–4.0.8 with ignoreDuplicateSlashes: true set in the Fastify server factory. This is a non-default configuration. Reconnaissance typically involves probing for path-normalization behavior — sending requests with duplicate slashes and observing whether the server collapses them (200 vs 404 on //health vs /health).
Conditions required:
  • Target runs @fastify/express ≥4.0.5 <4.0.9
  • Fastify is configured with ignoreDuplicateSlashes: true
  • Service is network-reachable
Where this breaks in practice:
  • ignoreDuplicateSlashes defaults to false — most deployments never enable it
  • @fastify/express is a niche migration-bridge library; many Fastify apps use native middleware or @fastify/middie instead
  • No banner or header reveals the Fastify config flag
Detection/coverage: No Nuclei template or Nessus plugin exists for this CVE as of disclosure day. Version fingerprinting of Node.js frameworks via HTTP headers is unreliable; X-Powered-By is commonly stripped.
STEP 02

Locate an Express-middleware-protected scoped route

The attacker identifies a path guarded by Express middleware — typically an admin panel, internal API, or privileged endpoint mounted under a prefix like /admin or /api/v1/internal. The auth check is registered via app.use('/admin', authMiddleware) in the Express compatibility layer. The attacker tries common admin paths or uses directory brute-forcing tools like ffuf or feroxbuster.
Conditions required:
  • A scoped route exists that is protected by Express middleware (not a Fastify preHandler hook)
  • The auth/authz logic lives exclusively in that Express middleware layer
Where this breaks in practice:
  • Teams that followed Fastify best practices use preHandler hooks for auth, which are unaffected
  • Applications may have defense-in-depth (e.g., WAF path rules, Cloudflare Access, API gateway auth) independent of the Express middleware
Detection/coverage: WAF rules inspecting for absolute-form request targets in the first request line could flag anomalous requests, though most WAFs parse the path component only.
STEP 03

Craft an absolute-form HTTP request with duplicate slashes

The attacker sends a request using the absolute-form target syntax (RFC 7230 §5.3.2) with a duplicate slash that triggers normalization. For example: GET http://target.example.com//admin/dashboard HTTP/1.1. Fastify's duplicate-slash normalizer collapses //admin to /admin and routes to the handler. Simultaneously, the :// in the scheme gets mangled in the Express layer's path extraction, so the Express middleware mounted on /admin does not match and is skipped entirely. Tools: plain curl, httpie, or any HTTP client that allows raw request-line control.
Conditions required:
  • Attacker can send HTTP/1.1 requests with absolute-form targets to the server
  • No upstream proxy rewrites or strips absolute-form request lines before they reach Fastify
Where this breaks in practice:
  • Some reverse proxies (nginx, HAProxy) normalize or reject absolute-form request targets before they reach the application, breaking the attack chain
  • HTTP/2 frontends decompose the request into pseudo-headers, eliminating the absolute-form vector entirely
  • CDN/edge proxies (Cloudflare, AWS ALB) may normalize or reject non-standard request forms
Detection/coverage: Access logs may show the raw absolute-form URL if the reverse proxy preserves it. A detection rule matching GET http:// in the request line of access logs is a low-false-positive indicator.
STEP 04

Access protected handler without authentication

The handler executes with full privileges. Depending on what the route does, the attacker can read sensitive data (C:H), modify records or configuration (I:H), or pivot further. The Express auth middleware never fires, so no credentials are checked, no session is validated, and no rate-limiting applies. The impact is scoped to whatever that handler exposes — it could be an admin CRUD panel, a user-management API, or an internal metrics endpoint.
Conditions required:
  • The handler behind the middleware returns sensitive data or allows state-changing operations
Where this breaks in practice:
  • If the handler itself performs secondary auth checks (e.g., verifying a JWT in the request body), the bypass is mitigated
  • Application-level audit logging may still fire, creating forensic evidence
Detection/coverage: Application audit logs showing privileged operations without a corresponding authentication event. SIEM correlation: handler invocation without prior auth-middleware log entry.
03 · Compensating Control

1
HIGH 7.2→IGNORE 0.0
SEVERITY REDUCED
Upgrade @fastify/express to 4.0.9 immediately — The definitive fix. Run npm install @fastify/[email protected] or update your lockfile and redeploy. Per the noisgate mitigation SLA for HIGH severity, deploy within 30 days. Given the trivial exploitability when preconditions are met and same-day patch availability, aim for days, not weeks.
2
HIGH 7.2→IGNORE 0.0
SEVERITY REDUCED
Disable ignoreDuplicateSlashes — If you cannot upgrade immediately, set ignoreDuplicateSlashes to false (the default) in your Fastify server factory options. This completely eliminates the attack vector because the path normalization that collapses the scheme separator no longer runs. Test your application for any routes that depend on duplicate-slash tolerance. Deploy within the 30-day noisgate mitigation SLA for HIGH.
3
HIGH 7.2→IGNORE 0.0
SEVERITY REDUCED
Move auth to Fastify preHandler hooks — Migrate authentication and authorization checks from Express middleware (app.use('/path', authMw)) to Fastify's preHandler hook, which executes *after* the router resolves the request and is unaffected by this normalization gap. This is the vendor-recommended workaround and also hardens against the related CVE-2026-33808. Even after patching, this is better architectural hygiene. Deploy within the 30-day mitigation window.
4
HIGH 7.2→MEDIUM 5.5
SEVERITY REDUCED
Ensure a normalizing reverse proxy sits in front of Fastify — Confirm that your reverse proxy (nginx, HAProxy, Envoy, or a CDN like Cloudflare/AWS ALB) normalizes or rejects absolute-form HTTP request targets before they reach the Fastify process. Most standard proxy configurations already do this. Verify by sending curl --request-target 'http://yourhost//admin' http://yourhost/ and confirming a 400 or rewritten path in Fastify's access log. This is defense-in-depth, not a standalone fix.
What doesn't work
  • Network-level firewalling / IP allowlisting — The attack uses a standard HTTP request on the same port and path the service legitimately serves. Firewall rules cannot distinguish the malicious absolute-form target from normal traffic.
  • WAF generic SQL injection / XSS rulesets — The payload is a well-formed URL with no injection characters. Standard OWASP CRS rules do not inspect the request-line form (absolute vs. relative).
  • Rate limiting on the unprotected path — The entire point of the bypass is that the rate-limiting middleware is skipped. Adding rate limiting in the same Express middleware layer does not help; it must be in a Fastify hook or at the reverse proxy.
04 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNo evidence. Not listed in CISA KEV. No campaigns or threat-actor usage reported as of 2026-10-27. Disclosure is same-day as this assessment.
Proof-of-Concept AvailabilityNo public PoC. Not indexed on pocindex.io, no GitHub repos named after CVE-2026-112362, no ExploitDB or Metasploit module. However, the exploit is conceptually trivial — a single curl command with an absolute-form URL — so weaponization requires minutes, not days.
EPSS ScoreNot yet scored — CVE was disclosed 2026-10-27 (today). FIRST EPSS model typically ingests new CVEs within 24–72 hours. Expect a low-to-moderate EPSS given the non-default config prerequisite.
CISA KEV StatusNot listed. No due date imposed.
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N — vendor-assigned 9.1. The AC:L is debatable; the non-default ignoreDuplicateSlashes flag is a prerequisite the vector does not capture. With AC:H the score drops to 7.4.
Affected Versions@fastify/express ≥4.0.5 <4.0.9 (npm). Versions <4.0.5 are affected by the *separate* CVE-2026-33808 (GHSA-6hw5-45gm-fj88), a related but distinct normalization bypass.
Fixed Version@fastify/express 4.0.9 — released 2026-10-27. No distro backports apply; this is a pure npm package.
Package Footprint~103K weekly npm downloads. This is a migration-bridge library, not core Fastify. For comparison, fastify core sees ~5M+ weekly downloads. The vulnerable population is a small fraction of the Node.js ecosystem.
Disclosure TimelineReserved 2026-10-19 by OpenJS Foundation (CNA). Published and patched simultaneously on 2026-10-27. Coordinated disclosure with patch available at announcement.
Researcher / CNAReported through the OpenJS Foundation security process. GHSA ID: GHSA-6h42-57hq-9746. No individual researcher publicly credited at time of disclosure.

Sources.

  1. GitHub Security Advisory GHSA-6h42-57hq-9746
  2. @fastify/express v4.0.9 Release (patch)
  3. Strix.ai CVE-2026-112362 Analysis
  4. Offseq Radar — CVE-2026-112362 Threat Report
  5. Related Advisory CVE-2026-33808 (GHSA-6hw5-45gm-fj88)
  6. Fastify Server Options Documentation (ignoreDuplicateSlashes)
  7. @fastify/express on npm
05 · The Call

Final Verdict
↓ DOWNGRADED to HIGH (7.2/10)

Why this verdict

  • Non-default configuration gate: The ignoreDuplicateSlashes option defaults to false. The attack chain is dead unless the deployer explicitly opts in. The CVSS vector's AC:L does not account for this; recalculating with AC:H gives 7.4. This is the single largest downward adjustment from the vendor's 9.1.
  • Niche library, narrow installed base: @fastify/express has ~103K weekly npm downloads — a bridge library for Express-to-Fastify migrations. Most Fastify deployments (5M+ core downloads) never load this plugin. The intersection of 'uses @fastify/express' AND 'enables ignoreDuplicateSlashes' AND 'relies on Express middleware for auth' is a small population.
  • Upstream proxy normalization breaks the chain: The absolute-form request target required for exploitation is non-standard. nginx (the most common Node.js reverse proxy) normalizes request targets before forwarding. AWS ALB, Cloudflare, and HTTP/2 frontends similarly decompose or reject absolute-form lines. Many production deployments are shielded by infrastructure they already have.
  • No PoC, no exploitation, day-zero disclosure: Patch shipped simultaneously with advisory. No weaponized exploit exists. While the exploit is conceptually simple, the timing gives defenders a window before any scanning begins.
  • Role multiplier: @fastify/express is an application-layer library, not infrastructure. It does not canonically occupy a high-value role (not an IdP, hypervisor, CI/CD system, CA, or network edge). The worst plausible high-value scenario is an API gateway or admin service built on Fastify+Express bridge with the non-default flag — this is realistic but not the dominant deployment pattern. Blast radius is application-scoped (data in that service), not domain-wide or fleet-wide. This keeps the floor at HIGH but does not elevate to CRITICAL.
  • Trivial exploitation when conditions met (floor enforcement): Despite the friction, when an app *does* meet all preconditions, exploitation requires only a curl one-liner from an unauthenticated remote position, yielding complete auth bypass. This prevents downgrading below HIGH.

Why not higher?

The non-default ignoreDuplicateSlashes configuration requirement is a hard gate that the majority of @fastify/express deployments do not pass through. The package itself is a transitional bridge library (~103K weekly downloads vs. ~5M for Fastify core), not infrastructure that canonically sits in a high-value role. The blast radius of a successful exploit is scoped to a single application instance — there is no domain takeover, fleet compromise, or supply-chain pivot inherent to this vulnerability. Without evidence of active exploitation or a public PoC driving mass scanning, CRITICAL is not warranted.

Why not lower?

When the preconditions are met, exploitation is trivially achievable by an unauthenticated remote attacker with a single HTTP request — no tooling, no credentials, no user interaction. The impact is complete authentication and authorization bypass on scoped routes, which can expose admin panels and sensitive data. The attack is network-reachable (AV:N), and some production deployments serving real user data will have this exact configuration. A MEDIUM rating would understate the risk for those environments and could lead to deprioritization that leaves exploitable services exposed.

06 · Verification

Crowdsourced verification payload.

Run this script on any machine with node (≥16) and network access to your npm registry or local node_modules. It checks the installed version of @fastify/express in the current project directory. No special privileges needed. Usage: chmod +x check_cve_2026_112362.sh && ./check_cve_2026_112362.sh /path/to/your/project

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_cve_2026_112362.sh — Detect CVE-2026-112362 in @fastify/express
# Checks installed package version and Fastify config for ignoreDuplicateSlashes
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN

set -euo pipefail

PROJECT_DIR="${1:-.}"
PKG_NAME="@fastify/express"
FIXED_VERSION="4.0.9"
MIN_VULN="4.0.5"

if [ ! -d "$PROJECT_DIR/node_modules" ]; then
  echo "UNKNOWN — node_modules not found in $PROJECT_DIR. Run 'npm install' first or pass the correct project path."
  exit 2
fi

PKG_JSON="$PROJECT_DIR/node_modules/@fastify/express/package.json"

if [ ! -f "$PKG_JSON" ]; then
  echo "UNKNOWN — $PKG_NAME is not installed in $PROJECT_DIR."
  exit 2
fi

INSTALLED=$(node -e "console.log(require('$PKG_JSON').version)" 2>/dev/null)
if [ -z "$INSTALLED" ]; then
  echo "UNKNOWN — could not read version from $PKG_JSON."
  exit 2
fi

echo "Installed $PKG_NAME version: $INSTALLED"

# Compare versions using node's semver-compatible comparison
IS_VULN=$(node -e "
  const v = '$INSTALLED'.split('.').map(Number);
  const min = '$MIN_VULN'.split('.').map(Number);
  const fix = '$FIXED_VERSION'.split('.').map(Number);
  function cmp(a, b) {
    for (let i = 0; i < 3; i++) {
      if (a[i] < b[i]) return -1;
      if (a[i] > b[i]) return 1;
    }
    return 0;
  }
  const vuln = cmp(v, min) >= 0 && cmp(v, fix) < 0;
  console.log(vuln ? 'YES' : 'NO');
" 2>/dev/null)

if [ "$IS_VULN" = "YES" ]; then
  # Check for ignoreDuplicateSlashes in source files
  echo ""
  echo "Checking for ignoreDuplicateSlashes usage..."
  MATCHES=$(grep -rl 'ignoreDuplicateSlashes' "$PROJECT_DIR/"*.js "$PROJECT_DIR/src/" "$PROJECT_DIR/lib/" 2>/dev/null || true)
  if [ -n "$MATCHES" ]; then
    echo "WARNING: ignoreDuplicateSlashes found in:"
    echo "$MATCHES"
    echo ""
    echo "VULNERABLE — $PKG_NAME $INSTALLED is in the affected range ($MIN_VULN – <$FIXED_VERSION) AND ignoreDuplicateSlashes is referenced in source. CVE-2026-112362 applies."
    exit 1
  else
    echo "ignoreDuplicateSlashes not found in project source (checked .js, src/, lib/)."
    echo ""
    echo "VULNERABLE (version) — $PKG_NAME $INSTALLED is in the affected range ($MIN_VULN – <$FIXED_VERSION), but ignoreDuplicateSlashes was not detected in source. Verify manually that this option is not set at runtime. Upgrade to $FIXED_VERSION+ regardless."
    exit 1
  fi
else
  echo ""
  echo "PATCHED — $PKG_NAME $INSTALLED is outside the vulnerable range ($MIN_VULN – <$FIXED_VERSION)."
  exit 0
fi