A bouncer who only checks the last ID in the stack and waves everyone through
CVE-2026-92087 is an authorization bypass in @fastify/auth versions 5.0.0 through 5.1.0. The plugin lets developers compose multiple auth strategies (e.g., "must have API key AND be admin") into a single route guard. When strategies are composed using nested AND groups under { relation: 'or', run: 'all' }, the engine evaluates them in an order-dependent way: if an earlier check in the AND group fails, its failure is silently dropped, and the group's result becomes the outcome of the *last* check only. An attacker who satisfies only the weakest credential — say a valid API key without admin privileges — gets authorized to resources that should require both. A mirror-image bypass exists when a top-level and relation contains a nested or group.
The vendor rates this HIGH at CVSS 8.1, which captures the network-reachable, low-privilege, high-impact nature of an auth bypass on paper. In practice, the score overstates risk for most enterprises. The bug only fires under a specific, non-default composition pattern (run: 'all' with nested array groups), affects a narrow two-minor-version window (5.0.0–5.1.0), lives in an npm package with roughly 43 direct dependents, and requires the attacker to already hold at least one valid credential. Most Fastify deployments either don't use @fastify/auth at all, or don't use the vulnerable nested-group pattern. A reassessment to MEDIUM better reflects the real exposure surface.
4 steps from start to impact.
Obtain a low-privilege credential
- Valid low-privilege credential for the target app
- Credential acquisition is a prerequisite chain step the attacker must already have completed
- Many apps use short-lived JWTs or rotate API keys, narrowing the window
Identify a route using the vulnerable composition pattern
@fastify/auth guard uses a nested AND group inside an OR composition with run: 'all' enabled. This is not the default configuration — developers must explicitly opt into nested arrays and the run: 'all' option. Without this specific pattern, the bypass does not trigger.- Target route uses
{ relation: 'or', run: 'all' }or{ relation: 'and' }with nested groups - @fastify/auth version 5.0.0–5.1.0
- This is a non-default, advanced composition pattern — most @fastify/auth users employ flat strategy lists
- The affected version window is only two minor releases wide
- No public tooling exists to fingerprint the auth composition pattern remotely
Send a request satisfying only the weakest check in the AND group
- Request carries the low-privilege credential that satisfies the final strategy in the nested group
- Attacker needs to know or guess the evaluation order of strategies in the AND group
- No public PoC or exploit tooling automates this
Access unauthorized resources
- Successful bypass from step 3
- Blast radius is limited to the routes using the vulnerable pattern, not the entire application
- No privilege escalation beyond the application tier is inherent
The supporting signals.
| In-the-wild exploitation | No evidence. Not listed on CISA KEV. No reports from threat intel vendors or ISACs as of 2026-09-17. |
|---|---|
| Proof-of-concept | None public. No PoC repos on GitHub. The advisory describes the trigger pattern but does not include weaponized code. Researcher: *Sengtocxoen* (reporter); fix by *UlisesGascon*, reviewed by *mcollina*. |
| EPSS | Not yet scored. CVE disclosed 2026-09-16; EPSS typically lags 1–3 days for new entries. Expected to land in the low percentiles given no public exploit and niche package. |
| KEV status | Not listed. No CISA KEV entry as of 2026-09-17. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N — Network-reachable, low complexity, but requires low-privilege auth. Scope unchanged, no availability impact. |
| Affected versions | @fastify/auth 5.0.0 – 5.1.0 (two minor releases). Versions < 5.0.0 (including the legacy fastify-auth package) are not affected. |
| Fixed version | @fastify/auth 5.1.1 — released 2026-09-16 by Matteo Collina. |
| Scanning / exposure | Minimal. npm reports ~43 direct dependents. @fastify/auth is a niche plugin within the Fastify ecosystem; Fastify itself has ~3–4M weekly downloads but the auth composition plugin is a fraction of that. No Shodan/Censys/GreyNoise signatures exist for this application-layer logic bug. |
| Disclosure date | 2026-09-16 (coordinated disclosure via GitHub Security Advisory GHSA-7h52-2rwr-m76r). |
| CWE | CWE-285 (Improper Authorization), CWE-697 (Incorrect Comparison) |
noisgate verdict.
The single most decisive factor is the compound narrowing of the reachable population: the bug requires a non-default, advanced composition pattern (run: 'all' with nested array groups) in a niche npm package with ~43 direct dependents, inside a two-minor-version window. Even among @fastify/auth users, only the subset using this specific pattern is vulnerable, making the real-world exposure population vanishingly small.
Why this verdict
- Authenticated access required (PR:L): The attacker must already hold a valid credential for the target application. This eliminates drive-by and mass-scan attack patterns and implies a prior compromise step or insider position.
- Non-default trigger pattern: The bypass only fires when developers use nested AND/OR array groups with
run: 'all'— an advanced configuration most @fastify/auth users never touch. This dramatically narrows the vulnerable subset of an already small population. - Tiny installed base: With ~43 direct npm dependents, @fastify/auth is a niche plugin. The fraction of those dependents running 5.0.0–5.1.0 AND using the vulnerable pattern is a rounding error at enterprise scale.
- Role multiplier:
@fastify/authis application-tier middleware for Node.js web services. It is *not* canonically deployed as an identity provider, domain controller, hypervisor, or other fleet-critical infrastructure. In its typical role (line-of-business API auth guard), a successful bypass yields access to that application's data — not lateral movement, domain compromise, or supply-chain pivot. In the rare case where a Fastify app serves as a custom identity gateway, the blast radius could reach tenant-level, but this represents a negligible fraction of the installed base. - No exploitation evidence: No KEV listing, no public PoC, no threat-intel reports of active campaigns. The bug is logic-based and requires application-specific knowledge to exploit.
Why not higher?
The vendor's HIGH/8.1 would be appropriate if @fastify/auth were widely deployed and the vulnerable pattern were the default configuration. Neither is true. The ~43-dependent installed base, the non-default trigger pattern, and the PR:L requirement compound to reduce the reachable population well below the threshold where HIGH is warranted. No active exploitation or public PoC exists to counterbalance these friction points.
Why not lower?
Despite the narrow exposure, this is still a genuine authorization bypass that is network-reachable with low complexity once the preconditions are met. An attacker with a valid low-privilege credential and knowledge of the composition pattern can escalate privileges within the application without user interaction. The impact on confidentiality and integrity is real for affected deployments, preventing a LOW or IGNORE rating.
What to do — in priority order.
- Remove
run: 'all'from auth compositions — The bypass only triggers whenrun: 'all'is used with nested array groups. Removing this option causes@fastify/authto short-circuit on the first passing (or) / failing (and) strategy, which is both safer and faster. Apply within the 365-day noisgate remediation SLA window, or immediately if you cannot upgrade. - Flatten nested strategy groups — Replace nested AND/OR arrays with explicit top-level compositions. Instead of
[[checkAdmin, checkApiKey]]inside an OR, create a dedicated composed function that performs both checks sequentially with explicit error propagation. This eliminates the order-dependent evaluation entirely. - Reorder AND groups so the strictest check is last — As a stopgap if you cannot refactor, move the most restrictive strategy (e.g., role check) to the final position in each nested AND group. The bug causes only the last result to survive, so placing the strictest check last preserves the intended gate. This is fragile and should be treated as a temporary measure.
- Add application-layer audit logging on auth decisions — Log which strategies passed and failed for each request. This provides detection coverage for bypass attempts and validates that your compensating controls are working. Review logs weekly until the patch is deployed.
- WAF rules — This is an application-logic bug in auth composition evaluation order. No HTTP request signature distinguishes a bypass attempt from a legitimate authenticated request. WAFs cannot detect or block it.
- Rate limiting — The attacker needs only a single well-crafted request per resource. Rate limiting does not address authorization logic flaws.
- Network segmentation — The bug is in the application layer. Restricting network access helps if you can limit who reaches the Fastify service, but any authenticated user on an allowed network can still trigger the bypass.
Crowdsourced verification payload.
Run this on any machine with npm or yarn available, from the root of your Node.js project directory. No special privileges required. Example: bash check_fastify_auth.sh /path/to/your/project
#!/usr/bin/env bash
# check_fastify_auth.sh — CVE-2026-92087 detector for @fastify/auth
# Usage: bash check_fastify_auth.sh [/path/to/project]
# Exit codes: 0 = PATCHED/not present, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
PROJECT_DIR="${1:-.}"
if [ ! -d "$PROJECT_DIR" ]; then
echo "UNKNOWN — directory $PROJECT_DIR does not exist"
exit 2
fi
cd "$PROJECT_DIR"
# Check if @fastify/auth is installed
if [ ! -d "node_modules/@fastify/auth" ]; then
echo "PATCHED — @fastify/auth is not installed in this project"
exit 0
fi
# Get installed version from package.json
VERSION=$(node -e "try { console.log(require('./node_modules/@fastify/auth/package.json').version) } catch(e) { console.log('unknown') }" 2>/dev/null)
if [ "$VERSION" = "unknown" ]; then
echo "UNKNOWN — could not determine @fastify/auth version"
exit 2
fi
echo "Detected @fastify/auth version: $VERSION"
# Parse major.minor.patch
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
# Affected: >= 5.0.0 and < 5.1.1
if [ "$MAJOR" -eq 5 ]; then
if [ "$MINOR" -eq 0 ]; then
echo "VULNERABLE — @fastify/auth $VERSION is in the affected range (5.0.0–5.1.0). Upgrade to 5.1.1+"
exit 1
elif [ "$MINOR" -eq 1 ] && [ "$PATCH" -eq 0 ]; then
echo "VULNERABLE — @fastify/auth $VERSION is in the affected range (5.0.0–5.1.0). Upgrade to 5.1.1+"
exit 1
elif [ "$MINOR" -eq 1 ] && [ "$PATCH" -ge 1 ]; then
echo "PATCHED — @fastify/auth $VERSION is fixed"
exit 0
else
echo "PATCHED — @fastify/auth $VERSION is above the affected range"
exit 0
fi
else
echo "PATCHED — @fastify/auth $VERSION is outside the affected major version (5.x)"
exit 0
fiIf you remember one thing.
@fastify/auth 5.0.0–5.1.0, check whether any route guards use nested AND/OR arrays with run: 'all'. If they do, you have two immediate options: remove run: 'all' or reorder the nested group so the strictest check is last. For the actual fix, run npm install @fastify/[email protected]. At a reassessed MEDIUM, there is no noisgate mitigation SLA — go straight to the 365-day noisgate remediation SLA window for applying the patch. That said, the fix is a one-line dependency bump with no breaking changes, so there is no reason to wait — roll it into your next scheduled dependency update cycle. If you discover this package is guarding a high-value service (e.g., an internal identity gateway or admin API), treat it with urgency regardless of the MEDIUM rating and patch within the current sprint.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.