Someone handed out unlimited arcade tokens by wearing a different hat each visit
CVE-2026-15144 affects @fastify/rate-limit versions prior to 11.2.0. The plugin's default keyGenerator uses the verbatim string from request.ip as the rate-limit bucket key. This creates two bypass vectors: (1) IPv6 prefix rotation — a standard residential or cloud IPv6 allocation gives an attacker a /64 block containing 2^64 unique addresses, each minting a fresh rate-limit bucket; and (2) representation aliasing — the same IPv6 address can be expressed in compressed (::1), expanded (0000:0000:…:0001), mixed-case, or IPv4-mapped (::ffff:10.0.0.1) forms, each treated as a distinct key. The fix in 11.2.0 introduces a normalizeIP() function and a configurable ipv6Subnet option (default /64) that canonicalizes addresses before keying. All applications using @fastify/rate-limit <11.2.0 behind IPv6-capable proxies (Cloudflare, AWS ALB, GCP LB, Vercel, Fly.io, Render, Railway) are in scope.
The vendor's HIGH 7.3 rating overweights the theoretical ceiling. The CVSS vector itself (C:L/I:L/A:L) correctly rates every impact dimension as *Low* — the 7.3 is inflated by the ease-of-reach metrics (network-accessible, no auth, no interaction). In practice, this vulnerability weakens a defense-in-depth control rather than directly achieving compromise. An attacker who bypasses the rate limit still needs to chain it with brute-force, credential stuffing, or volumetric abuse against an endpoint that *also* lacks MFA, account lockout, or CAPTCHA. Most enterprise-grade deployments of Fastify behind WAFs or API gateways already enforce rate limits upstream of the application layer, further reducing real-world exposure. A MEDIUM reassessment better reflects the actual blast radius.
5 steps from start to impact.
Identify IPv6-exposed Fastify service
@fastify/rate-limit protecting a security-sensitive endpoint (login, OTP, password reset). The attacker confirms IPv6 connectivity by resolving the target's AAAA record or observing X-Forwarded-For headers passed by the reverse proxy.- Target application uses @fastify/rate-limit <11.2.0
- Target accepts IPv6 connections or sits behind a dual-stack proxy
- Many enterprise API deployments are IPv4-only behind internal load balancers
- Some WAFs and CDNs normalize or strip IPv6 before it reaches the Fastify app
Acquire routable IPv6 prefix
/64 or larger IPv6 prefix. Cloud VPS providers (Vultr, Hetzner, OVH) routinely assign /64 or /48 blocks. Residential ISPs also allocate /56 or /48 by default. Tools like freebind (github.com/blechschmidt/freebind) hook into socket calls via LD_PRELOAD and bind each outgoing connection to a random address within the prefix.- Attacker controls a machine with a routed IPv6 prefix
- Linux with AnyIP configured:
ip -6 route add local <prefix> dev lo
- Requires a VPS or ISP that delegates a prefix — commodity but not zero-cost
- freebind requires Linux; no native Windows/macOS equivalent
Rotate source IPs to evade per-IP rate limit
@fastify/rate-limit keys on the verbatim request.ip string, every request creates a new bucket and is never throttled. Alternatively, the attacker can send the same IPv4-mapped IPv6 address in different textual representations (::ffff:10.0.0.1 vs 0:0:0:0:0:ffff:a00:1) to bypass the limit even without a large prefix.- Step 2 completed
- Application does not normalize IPs upstream of the rate limiter
- Upstream WAFs or API gateways (Cloudflare, AWS WAF, Akamai) often enforce their own rate limits before traffic reaches Fastify
- CDNs that canonicalize the
X-Forwarded-Forheader eliminate the representation-aliasing vector
Execute brute-force or credential-stuffing attack
- Rate limit successfully bypassed
- Target endpoint lacks secondary brute-force defenses
- MFA blocks credential stuffing even if rate limit is bypassed
- Account lockout policies (e.g., 5-strike lockout) are independent of rate limiting
- CAPTCHA or proof-of-work challenges add per-request cost the attacker cannot avoid
Account compromise or service degradation
- Step 4 succeeds against an account without MFA or lockout
- Blast radius is limited to individual accounts, not infrastructure
- No privilege escalation, lateral movement, or persistence is inherent to this vuln
The supporting signals.
| In-the-Wild Exploitation | No known exploitation. Not listed on CISA KEV. No campaign reports. The IPv6 rotation technique is well-documented generically (HackerOne report #1154003, HackTricks rate-limit-bypass page) but no targeted exploitation of this specific CVE has been observed. |
|---|---|
| Proof-of-Concept | No CVE-specific PoC published. However, the attack is trivial to reproduce using freebind (Linux LD_PRELOAD tool for per-socket IPv6 rotation) plus curl or any HTTP client. The representation-aliasing vector requires only header manipulation. Researcher/reporter: mcollina (Matteo Collina, Fastify core maintainer). |
| EPSS Score | Not yet scored — CVE was disclosed 2026-07-29 (yesterday). FIRST EPSS data typically populates within 7–14 days of NVD publication. |
| KEV Status | Not listed. No CISA KEV entry as of 2026-07-30. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L → 7.3 HIGH. All three CIA impacts are *Low*. The score is driven entirely by the attack-reach metrics (Network, Low complexity, No privileges, No interaction). The unchanged scope is correct — the vuln affects only the rate-limiter's own security function. |
| Affected Versions | All versions of @fastify/rate-limit prior to 11.2.0. This includes the legacy fastify-rate-limit package (pre-scoped npm name). |
| Fixed Version | @fastify/rate-limit 11.2.0 (released 2026-07-29). Introduces normalizeIP() canonicalization and configurable ipv6Subnet option (default /64). No distro backports apply — this is a pure npm package. |
| Exposure / Install Base | ~812,000 weekly npm downloads. Fastify is the second-most-popular Node.js framework after Express. No Shodan/Censys fingerprint exists for this specific middleware — exposure must be inferred from npm telemetry and dependency graphs. |
| Disclosure Date | 2026-07-29 — advisory published by Matteo Collina (mcollina) via GitHub Security Advisories (GHSA-grpc-p53c-r64v). |
| Related CVEs | CVE-2026-30827 (express-rate-limit IPv4-mapped IPv6 bypass, similar class). CVE-2026-29794 (Vikunja rate-limit bypass via spoofed headers). This is part of a 2026 wave of IPv6-aware rate-limit fixes across the Node.js ecosystem. |
noisgate verdict.
This vulnerability only weakens a defense-in-depth rate-limiting control — it does not independently achieve compromise, data access, or code execution; the attacker must still chain it with brute-force against an endpoint that *also* lacks MFA, account lockout, or CAPTCHA. The single most decisive downgrade factor is blast radius limited to individual accounts on endpoints missing secondary brute-force defenses, which narrows real-world impact well below the vendor's HIGH threshold.
Why this verdict
- Defense-in-depth weakening, not direct compromise: The vulnerability disables one layer (rate limiting) but leaves MFA, account lockout, CAPTCHA, and upstream WAF rate limits intact. An attacker who bypasses the Fastify rate limiter has *permission to try harder* — not permission to succeed.
- IPv6 connectivity is a prerequisite that narrows exposure: Many enterprise API deployments sit behind IPv4-only internal load balancers or CDNs that canonicalize addresses upstream. The attack requires the attacker to have a routable IPv6 prefix *and* for the target to pass raw IPv6 through to Fastify — a conjunction that excludes a significant fraction of deployments.
- Vendor's own CIA ratings are all Low: The CVSS vector explicitly rates confidentiality, integrity, and availability impact as Low. The 7.3 score is inflated by the frictionless attack-reach metrics (AV:N/AC:L/PR:N/UI:N). In a friction-adjusted model, the Low/Low/Low impact ceiling pulls the real-world severity into MEDIUM territory.
- Role multiplier: @fastify/rate-limit is application-tier middleware deployed in Node.js web servers and API services. It is *not* a canonical high-value-role component (not a domain controller, hypervisor, identity provider, backup agent, PKI, or network edge appliance). A small fraction of Fastify apps serve as custom identity providers where rate limiting on login is security-critical, but even in that worst case the blast radius is account-level compromise — not fleet-scale, domain-scale, or supply-chain-scale. No high-value-role floor override applies.
- No exploitation evidence or weaponized tooling specific to this CVE: While the generic IPv6 rotation technique is commodity knowledge, no threat actor has been observed targeting @fastify/rate-limit specifically. The 48-hour-old disclosure has produced no PoC repos or scanner plugins yet.
Why not higher?
The vendor's HIGH (7.3) would be appropriate if bypassing the rate limit *directly* achieved compromise — but it doesn't. The CIA impact is Low/Low/Low by the vendor's own vector. The vulnerability is a prerequisite-weakener that must be chained with brute-force against an endpoint that also lacks MFA, lockout, and CAPTCHA. Enterprise deployments typically have upstream WAF or CDN rate limits that operate independently of the Fastify middleware, further reducing the population where this vulnerability is the sole defense.
Why not lower?
A LOW or IGNORE rating would underweight the 812K weekly download footprint and the fact that the attack is unauthenticated, remotely exploitable, and requires zero user interaction. Some Fastify applications *do* rely on @fastify/rate-limit as their primary brute-force defense on login endpoints — particularly smaller teams that haven't implemented MFA or account lockout. For those deployments, this bypass is operationally significant. The fix is also trivial (npm update), so there's no reason to deprioritize it into backlog-only status.
What to do — in priority order.
- Enforce MFA on all authentication endpoints — MFA renders brute-force attacks ineffective regardless of rate-limit status. If your Fastify login endpoints lack MFA, this is your highest-priority compensating control — deploy it within the 365-day noisgate remediation window, ideally much sooner.
- Implement account lockout or progressive delays — Lock accounts after N failed attempts (e.g., 5 failures → 15-minute lockout). This operates independently of IP-based rate limiting and stops credential stuffing even if the rate limiter is bypassed.
- Add CAPTCHA or proof-of-work on sensitive endpoints — reCAPTCHA v3, hCaptcha, or Turnstile on login/OTP/reset endpoints impose per-request cost that IPv6 rotation cannot circumvent.
- Apply upstream rate limiting at CDN/WAF/API gateway — Cloudflare Rate Limiting, AWS WAF rate-based rules, or NGINX
limit_reqwith IPv6 subnet awareness (/64bucketing) will throttle traffic before it reaches Fastify. Configure your edge to normalize and subnet-mask IPv6 addresses. - Pin a custom keyGenerator until you can upgrade — If you cannot immediately bump to 11.2.0, set a custom
keyGeneratorthat normalizes IPs:keyGenerator: (req) => require('net').isIPv6(req.ip) ? req.ip.replace(/:.*/,'') : req.ipas a rough /16 mask. This is a stopgap — upgrade is the real fix.
- IP reputation blocklists — the attacker uses fresh, never-seen-before IPv6 addresses from a legitimately allocated prefix; reputation databases will not flag them.
- Connection-level rate limiting (iptables/nftables per-IP) — the attacker rotates source IPs at Layer 3, so per-IP kernel-level limits face the same bypass unless configured with
/64prefix matching viaipsetornftsets. - TLS client certificate pinning — while it eliminates anonymous access, it doesn't help if the attacker has a valid client cert (e.g., in mTLS API deployments where certs are issued per-org, not per-device).
Crowdsourced verification payload.
Run this on any machine with node and npm installed (no root required). It checks the installed version of @fastify/rate-limit in the current project directory. Example: cd /path/to/your/fastify-app && bash check_cve_2026_15144.sh
#!/usr/bin/env bash
# check_cve_2026_15144.sh
# Checks whether @fastify/rate-limit is vulnerable to CVE-2026-15144
# (IPv6 rate-limit bypass via address rotation / representation aliasing)
# Fixed in: @fastify/rate-limit >= 11.2.0
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
PKG="@fastify/rate-limit"
FIXED="11.2.0"
# Try to find installed version
if command -v npm &>/dev/null; then
VERSION=$(npm ls "$PKG" --json 2>/dev/null | node -e "
const j = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
function find(obj) {
if (!obj) return null;
if (obj.dependencies && obj.dependencies['$PKG']) return obj.dependencies['$PKG'].version;
if (obj.dependencies) for (const k of Object.keys(obj.dependencies)) { const r = find(obj.dependencies[k]); if (r) return r; }
return null;
}
const v = find(j);
if (v) process.stdout.write(v); else process.exit(1);
" 2>/dev/null) || true
fi
if [ -z "${VERSION:-}" ]; then
# Fallback: check package-lock.json or node_modules directly
if [ -f node_modules/@fastify/rate-limit/package.json ]; then
VERSION=$(node -e "console.log(require('./node_modules/@fastify/rate-limit/package.json').version)" 2>/dev/null) || true
fi
fi
if [ -z "${VERSION:-}" ]; then
echo "UNKNOWN — $PKG not found in this project"
exit 2
fi
# Compare versions using node's semver-compatible comparison
RESULT=$(node -e "
const v = '$VERSION'.split('.').map(Number);
const f = '$FIXED'.split('.').map(Number);
for (let i = 0; i < 3; i++) {
if (v[i] < f[i]) { console.log('VULNERABLE'); process.exit(0); }
if (v[i] > f[i]) { console.log('PATCHED'); process.exit(0); }
}
console.log('PATCHED');
" 2>/dev/null)
if [ "$RESULT" = "VULNERABLE" ]; then
echo "VULNERABLE — $PKG $VERSION is below fixed version $FIXED (CVE-2026-15144)"
exit 1
elif [ "$RESULT" = "PATCHED" ]; then
echo "PATCHED — $PKG $VERSION >= $FIXED"
exit 0
else
echo "UNKNOWN — could not compare versions"
exit 2
fiIf you remember one thing.
@fastify/rate-limit — it weakens a defense layer but doesn't independently achieve compromise. There is no noisgate mitigation SLA for MEDIUM — go straight to the 365-day noisgate remediation SLA. That said, the fix is a one-line npm update @fastify/rate-limit to 11.2.0, so there's no reason to wait: queue it into your next scheduled dependency update cycle. If your Fastify applications protect authentication or OTP endpoints *without* MFA or account lockout, prioritize those apps first and confirm upstream WAF/CDN rate limits are active as a compensating control in the interim. For the other 90% of deployments where rate limiting is a convenience throttle rather than a security gate, treat this as routine dependency hygiene within your normal sprint cadence.Sources
- GitHub Security Advisory GHSA-grpc-p53c-r64v
- @fastify/rate-limit Releases (v11.2.0)
- @fastify/rate-limit README — keyGenerator and ipv6Subnet docs
- freebind — IPv6 address rotation evasion tool
- OneUptime — How to Handle IPv6 in Rate Limiting Middleware
- CVE-2026-30827 — express-rate-limit IPv6 bypass (related class)
- HackTricks — Rate Limit Bypass Techniques
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.