Skip to content

🚨 [security] Update @fastify/middie 8.3.0 → 9.2.0 (major) - #596

Closed
depfu[bot] wants to merge 1 commit into
mainfrom
depfu/update/pnpm/@fastify/middie-9.2.0
Closed

depfu[bot] wants to merge 1 commit into
mainfrom
depfu/update/pnpm/@fastify/middie-9.2.0

Conversation

@depfu

@depfu depfu Bot commented Feb 28, 2026

Copy link
Copy Markdown
Contributor

🚨 Your current dependencies have known security vulnerabilities 🚨

This dependency update fixes known security vulnerabilities. Please see the details below and assess their impact carefully. We recommend to merge and deploy this as soon as possible!


Here is everything you need to know about this upgrade. Please take a good look at what changed and the test results before merging this pull request.

What changed?

✳️ @​fastify/middie (8.3.0 → 9.2.0) · Repo

Security Advisories 🚨

🚨 @fastify/middie has Improper Path Normalization when Using Path-Scoped Middleware

Summary

A path normalization inconsistency in @fastify/middie can result in authentication/authorization bypass when using path-scoped middleware (for example, app.use('/secret', auth)).

When Fastify router normalization options are enabled (such as ignoreDuplicateSlashes, useSemicolonDelimiter, and related trailing-slash behavior), crafted request paths may bypass middleware checks while still being routed to protected handlers.

Impact

An unauthenticated remote attacker can access endpoints intended to be protected by middleware-based auth/authorization controls by sending specially crafted URL paths (for example, //secret or /secret;foo=bar), depending on router option configuration.

This may lead to unauthorized access to protected functionality and data exposure.

Affected versions

  • Confirmed affected: @fastify/middie@9.1.0
  • All versions prior to the patch are affected.

Patched versions

  • Fixed in: 9.2.0

Details

The issue is caused by canonicalization drift between:

  1. @fastify/middie path matching for app.use('/prefix', ...), and
  2. Fastify/find-my-way route lookup normalization.

Because middleware and router did not always evaluate the same normalized path, auth middleware could be skipped while route resolution still succeeded.

Workarounds

Until patched version is deployed:

  • Avoid relying solely on path-scoped middie guards for auth/authorization.
  • Enforce auth at route-level handlers/hooks after router normalization.
  • Disable risky normalization combinations only if operationally feasible.

Resources

Credits

  • Cristian Vargas (Fluid Attacks Research Team) — discovery and report.
  • Oscar Uribe (Fluid Attacks) — coordination and disclosure.

🚨 Fastify Middie Middleware Path Bypass

Summary

A security vulnerability exists in @fastify/middie where middleware registered with a specific path prefix can be bypassed using URL-encoded characters (e.g., /%61dmin instead of /admin). While the middleware engine fails to match the encoded path and skips execution, the underlying Fastify router correctly decodes the path and matches the route handler, allowing attackers to access protected endpoints without the middleware constraints.

Details

The vulnerability is caused by how middie matches requests against registered middleware paths.

  1. Regex Generation: When fastify.use('/admin', ...) is called, middie uses path-to-regexp to generate a regular expression for the path /admin.
  2. Request Matching: For every request, middie executes this regular expression against req.url (or req.originalUrl).
  3. The Flaw: req.url in Fastify contains the raw, undecoded path string.
    • The generated regex expects a decoded path (e.g., /admin).
    • If a request is sent to /%61dmin, the regex comparison fails (/^\/admin/ does not match /%61dmin).
    • middie assumes the middleware does not apply and calls next().
  4. Route Execution: The request proceeds to Fastify's internal router, which performs URL decoding. It correctly identifies /%61dmin as /admin and executes the corresponding route handler.

Incriminated Source Code:
In the provided middie source:

// ... inside Holder function
if (regexp) {
  const result = regexp.exec(url) // <--- 'url' is undecoded.
  if (result) {
    // ... executes middleware ...
  } else {
    that.done() // <--- Middleware skipped on mismatch
  }
}

PoC

Step 1: Run the following Fastify application (save as app.js):

const fastify = require('fastify')({ logger: true });

async function start() {
// Register middie for Express-style middleware support
await fastify.register(require('@fastify/middie'));

// Middleware to block /admin route
fastify.use('/admin', (req, res, next) => {
res.statusCode = 403;
res.end('Forbidden: Access to /admin is blocked');
});

// Sample routes
fastify.get('/', async (request, reply) => {
return { message: 'Welcome to the homepage' };
});

fastify.get('/admin', async (request, reply) => {
return { message: 'Admin panel' };
});

// Start server
try {
await fastify.listen({ port: 3008 });
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
}

start();

Step 2: Execute the attack.

  1. Normal Request (Blocked):
    curl http://localhost:3008/admin
    # Output: Forbidden: Access to /admin is blocked
  2. Bypass Request (Successful):
    curl http://localhost:3008/%61dmin
    # Output: {"message":"Admin panel"}

Impact

  • Type: Authentication/Authorization Bypass.
  • Affected Components: Applications using @fastify/middie to apply security controls (auth, rate limiting, IP filtering) to specific route prefixes.
  • Severity: High. Attackers can trivially bypass critical security middleware to access protected administrative or sensitive endpoints.
Release Notes

9.1.0

What's Changed

New Contributors

Full Changelog: v9.0.3...v9.1.0

9.0.3

What's Changed

  • build(deps-dev): bump helmet from 7.2.0 to 8.0.0 by @dependabot in #217
  • refactor(lib/engine): replace var with let by @Fdawgs in #218
  • build(deps): bump fastify/workflows from 5.0.0 to 5.0.1 by @dependabot in #219
  • style: remove trailing whitespace by @Fdawgs in #220
  • docs(readme): update ci badge syntax by @Fdawgs in #221
  • build(deps-dev): replace standard with neostandard by @Fdawgs in #222
  • types: use node: prefix for builtins by @Fdawgs in #223
  • build(deps-dev): bump neostandard from 0.11.9 to 0.12.0 by @dependabot in #224
  • build(deps-dev): add eslint, peer dep of neostandard by @Fdawgs in #225
  • refactor: prefix unused params with underscores by @Fdawgs in #226
  • docs(readme): spelling and grammar fixes by @Fdawgs in #227

Full Changelog: v9.0.2...v9.0.3

9.0.2

What's Changed

Full Changelog: v9.0.1...v9.0.2

9.0.1

Security

  • path-to-regexp is updated to 8.1.0 to prevent ReDOS attack, it is recommended to use the latest version of this package.

What's Changed

Full Changelog: v9.0.0...v9.0.1

8.3.3

Security

  • path-to-regexp is updated to 6.3.0 to prevent ReDOS attack, it is recommended to use the latest version of this package.

What's Changed

Full Changelog: v8.3.2...v8.3.3

8.3.2

Deprecated

This version includes too much breaking change due to security patch. Please upgrade to version 8.3.3 which includes the security patch with minimal breakages.

Security

  • path-to-regexp is updated to 8.1.0 to prevent ReDOS attack, it is recommended to use the latest version of this package.

You may see some unexpected breaking due the security patch. Here is the workaround,

  1. when you are using wildcard *, you must to provides a param name.
// before
fastify.use('*.css')
// after
fastify.use('*filename{.css}')

What's Changed

Full Changelog: v8.3.1...v8.3.2

8.3.1

What's Changed

  • build(deps-dev): bump tsd from 0.28.1 to 0.29.0 by @dependabot in #189
  • perf: use node: prefix to bypass require.cache call for builtins by @Fdawgs in #190
  • chore: add .gitattributes file by @Fdawgs in #192
  • chore(package): explicitly declare js module type by @Fdawgs in #193
  • build(deps-dev): bump tsd from 0.29.0 to 0.30.0 by @dependabot in #194
  • docs(readme): replace fastify.io links with fastify.dev by @Fdawgs in #195
  • docs(readme): remove www. from fastify.dev urls by @Fdawgs in #196
  • chore(.gitignore): add .tap/ dir by @Fdawgs in #197
  • build(deps-dev): bump tsd from 0.30.7 to 0.31.0 by @dependabot in #198
  • Warn for possible ReDoS by @mcollina in #200
  • Only sets req.raw.body if body defined, aligning behaviour with node:http by @didley in #201

New Contributors

Full Changelog: v8.3.0...v8.3.1

Does any of this look wrong? Please let us know.

Commits

See the full diff on Github. The new version differs by 61 commits:


Depfu Status

Depfu will automatically keep this PR conflict-free, as long as you don't add any commits to this branch yourself. You can also trigger a rebase manually by commenting with @depfu rebase.

All Depfu comment commands
@​depfu rebase
Rebases against your default branch and redoes this update
@​depfu recreate
Recreates this PR, overwriting any edits that you've made to it
@​depfu merge
Merges this PR once your tests are passing and conflicts are resolved
@​depfu cancel merge
Cancels automatic merging of this PR
@​depfu close
Closes this PR and deletes the branch
@​depfu reopen
Restores the branch and reopens this PR (if it's closed)
@​depfu pause
Ignores all future updates for this dependency and closes this PR
@​depfu pause [minor|major]
Ignores all future minor/major updates for this dependency and closes this PR
@​depfu resume
Future versions of this dependency will create PRs again (leaves this PR as is)

@depfu

depfu Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor Author

Closed in favor of #604.

@depfu depfu Bot closed this Apr 17, 2026
@depfu
depfu Bot deleted the depfu/update/pnpm/@fastify/middie-9.2.0 branch April 17, 2026 01:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants