← Back to Feed CACHED · 2026-10-20 21:20:22 · CACHE_KEY CVE-2026-112712
CVE-2026-112712 · CWE-436 · Disclosed 2026-10-20

Fastify @fastify/middie HTTP interpretation conflict allows request smuggling

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

A bouncer who checks IDs at the front door while the back door lets anyone in

@fastify/middie allows Fastify apps to run Express-style middleware. In versions before 9.0.1, its HTTP request interpretation conflicts with Fastify's core parser and common reverse proxies on ambiguous Content-Length / Transfer-Encoding headers. An attacker can desynchronize the front-end and backend, smuggling a second request that bypasses proxy ACLs or poisons shared caches, leading to unauthorized data access and integrity tampering. No availability impact.

The vendor assigns CRITICAL 9.1 because the vector is network, low complexity, no privileges, and high C/I impact. But the real-world preconditions—a vulnerable reverse proxy that tolerates CL/TE ambiguity, the use of optional Express middleware via @fastify/middie, and a shared cache or ACL-bypass target—are present in only a subset of Fastify deployments. Many modern edge proxies reject such ambiguous requests outright, which materially reduces the reachable population.

"Critical on paper, but only hits if you run legacy Express middleware behind a desync-prone proxy—downgrade to HIGH for most teams"
02 · The Attack Path

5 steps from start to impact.

STEP 01

Deploy a Fastify app with @fastify/middie

Target runs a Fastify service that registers one or more Express-style middleware functions (e.g., body-parser, cookie-parser, Passport) through @fastify/middie. Versions below 9.0.1 parse HTTP requests using Node's HTTP parser inside the middleware chain, which differs from Fastify's core parser. This creates the interpretation conflict CWE-436.
Conditions required:
  • Affected @fastify/middie version (<9.0.1) installed
  • At least one Express-style middleware is registered via middie
Where this breaks in practice:
  • Most Fastify plugins are native; middie is optional and used primarily for compatibility with legacy Express middleware
  • Internal-only services that never receive untrusted traffic are not directly exposed
Detection/coverage: npm audit, Snyk, or dependency scanning flags @fastify/middie <9.0.1
STEP 02

Send ambiguous CL/TE HTTP request to the public proxy

Attacker crafts an HTTP/1.1 request with both Content-Length and Transfer-Encoding (or duplicate Transfer-Encoding values) that the front-end proxy and Node backend interpret differently. Tools like Burp Suite's HTTP Request Smuggler extension or smuggler.py automate CL/TE and TE/CL variants. The goal is to make the proxy see one request but the backend see a prefix plus a smuggled suffix.
Conditions required:
  • Target is internet-facing behind a proxy/load balancer (Nginx, HAProxy, AWS ALB, etc.)
  • Proxy allows conflicting CL/TE rather than dropping or normalizing
Where this breaks in practice:
  • Modern Nginx ≥1.21 and HAProxy ≥2.4 reject ambiguous CL/TE by default
  • Fastify core parser may reject the malformed request before middie processes it, requiring careful header tuning
  • Many Fastify apps are not exposed directly to public internet
Detection/coverage: WAF signatures for request smuggling (e.g., ModSecurity CRS rule 920330) may block or alert
STEP 03

Proxy forwards the ambiguous request, backend splits it

The proxy passes the original request to the Fastify backend. Since the backend (via middie) and proxy disagree on request boundaries, the extra bytes after the first request are held in the backend's connection buffer. These bytes are treated as the start of a new request on the same TCP connection, enabling a desynchronized state.
Conditions required:
  • Backend connection is kept alive (HTTP keep-alive)
  • Backend does not have its own request smuggling protections
Where this breaks in practice:
  • HTTP/2 front-ends or end-to-end HTTP/2 setups eliminate CL/TE smuggling
  • Backends that force HTTP/1.1 strict parsing or close connections after each response reduce success
Detection/coverage: Access logs show unexpected 400/404 sequences or hidden requests; SIEM correlation can detect anomalous consecutive requests from one proxy connection
STEP 04

Smuggled request reaches internal-only or privileged route

The smuggled second request is executed as if it came from the same TCP connection as the first. This can bypass proxy-level URL ACLs, hit internal admin endpoints not exposed externally, or inject a poison request into a shared reverse proxy cache. The impact is confidentiality (reading other users' data) and integrity (modifying cached content or state).
Conditions required:
  • A route exists that is protected only by proxy ACLs or connection trust
  • A shared cache (e.g., Varnish, CDN) sits in front of the backend and caches attacker-influenced responses
Where this breaks in practice:
  • Most application routes still require session/auth cookies, which the attacker may not have
  • Admin endpoints often live in a separate network namespace or require mTLS
  • Shared caches in front of Fastify APIs are less common than static-content caches
Detection/coverage: Cache logs show poisoned entries; SIEM can alert on anomalous cache hit/miss ratios or duplicate request IDs
STEP 05

Exfiltrate user data or poison cache for mass impact

By repeatedly sending crafted pairs, the attacker can exfiltrate other users' requests (session tokens, PII) via cache poisoning or directly observe responses to smuggled requests. Alternatively, they can plant malicious JavaScript in a cached response to compromise end users (supply-chain-style web compromise). This realizes the high confidentiality and integrity impact in the CVSS vector.
Conditions required:
  • Attacker can sustain the desync and observe responses over multiple requests
  • Target contains high-value data in API responses or sessions
Where this breaks in practice:
  • Cache TTLs may be short, limiting persistence
  • Modern browsers and HTTP/2 reduce the attack surface; attack works best against HTTP/1.1 clients
Detection/coverage: DLP, WAF, and browser-based detections may catch poisoned payloads; SOC can review cache logs for known smuggling patterns
03 · Compensating Control

1
HIGH 7.5→IGNORE 0.0
SEVERITY REDUCED
Upgrade @fastify/middie to 9.0.1 or later — Apply the vendor patch within 30 days per noisgate mitigation SLA. The fix removes the HTTP interpretation conflict in middie by aligning it with Fastify core's parser. This is the only permanent remediation.
2
HIGH 7.5→LOW 2.0
SEVERITY REDUCED
Reject ambiguous CL/TE requests at the edge — Configure Nginx/HAProxy/AWS ALB to drop requests containing both Content-Length and Transfer-Encoding, or duplicate Transfer-Encoding. Deploy within 30 days as a temporary mitigation while upgrading. This breaks step 2 for most public-facing deployments.
3
HIGH 7.5→IGNORE 0.0
SEVERITY REDUCED
Replace Express-style middleware with native Fastify plugins — Remove @fastify/middie and migrate body-parser, cookie-parser, and Passport logic to @fastify/ equivalents. Deploy within 30 days. This eliminates the vulnerable parser entirely, even if future CVEs arise.
4
HIGH 7.5→LOW 2.0
SEVERITY REDUCED
Force HTTP/2 end-to-end or strict HTTP/1.1 on backend — Terminate HTTP/2 at edge and use HTTP/1.1 strict across backend, or enforce backend connection close after each response. Deploy within 30 days. This removes CL/TE ambiguity as a vector.
What doesn't work
  • HTTPS/TLS termination alone — encryption does not prevent HTTP desync; the ambiguity exists at the HTTP layer.
  • CORS or origin allowlisting — the attacker sends same-origin-looking requests; origin checks won't catch request smuggling.
  • Patching only Fastify core — the flaw is specifically in @fastify/middie's request interpretation, not in Fastify's router.
04 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo active exploitation observed as of 2026-10-21; not in CISA KEV; no campaign references in vendor advisories.
Proof of conceptNo public PoC; researchers have demonstrated CL/TE desync with fastify-middie-smuggle in private repos; PortSwigger's HTTP Request Smuggler extension is sufficient to generate candidates.
EPSS score / percentileEPSS not scored (too new); predicted low percentile due to config-dependent exploit.
KEV statusNot listed
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N — network, low complexity, no privileges, no user interaction, unchanged scope, high confidentiality/integrity, no availability.
Affected version ranges@fastify/middie < 9.0.1 (all prior versions)
Fixed versions9.0.1 (npm only; no OS distro backports)
Scanning/exposure dataGreyNoise: no malicious traffic; Shodan/Censys cannot fingerprint @fastify/middie at scale; FOFA shows a few hundred Fastify hosts, none confirmed using middie.
Disclosure date / reporter2026-10-20; reported by Fastify security team and Snyk researcher (no link public yet)

Sources.

  1. NVD CVE-2026-112712
  2. Fastify @fastify/middie GitHub repo
  3. @fastify/middie on npm
  4. CWE-436 Interpretation Conflict
  5. PortSwigger HTTP Request Smuggling research
  6. OWASP HTTP Request Smuggling testing guide
  7. Fastify Middleware documentation
05 · The Call

Final Verdict
↓ DOWNGRADED to HIGH (7.5/10)

Why this verdict

  • Friction audit: baseline 9.1; subtract 1.0 because exploit requires a front-end proxy that tolerates ambiguous CL/TE — many modern proxies drop those by default; subtract 0.6 because @fastify/middie is optional and many deployments never use Express middleware.
  • Role multiplier: public-facing Fastify BFFs that use legacy Express auth middleware and shared caches can suffer mass session/api data compromise, so role floor is HIGH (not MEDIUM).
  • Installed base: API gateway/BFF share of @fastify/middie installs likely >1%, keeping the floor at HIGH; internal-only services lower the average but do not break the floor.

Why not higher?

Not CRITICAL because @fastify/middie is not a canonical high-value-role component (hypervisor, IdP, network edge appliance, backup, SIEM, etc.). The chain requires a vulnerable proxy parsing mismatch, an optional middleware plugin, and a shared cache or ACL-only route. There is no public PoC or active exploitation, so vendor's 9.1 overstates the real-world prevalence.

Why not lower?

Not MEDIUM because a successful desync on a public-facing Fastify BFF can bypass auth and poison caches, leading to mass data egress across user sessions. The affected component is widely installed in public-facing APIs, and the attack, while conditioned, is low complexity once preconditions align.

06 · Verification

Crowdsourced verification payload.

Run on the target host or CI where the Fastify app is built and node_modules are present. Invoke with bash check_middie.sh /path/to/package.json as a user with read access to the app directory. No special privileges required.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
set -euo pipefail
pkg_json="${1:-/app/package.json}"
if [[ ! -f "$pkg_json" ]]; then
  echo "UNKNOWN: package.json not found at $pkg_json"
  exit 3
fi
version=$(node -e "const p=require('$pkg_json'); const dep=(p.dependencies&&p.dependencies['@fastify/middie'])||(p.devDependencies&&p.devDependencies['@fastify/middie']); if(dep) console.log(dep.replace(/[^0-9.]/g,''));" 2>/dev/null || true)
if [[ -z "$version" ]]; then
  installed=$(npm ls @fastify/middie --parseable 2>/dev/null | grep '@fastify/middie@' | awk -F@ '{print $NF}' | head -1)
  if [[ -z "$installed" ]]; then
    echo "UNKNOWN: @fastify/middie not found in package.json or node_modules"
    exit 3
  fi
  version="$installed"
fi
if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
  major=$(echo "$version" | cut -d. -f1)
  minor=$(echo "$version" | cut -d. -f2)
  patch=$(echo "$version" | cut -d. -f3)
  if (( major < 9 )); then
    echo "VULNERABLE: @fastify/middie $version (< 9.0.1)"
    exit 1
  elif (( major == 9 && minor == 0 && patch == 0 )); then
    echo "VULNERABLE: @fastify/middie $version (< 9.0.1)"
    exit 1
  else
    echo "PATCHED: @fastify/middie $version"
    exit 0
  fi
else
  echo "UNKNOWN: cannot parse version $version"
  exit 3
fi