Advisory Summary
A critical authentication bypass vulnerability (CVSS 9.1) has been assigned to CVE-2026-14198, affecting the @fastify/middie middleware integration package for the Fastify web framework. The flaw allows attackers to bypass middleware-enforced security controls — including authentication, authorization, and rate-limiting — by exploiting a URL path decoding inconsistency between the middleware layer and Fastify's internal router.
| Attribute | Value |
|---|---|
| CVE ID | CVE-2026-14198 |
| CVSS v3.1 Score | 9.1 (Critical) |
| Attack Vector | Network (AV:N) |
| Attack Complexity | Low (AC:L) |
| Privileges Required | None (PR:N) |
| User Interaction | None (UI:N) |
| Package | @fastify/middie |
| Affected Versions | 9.1.0 – 9.3.2 |
| Fixed Version | 9.3.3+ |
| Published | 2026-07-01 |
Vulnerability Details
Root Cause: %2F Decoding Mismatch
@fastify/middie decodes the percent-encoded slash %2F inside URL path parameter values before matching middleware paths. Fastify's underlying router, however, preserves the encoding during route lookup. The result is a disagreement between the two layers about what the canonical request path is.
This creates a dangerous inconsistency:
Request URL: /api/admin%2Fusers
middie sees: /api/admin/users → matches middleware path /api/admin/*
→ middleware runs (e.g., auth check PASSES)
Fastify sees: /api/admin%2Fusers → does NOT match /api/admin/*
→ routes to different handler
→ handler runs WITHOUT middleware protection
An attacker who knows or guesses a protected route path can encode a slash as %2F in the URL to slip past middleware while still having their request handled by the target endpoint.
Impact
Any security-critical middleware registered with @fastify/middie is affected:
- Authentication middleware — unauthenticated requests reach protected endpoints
- Authorization middleware — role/permission checks bypassed entirely
- Rate limiting middleware — unauthenticated users bypass request throttling
- Input validation middleware — pre-processing skipped
- Audit/logging middleware — requests go unrecorded
Affected Configurations
Applications are vulnerable if all three conditions are met:
- Running
@fastify/middieversion 9.1.0 through 9.3.2 - Registering middleware that enforces security on path patterns (e.g.,
/api/*,/admin/*) - Handling routes whose paths contain parameters that could be expressed with a slash
Common vulnerable patterns:
// Vulnerable: auth middleware on /api/* can be bypassed
fastify.register(require('@fastify/middie'))
fastify.addHook('onRequest', async (req, reply) => {
// This auth check CAN BE BYPASSED via %2F encoding
if (req.url.startsWith('/api/')) {
await requireAuth(req, reply)
}
})
fastify.get('/api/users/:id', handler)
// Accessible unauthenticated via: GET /api/users%2F123Detection
Check Your Package Version
# Check installed version
npm list @fastify/middie
# Check package.json for affected version ranges
grep -r "@fastify/middie" package.json package-lock.jsonLog Review
Look for requests containing %2F in paths that should be protected:
# Nginx / reverse proxy logs
grep '%2F' /var/log/nginx/access.log | grep -E "/(api|admin|auth)/"
# Node.js application logs — check for unauthenticated access patterns
grep -E "403|401|bypass|unauthenticated" app.logTest for Vulnerability (Safe Testing Only)
# If /api/protected requires auth, this SHOULD return 401:
curl -v http://localhost:3000/api/protected
# On a VULNERABLE system, this may return 200 (bypass):
curl -v http://localhost:3000/api%2Fprotected
# Or with encoded path separators:
curl -v "http://localhost:3000/api/admin%2Fdashboard"Remediation
Immediate Fix: Upgrade @fastify/middie
# Upgrade to the patched version
npm install @fastify/middie@latest
# Verify
npm list @fastify/middie
# Should show 9.3.3 or higherWorkaround: Explicit Route-Level Hooks
If immediate upgrade is not possible, move security middleware from path-pattern matching to explicit route-level onRequest hooks:
// SAFER: Per-route hook — not affected by path decoding issues
fastify.get('/api/users/:id', {
onRequest: [requireAuth], // Auth enforced at route level
handler: async (req, reply) => {
return getUser(req.params.id)
}
})
// Or register preHandler hooks per route
fastify.addHook('preHandler', async (req, reply) => {
// Only runs after routing — path is already resolved
if (req.routerPath?.startsWith('/api/')) {
await requireAuth(req, reply)
}
})Note: Use req.routerPath (the matched route pattern) rather than req.url (the raw decoded URL) for security checks to avoid decoding ambiguities.
Defense in Depth
Even after patching, apply these hardening measures:
-
Normalize URLs at the reverse proxy — configure Nginx/Caddy to decode and re-encode URLs before forwarding:
# Normalize percent-encoded slashes location ~ %2F { return 400; } -
Reject
%2Fat the application boundary — if your application does not legitimately use encoded slashes in paths, block them explicitly. -
Add integration tests for auth bypass — test that
%2F-encoded variants of protected URLs return401/403.
Patch Verification
After upgrading, verify the fix is in place:
# Check version
node -e "console.log(require('@fastify/middie/package.json').version)"
# Run a quick functional test
# 1. Start your server
# 2. Send a request with %2F to a protected route
# 3. Confirm it returns 401/403, not 200
curl -v "http://localhost:3000/api/admin%2Fdashboard"
# Expected: HTTP/1.1 401 Unauthorized (or 403 Forbidden)