The vulnerability is a Time-of-check Time-of-use (TOCTOU) issue caused by inconsistent URL decoding between the NestJS middleware layer and the underlying Fastify router. The root cause is that the middleware matching logic did not decode URL-encoded characters in the request path before checking if a middleware should be applied.
An attacker could send a request with a URL-encoded path, such as /%61dmin.
-
Time-of-check: The middleware dispatcher (originally in @fastify/middie, and also in FastifyAdapter.use) would compare the path pattern (e.g., /admin) against the raw path (/%61dmin). The match would fail, and the security middleware (e.g., for authentication/authorization) would be skipped.
-
Time-of-use: The request would then be passed to the Fastify router, which would decode the path to /admin. The router would find the corresponding controller for /admin and execute it, but without the security checks from the skipped middleware.
The patch addresses this by introducing URL decoding at the point of the middleware path check. The commit c4cedda15a05aafec1e6045b36b0335ab850e771 implements two main fixes:
- It replaces the external
@fastify/middie package with a patched, internal version (packages/platform-fastify/adapters/middie/fastify-middie.ts). Inside this new file, the runMiddie function and its internal logic now use safeDecodeURI on the request URL before performing the regex match to determine if a middleware should run.
- It also modifies
FastifyAdapter.use to decode the pathname using safeDecodeURI for middleware applied directly with app.use().
The identified vulnerable functions, FastifyAdapter.use and the logic now within runMiddie, were the points where the vulnerable 'check' occurred.