← Back to Feed CACHED · 2026-09-15 07:24:26 · CACHE_KEY CVE-2026-90711
CVE-2026-90711 · CWE-290 · Disclosed 2026-09-15

proxy-addr is a Node.js module that determines a request's client address behind trusted reverse proxies

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

A fire alarm that silently disconnects itself when you wire it with a metric-to-imperial adapter

CVE-2026-90711 affects proxy-addr versions 1.1.0 through 2.0.7, the module that powers req.ip and req.ips in Express.js. When a developer configures a trust subnet using IPv4-mapped IPv6 notation with an IPv4-sized prefix — e.g., ::ffff:10.0.0.0/8 instead of the correct ::ffff:10.0.0.0/104 — the library silently accepts the input and proceeds to trust every IPv4 address on the internet. An unauthenticated remote attacker can then inject arbitrary X-Forwarded-For headers, controlling the IP address the application reads. This defeats IP-based access control, rate limiting, geolocation enforcement, and audit-log integrity. The fix in 2.0.8 validates prefix lengths for mapped subnets.

The vendor rates this CRITICAL at 9.1, and the CVSS vector (AV:N/AC:L/PR:N/UI:N) is technically accurate *if* the misconfiguration is present. But that’s a big “if.” The overwhelming majority of Express apps configure trust proxy with plain IPv4 notation (10.0.0.0/8), a numeric hop count (app.set('trust proxy', 1)), or named presets (loopback, linklocal, uniquelocal). The IPv4-mapped IPv6 form with a wrong-length prefix is a niche footgun. The CVSS effectively bakes in AC:L for a condition that is closer to AC:H in the real world. Additionally, the impact ceiling is IP spoofing — serious for security controls, but not remote code execution. A downgrade to HIGH at 6.5 is warranted.

"Massive install base but narrow trigger: only IPv6-mapped trust configs with wrong prefix are vulnerable."
02 · The Attack Path

3 steps from start to impact.

STEP 01

Identify Express app with vulnerable proxy-addr

Attacker identifies a target Express.js application reachable over the internet. The application uses proxy-addr <= 2.0.7 (bundled with Express 4.x/5.x). The key precondition is that the app’s trust proxy configuration uses IPv4-mapped IPv6 notation with an incorrect IPv4-sized prefix, such as ::ffff:10.0.0.0/8.
Conditions required:
  • Target runs Express or uses proxy-addr directly
  • Trust proxy configured with IPv4-mapped IPv6 and wrong prefix length
  • Application is network-reachable
Where this breaks in practice:
  • Most Express apps use plain IPv4 notation, numeric hop count, or named presets
  • The IPv6-mapped form with /8 instead of /104 is a rare configuration pattern
  • No banner or error reveals whether the misconfiguration is present
Detection/coverage: No scanner currently fingerprints this specific misconfiguration remotely. SBOM/SCA tools (Snyk, Socket, npm audit) can flag the vulnerable proxy-addr version but cannot determine runtime trust-proxy configuration.
STEP 02

Craft spoofed X-Forwarded-For header

Because proxy-addr now trusts the attacker’s source IP as a valid proxy hop, the attacker sends an HTTP request with a forged X-Forwarded-For: <arbitrary-ip> header. The library walks the header chain, finds the attacker’s socket address in the trusted set, and returns the forged IP as req.ip. No authentication, credentials, or special tooling is required — curl -H 'X-Forwarded-For: 1.2.3.4' is sufficient.
Conditions required:
  • Step 1 conditions met
  • Attacker can send HTTP requests to the application
Where this breaks in practice:
  • A properly positioned WAF or reverse proxy that overwrites X-Forwarded-For before it reaches the app would strip the spoofed header
  • Applications that don’t use req.ip for security decisions are unaffected even if technically vulnerable
Detection/coverage: WAF logs showing unusual X-Forwarded-For patterns may indicate exploitation. Application-level logging comparing socket address to req.ip can detect discrepancies.
STEP 03

Bypass IP-based security controls

With req.ip now attacker-controlled, the spoofed address bypasses IP allowlists, rate limiters (e.g., express-rate-limit), geo-restriction middleware, and IP-based audit logging. The attacker can brute-force authentication endpoints past rate limits, access admin panels behind IP allowlists, or poison forensic trails. The blast radius is scoped to the individual application instance — not lateral to other hosts.
Conditions required:
  • Application relies on req.ip for security-relevant decisions
  • Rate limiting, IP allowlisting, or geo-fencing is in use
Where this breaks in practice:
  • Applications using session-based or token-based auth are not directly compromised by IP spoofing alone
  • MFA on sensitive endpoints limits the value of rate-limit bypass
  • Impact is per-application, not fleet-wide
Detection/coverage: Anomalous rate-limit counter resets, logins from impossible-travel IPs, or audit logs showing internal IPs from external sessions are detection signals.
03 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNo known exploitation. Not listed on CISA KEV. No campaigns or threat actor usage reported as of 2026-09-15.
Proof-of-ConceptTrivial to reproduce but no public PoC repo found. Exploitation requires only curl -H 'X-Forwarded-For: <spoofed>' against a misconfigured target. The barrier is identifying the misconfiguration, not crafting the exploit.
EPSS ScoreNot yet scored (disclosed 2026-09-15, same day). Expect moderate EPSS given network vector but conditional trigger.
KEV StatusNot listed. No CISA KEV entry as of 2026-09-15.
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N — 9.1 CRITICAL. Network-accessible, no privileges, no interaction. C:H and I:H reflect IP-spoof-driven control bypass. A:N because no denial of service.
Affected Versionsproxy-addr 1.1.0 through 2.0.7. Express 4.x and 5.x bundle proxy-addr as a dependency.
Fixed Versionproxy-addr 2.0.8 (released 2026-09-15). Node.js June 2026 security releases also backport the fix.
Installed Base / Exposureproxy-addr has ~50–80 million weekly npm downloads (Snyk, Socket). It is a transitive dependency of virtually every Express.js application. However, only apps using IPv4-mapped IPv6 trust notation with wrong prefix are exploitable.
Disclosure Date2026-09-15 (coordinated disclosure, same-day patch).
Reporterskagebunsher and kustundag (reporters); UlisesGascon (developer/maintainer).
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to HIGH (6.5/10)

The single most decisive factor driving the downgrade from CRITICAL to HIGH is the narrow trigger condition: exploitation requires the target application to have configured trust proxy using IPv4-mapped IPv6 notation with an incorrect IPv4-sized prefix, a pattern used by a small minority of the massive Express installed base. The impact ceiling of IP spoofing (not RCE) further compresses the real-world severity below the vendor’s 9.1 score.

HIGH Vulnerability mechanism and affected versions
MEDIUM Prevalence of IPv6-mapped trust configuration in production Express apps
LOW EPSS and exploitation probability (too early to score)

Why this verdict

  • Conditional misconfiguration narrows the population dramatically. The bug only fires when trust proxy is set using ::ffff: IPv4-mapped notation with an IPv4-sized prefix. The vast majority of Express apps use app.set('trust proxy', 1), plain IPv4 CIDR, or named presets like loopback. This is closer to AC:H than AC:L.
  • Impact ceiling is IP spoofing, not code execution. The attacker controls req.ip, which can bypass rate limiting, IP allowlists, and audit logging. This is serious but does not grant shell access, data exfiltration of arbitrary records, or lateral movement. C:H and I:H in the vector overstate the real-world blast radius.
  • Massive install base keeps this from dropping to MEDIUM. proxy-addr has 50–80M weekly downloads. Even if only 0.1–1% of apps use the vulnerable configuration, that’s tens of thousands of potentially affected services. The unauthenticated, zero-interaction attack vector means any exposed misconfigured app is immediately exploitable.
  • Role multiplier: proxy-addr is a library used across all application tiers, not a canonically high-value infrastructure component. In typical roles (web APIs, SPAs, microservices), IP spoofing’s blast radius is limited to the individual application (rate-limit bypass, log poisoning). In higher-value roles (API gateways enforcing IP allowlists for admin panels, authentication services using IP for risk scoring), the impact escalates to auth-bypass-adjacent outcomes but remains scoped to that service, not fleet-wide. No realistic chain leads to domain takeover, fleet compromise, or supply-chain pivot from this bug alone. The floor is HIGH, not CRITICAL.

Why not higher?

Promoting to CRITICAL would require either active exploitation (none observed), a universally triggered condition (the IPv6-mapped misconfiguration is niche), or an impact that reaches RCE, domain takeover, or fleet-scale compromise (IP spoofing alone does not). The vendor’s 9.1 assumes the worst-case configuration is the common case; real-world deployment data does not support that assumption.

Why not lower?

Dropping to MEDIUM would undercount the risk posed by the enormous installed base and the zero-auth, zero-interaction network vector. The silent failure mode (no error on misconfiguration) means affected apps have no indication they’re exposed. Any app that IS misconfigured is trivially exploitable, and the IP spoofing impact against rate limiters and allowlists is operationally significant.

05 · Compensating Control

What to do — in priority order.

  1. Audit trust proxy configuration across all Express apps — Search codebases for ::ffff: in trust proxy settings and for direct proxy-addr compile() calls using IPv6-mapped notation. Convert any such entries to plain IPv4 CIDR (e.g., 10.0.0.0/8) or use prefix lengths >= 97 for mapped addresses. This eliminates the vulnerability without upgrading. Target completion within the noisgate mitigation SLA of 30 days for HIGH.
  2. Upgrade proxy-addr to 2.0.8 — Run npm audit fix or explicitly install proxy-addr@^2.0.8. For Express apps, ensure the resolved proxy-addr version in package-lock.json is >= 2.0.8. Deploy within the noisgate remediation SLA of 180 days for HIGH.
  3. Ensure reverse proxy overwrites X-Forwarded-For — Configure your edge reverse proxy (nginx, HAProxy, Envoy, AWS ALB) to set (not append) the X-Forwarded-For header. This prevents clients from injecting arbitrary values regardless of proxy-addr’s trust logic. This is a defense-in-depth measure that should already be in place.
  4. Add req.ip anomaly detection — Log both the socket remote address and req.ip in application access logs. Alert on cases where req.ip is an internal/RFC1918 address but the socket address is external. This detects active exploitation attempts.
What doesn't work
  • WAF IP reputation rules — the spoofed IP in X-Forwarded-For is chosen by the attacker and can be any “clean” address, so reputation-based blocking won’t flag it.
  • Network-level ACLs on the application port — the attacker connects from their real IP (which may be allowed); the spoofing happens at the HTTP header layer, not the TCP layer.
  • Upgrading Express without checking proxy-addr — Express 4.x may pin an older proxy-addr. You must verify the resolved transitive dependency version, not just the Express version.
06 · Verification

Crowdsourced verification payload.

Run this script on each application host or in your CI pipeline against the project’s node_modules. It checks the installed proxy-addr version and optionally scans for IPv6-mapped trust configurations. Requires read access to the project directory. Example: bash check_proxyaddr.sh /app

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_proxyaddr.sh - Check for CVE-2026-90711 (proxy-addr < 2.0.8)
# Usage: bash check_proxyaddr.sh <project_root>
# Exit codes: 1=VULNERABLE, 0=PATCHED, 2=UNKNOWN

set -euo pipefail

PROJECT_DIR="${1:-.}"
VULN_VERSION_CEILING="2.0.8"
RESULT="UNKNOWN"

# Find proxy-addr package.json
PKG_JSON=$(find "$PROJECT_DIR" -path '*/proxy-addr/package.json' -not -path '*/node_modules/.cache/*' 2>/dev/null | head -1)

if [ -z "$PKG_JSON" ]; then
  echo "[UNKNOWN] proxy-addr not found in $PROJECT_DIR"
  exit 2
fi

# Extract version
VERSION=$(grep -o '"version": *"[^"]*"' "$PKG_JSON" | head -1 | grep -o '[0-9][0-9.]*')

if [ -z "$VERSION" ]; then
  echo "[UNKNOWN] Could not parse proxy-addr version from $PKG_JSON"
  exit 2
fi

echo "Found proxy-addr version: $VERSION at $PKG_JSON"

# Compare versions using sort -V
MIN_SAFE=$(printf '%s\n%s' "$VERSION" "$VULN_VERSION_CEILING" | sort -V | head -1)

if [ "$VERSION" = "$VULN_VERSION_CEILING" ] || [ "$MIN_SAFE" = "$VULN_VERSION_CEILING" ]; then
  RESULT="PATCHED"
else
  # Check if version >= 1.1.0 (affected range start)
  MIN_AFFECTED=$(printf '%s\n%s' "$VERSION" "1.1.0" | sort -V | head -1)
  if [ "$MIN_AFFECTED" = "1.1.0" ] || [ "$VERSION" = "1.1.0" ]; then
    RESULT="VULNERABLE"
  else
    RESULT="PATCHED"
  fi
fi

# Bonus: scan for IPv6-mapped trust config (the actual trigger)
echo ""
echo "--- Scanning for IPv6-mapped trust configurations ---"
MAPPED_HITS=$(grep -rn '::ffff:' "$PROJECT_DIR" --include='*.js' --include='*.ts' --include='*.json' 2>/dev/null | grep -iv node_modules/proxy-addr || true)
if [ -n "$MAPPED_HITS" ]; then
  echo "[WARNING] Found IPv4-mapped IPv6 references in application code:"
  echo "$MAPPED_HITS"
else
  echo "[OK] No IPv4-mapped IPv6 trust configurations found in app code."
fi

echo ""
echo "[$RESULT] proxy-addr $VERSION"
[ "$RESULT" = "VULNERABLE" ] && exit 1
[ "$RESULT" = "PATCHED" ] && exit 0
exit 2
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning plan: First, run a quick grep across your Express codebases for ::ffff: in trust proxy configurations — if you find none, your exposure to this CVE is effectively zero and you can treat the upgrade as routine hygiene within the noisgate remediation SLA of 180 days. If you DO find IPv6-mapped trust configs with IPv4-sized prefixes, rewrite them to plain IPv4 CIDR notation immediately (this is your compensating control, due within the noisgate mitigation SLA of 30 days). In parallel, upgrade proxy-addr to 2.0.8 across all projects via npm audit fix and lock the resolved version. Verify your edge reverse proxy *sets* (not appends) X-Forwarded-For as a defense-in-depth layer. There is no active exploitation or KEV listing, so this is a measured response, not a fire drill — but the silent-failure nature of the bug means you should confirm your configs this week rather than assuming you’re safe.

Sources

  1. proxy-addr 2.0.8 Release (GitHub)
  2. CVE-2026-90711 Detail (THREATINT)
  3. Node.js June 2026 Security Releases
  4. proxy-addr Security Analysis (Snyk)
  5. proxy-addr Security Analysis (Socket)
  6. HKCERT Node.js Multiple Vulnerabilities Advisory
  7. CWE-290: Authentication Bypass by Spoofing (MITRE)
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.