VYPR
Moderate severityOSV Advisory· Published Dec 29, 2025· Updated Dec 29, 2025

Nest has a Fastify URL Encoding Middleware Bypass (TOCTOU)

CVE-2025-69211

Description

Nest is a framework for building scalable Node.js server-side applications. Versions prior to 11.1.11 have a Fastify URL encoding middleware bypass. A NestJS application is vulnerable if it uses @nestjs/platform-fastify; relies on NestMiddleware (via MiddlewareConsumer) for security checks (authentication, authorization, etc.), or through app.use(); and applies middleware to specific routes using string paths or controllers (e.g., .forRoutes('admin')). Exploitation can result in unauthenticated users accessing protected routes, restricted administrative endpoints becoming accessible to lower-privileged users, and/or middleware performing sanitization or validation being skipped. This issue is patched in @nestjs/platform-fastify@11.1.11.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@nestjs/platform-fastifynpm
< 11.1.1111.1.11

Affected products

1

Patches

1
c4cedda15a05

fix(platform-fastify): middie bypassing through decoded chars

https://github.com/nestjs/nestKamil MyśliwiecDec 29, 2025via ghsa
6 files changed · +419 765
  • integration/hello-world/e2e/middleware-fastify.spec.ts+9 0 modified
    @@ -208,6 +208,15 @@ describe('Middleware (FastifyAdapter)', () => {
             .then(({ payload }) => expect(payload).to.be.eql(INCLUDED_VALUE));
         });
     
    +    it(`GET forRoutes(POST /tests/%69ncluded) - ensure middleware is executed correctly with encoded characters`, () => {
    +      return app
    +        .inject({
    +          method: 'POST',
    +          url: '/tests/%69ncluded', // 'i' character is encoded
    +        })
    +        .then(({ payload }) => expect(payload).to.be.eql(INCLUDED_VALUE));
    +    });
    +
         afterEach(async () => {
           await app.close();
         });
    
  • package.json+3 0 modified
    @@ -138,6 +138,8 @@
         "eventsource": "4.1.0",
         "fancy-log": "2.0.0",
         "fastify": "5.6.2",
    +    "fastify-plugin": "5.1.0",
    +    "find-my-way": "9.3.0",
         "globals": "16.5.0",
         "graphql": "16.12.0",
         "graphql-subscriptions": "3.0.0",
    @@ -169,6 +171,7 @@
         "nyc": "14.1.1",
         "prettier": "^3.7.4",
         "redis": "5.10.0",
    +    "reusify": "1.1.0",
         "rxjs-compat": "6.6.7",
         "sinon": "21.0.1",
         "sinon-chai": "4.0.1",
    
  • package-lock.json+36 760 modified
    @@ -89,6 +89,8 @@
             "eventsource": "4.1.0",
             "fancy-log": "2.0.0",
             "fastify": "5.6.2",
    +        "fastify-plugin": "5.1.0",
    +        "find-my-way": "9.3.0",
             "globals": "16.5.0",
             "graphql": "16.12.0",
             "graphql-subscriptions": "3.0.0",
    @@ -120,6 +122,7 @@
             "nyc": "14.1.1",
             "prettier": "^3.7.4",
             "redis": "5.10.0",
    +        "reusify": "1.1.0",
             "rxjs-compat": "6.6.7",
             "sinon": "21.0.1",
             "sinon-chai": "4.0.1",
    @@ -226,7 +229,6 @@
           "integrity": "sha512-OEAl5bwVitkvVkmZlgWksSnQ10FUr6q2qJMdkexs83lsvOGmd/y81X5LoETmKZux8UiQsy/A/xzP00b8hTHH/w==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "@apollo/cache-control-types": "^1.0.3",
             "@apollo/server-gateway-interface": "^2.0.0",
    @@ -10397,28 +10399,6 @@
             "node": ">=6.0.0"
           }
         },
    -    "node_modules/@jridgewell/source-map": {
    -      "version": "0.3.11",
    -      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
    -      "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@jridgewell/gen-mapping": "^0.3.5",
    -        "@jridgewell/trace-mapping": "^0.3.25"
    -      }
    -    },
    -    "node_modules/@jridgewell/source-map/node_modules/@jridgewell/trace-mapping": {
    -      "version": "0.3.31",
    -      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
    -      "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@jridgewell/resolve-uri": "^3.1.0",
    -        "@jridgewell/sourcemap-codec": "^1.4.14"
    -      }
    -    },
         "node_modules/@jridgewell/sourcemap-codec": {
           "version": "1.5.5",
           "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
    @@ -11076,108 +11056,12 @@
             "@apollo/server": "^4.0.0"
           }
         },
    -    "node_modules/@nestjs/common": {
    -      "version": "11.1.10",
    -      "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.10.tgz",
    -      "integrity": "sha512-NoBzJFtq1bzHGia5Q5NO1pJNpx530nupbEu/auCWOFCGL5y8Zo8kiG28EXTCDfIhQgregEtn1Cs6H8WSLUC8kg==",
    -      "dev": true,
    -      "license": "MIT",
    -      "peer": true,
    -      "dependencies": {
    -        "file-type": "21.1.1",
    -        "iterare": "1.2.1",
    -        "load-esm": "1.0.3",
    -        "tslib": "2.8.1",
    -        "uid": "2.0.2"
    -      },
    -      "funding": {
    -        "type": "opencollective",
    -        "url": "https://opencollective.com/nest"
    -      },
    -      "peerDependencies": {
    -        "class-transformer": ">=0.4.1",
    -        "class-validator": ">=0.13.2",
    -        "reflect-metadata": "^0.1.12 || ^0.2.0",
    -        "rxjs": "^7.1.0"
    -      },
    -      "peerDependenciesMeta": {
    -        "class-transformer": {
    -          "optional": true
    -        },
    -        "class-validator": {
    -          "optional": true
    -        }
    -      }
    -    },
    -    "node_modules/@nestjs/common/node_modules/file-type": {
    -      "version": "21.1.1",
    -      "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.1.1.tgz",
    -      "integrity": "sha512-ifJXo8zUqbQ/bLbl9sFoqHNTNWbnPY1COImFfM6CCy7z+E+jC1eY9YfOKkx0fckIg+VljAy2/87T61fp0+eEkg==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@tokenizer/inflate": "^0.4.1",
    -        "strtok3": "^10.3.4",
    -        "token-types": "^6.1.1",
    -        "uint8array-extras": "^1.4.0"
    -      },
    -      "engines": {
    -        "node": ">=20"
    -      },
    -      "funding": {
    -        "url": "https://github.com/sindresorhus/file-type?sponsor=1"
    -      }
    -    },
    -    "node_modules/@nestjs/core": {
    -      "version": "11.1.10",
    -      "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.10.tgz",
    -      "integrity": "sha512-LYpaacSb8X9dcRpeZxA7Mvi5Aozv11s6028ZNoVKY2j/fyThLd+xrkksg3u+sw7F8mipFaxS/LuVpoHQ/MrACg==",
    -      "dev": true,
    -      "hasInstallScript": true,
    -      "license": "MIT",
    -      "peer": true,
    -      "dependencies": {
    -        "@nuxt/opencollective": "0.4.1",
    -        "fast-safe-stringify": "2.1.1",
    -        "iterare": "1.2.1",
    -        "path-to-regexp": "8.3.0",
    -        "tslib": "2.8.1",
    -        "uid": "2.0.2"
    -      },
    -      "engines": {
    -        "node": ">= 20"
    -      },
    -      "funding": {
    -        "type": "opencollective",
    -        "url": "https://opencollective.com/nest"
    -      },
    -      "peerDependencies": {
    -        "@nestjs/common": "^11.0.0",
    -        "@nestjs/microservices": "^11.0.0",
    -        "@nestjs/platform-express": "^11.0.0",
    -        "@nestjs/websockets": "^11.0.0",
    -        "reflect-metadata": "^0.1.12 || ^0.2.0",
    -        "rxjs": "^7.1.0"
    -      },
    -      "peerDependenciesMeta": {
    -        "@nestjs/microservices": {
    -          "optional": true
    -        },
    -        "@nestjs/platform-express": {
    -          "optional": true
    -        },
    -        "@nestjs/websockets": {
    -          "optional": true
    -        }
    -      }
    -    },
         "node_modules/@nestjs/graphql": {
           "version": "13.2.3",
           "resolved": "https://registry.npmjs.org/@nestjs/graphql/-/graphql-13.2.3.tgz",
           "integrity": "sha512-hTsQtNB2v2NoMhWUlcnpLfWlhEgSmuBETf3B1GybULhxQ84uVQxJ9CjvDWl3gf+1UmRehkS4W9NkksP07v4BxA==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "@graphql-tools/merge": "9.1.6",
             "@graphql-tools/schema": "10.0.30",
    @@ -12675,7 +12559,6 @@
           "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "@octokit/auth-token": "^4.0.0",
             "@octokit/graphql": "^7.1.0",
    @@ -12840,7 +12723,6 @@
           "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
           "dev": true,
           "license": "Apache-2.0",
    -      "peer": true,
           "engines": {
             "node": ">=8.0.0"
           }
    @@ -12851,7 +12733,6 @@
           "integrity": "sha512-JEV2RAqijAFdWeT6HddYymfnkiRu2ASxoTBr4WsnGJhOjWZkEy6vp+Sx9ozr1NaIODOa2HUyckExIqQjn6qywQ==",
           "dev": true,
           "license": "Apache-2.0",
    -      "peer": true,
           "dependencies": {
             "@opentelemetry/api": "^1.0.0"
           },
    @@ -13236,7 +13117,6 @@
           "integrity": "sha512-0CXMOYPXgAdLM2OzVkiUfAL6QQwWVhnMfUXCqLsITY42FZ9TxAhZIHkoc4mfVxvPuXsBnRYGR8UQZX86p87z4A==",
           "dev": true,
           "license": "Apache-2.0",
    -      "peer": true,
           "dependencies": {
             "@opentelemetry/api": "^1.0.0"
           },
    @@ -14122,7 +14002,6 @@
           "integrity": "sha512-JXmM4XCoso6C75Mr3lhKA3eNxSzkYi3nCzxDIKY+YOszYsJjuKbFgVtguVPbLMOttN4iu2fXoc2BGhdnYhIOxA==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "cluster-key-slot": "1.1.2"
           },
    @@ -15525,6 +15404,7 @@
           "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
           "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
           "dev": true,
    +      "license": "MIT",
           "dependencies": {
             "@types/node": "*"
           }
    @@ -15580,17 +15460,6 @@
             "@types/eslint": "*"
           }
         },
    -    "node_modules/@types/eslint-scope": {
    -      "version": "3.7.7",
    -      "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
    -      "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@types/eslint": "*",
    -        "@types/estree": "*"
    -      }
    -    },
         "node_modules/@types/estree": {
           "version": "1.0.8",
           "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
    @@ -15782,7 +15651,6 @@
           "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.4.tgz",
           "integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==",
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "undici-types": "~7.16.0"
           }
    @@ -16014,7 +15882,6 @@
           "integrity": "sha512-hM5faZwg7aVNa819m/5r7D0h0c9yC4DUlWAOvHAtISdFTc8xB86VmX5Xqabrama3wIPJ/q9RbGS1worb6JfnMg==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "@typescript-eslint/scope-manager": "8.50.1",
             "@typescript-eslint/types": "8.50.1",
    @@ -16474,167 +16341,6 @@
           "dev": true,
           "license": "MIT"
         },
    -    "node_modules/@webassemblyjs/ast": {
    -      "version": "1.14.1",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
    -      "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@webassemblyjs/helper-numbers": "1.13.2",
    -        "@webassemblyjs/helper-wasm-bytecode": "1.13.2"
    -      }
    -    },
    -    "node_modules/@webassemblyjs/floating-point-hex-parser": {
    -      "version": "1.13.2",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
    -      "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
    -      "dev": true,
    -      "license": "MIT"
    -    },
    -    "node_modules/@webassemblyjs/helper-api-error": {
    -      "version": "1.13.2",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
    -      "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
    -      "dev": true,
    -      "license": "MIT"
    -    },
    -    "node_modules/@webassemblyjs/helper-buffer": {
    -      "version": "1.14.1",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
    -      "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
    -      "dev": true,
    -      "license": "MIT"
    -    },
    -    "node_modules/@webassemblyjs/helper-numbers": {
    -      "version": "1.13.2",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz",
    -      "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@webassemblyjs/floating-point-hex-parser": "1.13.2",
    -        "@webassemblyjs/helper-api-error": "1.13.2",
    -        "@xtuc/long": "4.2.2"
    -      }
    -    },
    -    "node_modules/@webassemblyjs/helper-wasm-bytecode": {
    -      "version": "1.13.2",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
    -      "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
    -      "dev": true,
    -      "license": "MIT"
    -    },
    -    "node_modules/@webassemblyjs/helper-wasm-section": {
    -      "version": "1.14.1",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz",
    -      "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@webassemblyjs/ast": "1.14.1",
    -        "@webassemblyjs/helper-buffer": "1.14.1",
    -        "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
    -        "@webassemblyjs/wasm-gen": "1.14.1"
    -      }
    -    },
    -    "node_modules/@webassemblyjs/ieee754": {
    -      "version": "1.13.2",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz",
    -      "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@xtuc/ieee754": "^1.2.0"
    -      }
    -    },
    -    "node_modules/@webassemblyjs/leb128": {
    -      "version": "1.13.2",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz",
    -      "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
    -      "dev": true,
    -      "license": "Apache-2.0",
    -      "dependencies": {
    -        "@xtuc/long": "4.2.2"
    -      }
    -    },
    -    "node_modules/@webassemblyjs/utf8": {
    -      "version": "1.13.2",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
    -      "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
    -      "dev": true,
    -      "license": "MIT"
    -    },
    -    "node_modules/@webassemblyjs/wasm-edit": {
    -      "version": "1.14.1",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz",
    -      "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@webassemblyjs/ast": "1.14.1",
    -        "@webassemblyjs/helper-buffer": "1.14.1",
    -        "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
    -        "@webassemblyjs/helper-wasm-section": "1.14.1",
    -        "@webassemblyjs/wasm-gen": "1.14.1",
    -        "@webassemblyjs/wasm-opt": "1.14.1",
    -        "@webassemblyjs/wasm-parser": "1.14.1",
    -        "@webassemblyjs/wast-printer": "1.14.1"
    -      }
    -    },
    -    "node_modules/@webassemblyjs/wasm-gen": {
    -      "version": "1.14.1",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz",
    -      "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@webassemblyjs/ast": "1.14.1",
    -        "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
    -        "@webassemblyjs/ieee754": "1.13.2",
    -        "@webassemblyjs/leb128": "1.13.2",
    -        "@webassemblyjs/utf8": "1.13.2"
    -      }
    -    },
    -    "node_modules/@webassemblyjs/wasm-opt": {
    -      "version": "1.14.1",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz",
    -      "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@webassemblyjs/ast": "1.14.1",
    -        "@webassemblyjs/helper-buffer": "1.14.1",
    -        "@webassemblyjs/wasm-gen": "1.14.1",
    -        "@webassemblyjs/wasm-parser": "1.14.1"
    -      }
    -    },
    -    "node_modules/@webassemblyjs/wasm-parser": {
    -      "version": "1.14.1",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz",
    -      "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@webassemblyjs/ast": "1.14.1",
    -        "@webassemblyjs/helper-api-error": "1.13.2",
    -        "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
    -        "@webassemblyjs/ieee754": "1.13.2",
    -        "@webassemblyjs/leb128": "1.13.2",
    -        "@webassemblyjs/utf8": "1.13.2"
    -      }
    -    },
    -    "node_modules/@webassemblyjs/wast-printer": {
    -      "version": "1.14.1",
    -      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz",
    -      "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@webassemblyjs/ast": "1.14.1",
    -        "@xtuc/long": "4.2.2"
    -      }
    -    },
         "node_modules/@whatwg-node/promise-helpers": {
           "version": "1.3.2",
           "resolved": "https://registry.npmjs.org/@whatwg-node/promise-helpers/-/promise-helpers-1.3.2.tgz",
    @@ -16704,20 +16410,6 @@
             "node": ">=8"
           }
         },
    -    "node_modules/@xtuc/ieee754": {
    -      "version": "1.2.0",
    -      "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
    -      "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
    -      "dev": true,
    -      "license": "BSD-3-Clause"
    -    },
    -    "node_modules/@xtuc/long": {
    -      "version": "4.2.2",
    -      "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
    -      "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
    -      "dev": true,
    -      "license": "Apache-2.0"
    -    },
         "node_modules/@yarnpkg/lockfile": {
           "version": "1.1.0",
           "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
    @@ -16805,27 +16497,13 @@
           "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "bin": {
             "acorn": "bin/acorn"
           },
           "engines": {
             "node": ">=0.4.0"
           }
         },
    -    "node_modules/acorn-import-phases": {
    -      "version": "1.0.4",
    -      "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz",
    -      "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==",
    -      "dev": true,
    -      "license": "MIT",
    -      "engines": {
    -        "node": ">=10.13.0"
    -      },
    -      "peerDependencies": {
    -        "acorn": "^8.14.0"
    -      }
    -    },
         "node_modules/acorn-jsx": {
           "version": "5.3.2",
           "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
    @@ -16927,7 +16605,6 @@
           "version": "8.17.1",
           "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
           "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
    -      "peer": true,
           "dependencies": {
             "fast-deep-equal": "^3.1.3",
             "fast-uri": "^3.0.1",
    @@ -16955,19 +16632,6 @@
             }
           }
         },
    -    "node_modules/ajv-keywords": {
    -      "version": "5.1.0",
    -      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
    -      "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "fast-deep-equal": "^3.1.3"
    -      },
    -      "peerDependencies": {
    -        "ajv": "^8.8.2"
    -      }
    -    },
         "node_modules/amqp-connection-manager": {
           "version": "5.0.0",
           "resolved": "https://registry.npmjs.org/amqp-connection-manager/-/amqp-connection-manager-5.0.0.tgz",
    @@ -16991,7 +16655,6 @@
           "integrity": "sha512-jwSftI4QjS3mizvnSnOrPGYiUnm1vI2OP1iXeOUz5pb74Ua0nbf6nPyyTzuiCLEE3fMpaJORXh2K/TQ08H5xGA==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "buffer-more-ints": "~1.0.0",
             "url-parse": "~1.5.10"
    @@ -18443,16 +18106,6 @@
             "node": "^4.5.0 || >= 5.9"
           }
         },
    -    "node_modules/baseline-browser-mapping": {
    -      "version": "2.9.11",
    -      "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz",
    -      "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==",
    -      "dev": true,
    -      "license": "Apache-2.0",
    -      "bin": {
    -        "baseline-browser-mapping": "dist/cli.js"
    -      }
    -    },
         "node_modules/bcrypt-pbkdf": {
           "version": "1.0.2",
           "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
    @@ -18785,41 +18438,6 @@
           "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
           "dev": true
         },
    -    "node_modules/browserslist": {
    -      "version": "4.28.1",
    -      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
    -      "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
    -      "dev": true,
    -      "funding": [
    -        {
    -          "type": "opencollective",
    -          "url": "https://opencollective.com/browserslist"
    -        },
    -        {
    -          "type": "tidelift",
    -          "url": "https://tidelift.com/funding/github/npm/browserslist"
    -        },
    -        {
    -          "type": "github",
    -          "url": "https://github.com/sponsors/ai"
    -        }
    -      ],
    -      "license": "MIT",
    -      "peer": true,
    -      "dependencies": {
    -        "baseline-browser-mapping": "^2.9.0",
    -        "caniuse-lite": "^1.0.30001759",
    -        "electron-to-chromium": "^1.5.263",
    -        "node-releases": "^2.0.27",
    -        "update-browserslist-db": "^1.2.0"
    -      },
    -      "bin": {
    -        "browserslist": "cli.js"
    -      },
    -      "engines": {
    -        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
    -      }
    -    },
         "node_modules/buffer": {
           "version": "5.7.1",
           "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
    @@ -19118,7 +18736,6 @@
           "integrity": "sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "cluster-key-slot": "1.1.2",
             "generic-pool": "3.9.0",
    @@ -19373,27 +18990,6 @@
             "node": ">=8"
           }
         },
    -    "node_modules/caniuse-lite": {
    -      "version": "1.0.30001761",
    -      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001761.tgz",
    -      "integrity": "sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==",
    -      "dev": true,
    -      "funding": [
    -        {
    -          "type": "opencollective",
    -          "url": "https://opencollective.com/browserslist"
    -        },
    -        {
    -          "type": "tidelift",
    -          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
    -        },
    -        {
    -          "type": "github",
    -          "url": "https://github.com/sponsors/ai"
    -        }
    -      ],
    -      "license": "CC-BY-4.0"
    -    },
         "node_modules/cardinal": {
           "version": "2.1.1",
           "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz",
    @@ -19419,7 +19015,6 @@
           "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "assertion-error": "^1.1.0",
             "check-error": "^1.0.3",
    @@ -19548,16 +19143,6 @@
             "node": ">=10"
           }
         },
    -    "node_modules/chrome-trace-event": {
    -      "version": "1.0.4",
    -      "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
    -      "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
    -      "dev": true,
    -      "license": "MIT",
    -      "engines": {
    -        "node": ">=6.0"
    -      }
    -    },
         "node_modules/ci-info": {
           "version": "4.1.0",
           "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.1.0.tgz",
    @@ -19598,8 +19183,7 @@
         "node_modules/class-transformer": {
           "version": "0.5.1",
           "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
    -      "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
    -      "peer": true
    +      "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw=="
         },
         "node_modules/class-utils": {
           "version": "0.3.6",
    @@ -19633,7 +19217,6 @@
           "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.3.tgz",
           "integrity": "sha512-rXXekcjofVN1LTOSw+u4u9WXVEUvNBVjORW154q/IdmYWy1nMbOU9aNtZB0t8m+FJQ9q91jlr2f9CwwUFdFMRA==",
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "@types/validator": "^13.15.3",
             "libphonenumber-js": "^1.11.1",
    @@ -20860,7 +20443,6 @@
           "integrity": "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "engines": {
             "node": ">=18"
           }
    @@ -20871,7 +20453,6 @@
           "integrity": "sha512-uLnoLeIW4XaoFtH37qEcg/SXMJmKF4vi7V0H2rnPueg+VEtFGA/asSCNTcq4M/GQ6QmlzchAEtOoDTtKqWeHag==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "meow": "^13.0.0"
           },
    @@ -21412,7 +20993,6 @@
           "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "env-paths": "^2.2.1",
             "import-fresh": "^3.3.0",
    @@ -22712,13 +22292,6 @@
             "node": ">=0.10.0"
           }
         },
    -    "node_modules/electron-to-chromium": {
    -      "version": "1.5.267",
    -      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz",
    -      "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==",
    -      "dev": true,
    -      "license": "ISC"
    -    },
         "node_modules/emoji-regex": {
           "version": "8.0.0",
           "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
    @@ -23091,13 +22664,6 @@
             "node": ">= 0.4"
           }
         },
    -    "node_modules/es-module-lexer": {
    -      "version": "2.0.0",
    -      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz",
    -      "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==",
    -      "dev": true,
    -      "license": "MIT"
    -    },
         "node_modules/es-object-atoms": {
           "version": "1.1.1",
           "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
    @@ -23278,7 +22844,6 @@
           "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "@eslint-community/eslint-utils": "^4.8.0",
             "@eslint-community/regexpp": "^4.12.1",
    @@ -23339,7 +22904,6 @@
           "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "bin": {
             "eslint-config-prettier": "bin/cli.js"
           },
    @@ -24540,10 +24104,21 @@
           }
         },
         "node_modules/fastify-plugin": {
    -      "version": "5.0.1",
    -      "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-5.0.1.tgz",
    -      "integrity": "sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ==",
    -      "dev": true
    +      "version": "5.1.0",
    +      "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-5.1.0.tgz",
    +      "integrity": "sha512-FAIDA8eovSt5qcDgcBvDuX/v0Cjz0ohGhENZ/wpc3y+oZCY2afZ9Baqql3g/lC+OHRnciQol4ww7tuthOb9idw==",
    +      "dev": true,
    +      "funding": [
    +        {
    +          "type": "github",
    +          "url": "https://github.com/sponsors/fastify"
    +        },
    +        {
    +          "type": "opencollective",
    +          "url": "https://opencollective.com/fastify"
    +        }
    +      ],
    +      "license": "MIT"
         },
         "node_modules/fastify/node_modules/process-warning": {
           "version": "5.0.0",
    @@ -24846,17 +24421,18 @@
           }
         },
         "node_modules/find-my-way": {
    -      "version": "9.1.0",
    -      "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-9.1.0.tgz",
    -      "integrity": "sha512-Y5jIsuYR4BwWDYYQ2A/RWWE6gD8a0FMgtU+HOq1WKku+Cwdz8M1v8wcAmRXXM1/iqtoqg06v+LjAxMYbCjViMw==",
    +      "version": "9.3.0",
    +      "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-9.3.0.tgz",
    +      "integrity": "sha512-eRoFWQw+Yv2tuYlK2pjFS2jGXSxSppAs3hSQjfxVKxM5amECzIgYYc1FEI8ZmhSh/Ig+FrKEz43NLRKJjYCZVg==",
           "dev": true,
    +      "license": "MIT",
           "dependencies": {
             "fast-deep-equal": "^3.1.3",
             "fast-querystring": "^1.0.0",
    -        "safe-regex2": "^4.0.0"
    +        "safe-regex2": "^5.0.0"
           },
           "engines": {
    -        "node": ">=14"
    +        "node": ">=20"
           }
         },
         "node_modules/find-up": {
    @@ -26112,13 +25688,6 @@
             "node": ">=10.13.0"
           }
         },
    -    "node_modules/glob-to-regexp": {
    -      "version": "0.4.1",
    -      "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
    -      "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
    -      "dev": true,
    -      "license": "BSD-2-Clause"
    -    },
         "node_modules/glob-watcher": {
           "version": "6.0.0",
           "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-6.0.0.tgz",
    @@ -26358,7 +25927,6 @@
           "integrity": "sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "engines": {
             "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
           }
    @@ -30257,37 +29825,6 @@
             "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
           }
         },
    -    "node_modules/jest-worker": {
    -      "version": "27.5.1",
    -      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
    -      "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@types/node": "*",
    -        "merge-stream": "^2.0.0",
    -        "supports-color": "^8.0.0"
    -      },
    -      "engines": {
    -        "node": ">= 10.13.0"
    -      }
    -    },
    -    "node_modules/jest-worker/node_modules/supports-color": {
    -      "version": "8.1.1",
    -      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
    -      "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "has-flag": "^4.0.0"
    -      },
    -      "engines": {
    -        "node": ">=10"
    -      },
    -      "funding": {
    -        "url": "https://github.com/chalk/supports-color?sponsor=1"
    -      }
    -    },
         "node_modules/jiti": {
           "version": "2.6.1",
           "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
    @@ -30362,7 +29899,6 @@
           "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "engines": {
             "node": ">= 10.16.0"
           }
    @@ -32022,20 +31558,6 @@
             "node": ">=4"
           }
         },
    -    "node_modules/loader-runner": {
    -      "version": "4.3.1",
    -      "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz",
    -      "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==",
    -      "dev": true,
    -      "license": "MIT",
    -      "engines": {
    -        "node": ">=6.11.5"
    -      },
    -      "funding": {
    -        "type": "opencollective",
    -        "url": "https://opencollective.com/webpack"
    -      }
    -    },
         "node_modules/locate-path": {
           "version": "7.2.0",
           "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz",
    @@ -32722,7 +32244,6 @@
           "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz",
           "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==",
           "dev": true,
    -      "peer": true,
           "bin": {
             "marked": "bin/marked"
           },
    @@ -33668,7 +33189,6 @@
           "integrity": "sha512-+GCaqwE+X//yN9eo2M2L/n+mVti9J6vH5iQKbhD+2AArZd5iaZqK/DkmkE4S6/iYYMyVQPTXsRk7jyVOYEtJzA==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "kareem": "3.0.0",
             "mongodb": "~7.0",
    @@ -34641,13 +34161,6 @@
           "dev": true,
           "license": "MIT"
         },
    -    "node_modules/node-releases": {
    -      "version": "2.0.27",
    -      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
    -      "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
    -      "dev": true,
    -      "license": "MIT"
    -    },
         "node_modules/node-source-walk": {
           "version": "6.0.2",
           "resolved": "https://registry.npmjs.org/node-source-walk/-/node-source-walk-6.0.2.tgz",
    @@ -35140,7 +34653,6 @@
           "dev": true,
           "hasInstallScript": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "@napi-rs/wasm-runtime": "0.2.4",
             "@yarnpkg/lockfile": "^1.1.0",
    @@ -37375,7 +36887,6 @@
             }
           ],
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "nanoid": "^3.3.11",
             "picocolors": "^1.1.1",
    @@ -37514,7 +37025,6 @@
           "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "bin": {
             "prettier": "bin/prettier.cjs"
           },
    @@ -38187,7 +37697,6 @@
           "integrity": "sha512-0/Y+7IEiTgVGPrLFKy8oAEArSyEJkU0zvgV5xyi9NzNQ+SLZmyFbUsWIbgPcd4UdUh00opXGKlXJwMmsis5Byw==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "@redis/bloom": "5.10.0",
             "@redis/client": "5.10.0",
    @@ -38223,8 +37732,7 @@
         "node_modules/reflect-metadata": {
           "version": "0.2.2",
           "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
    -      "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
    -      "peer": true
    +      "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q=="
         },
         "node_modules/reflect.getprototypeof": {
           "version": "1.0.10",
    @@ -38384,7 +37892,6 @@
           "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
           "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
           "dev": true,
    -      "peer": true,
           "dependencies": {
             "aws-sign2": "~0.7.0",
             "aws4": "^1.8.0",
    @@ -38698,6 +38205,7 @@
           "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz",
           "integrity": "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==",
           "dev": true,
    +      "license": "MIT",
           "engines": {
             "node": ">=10"
           }
    @@ -38712,10 +38220,11 @@
           }
         },
         "node_modules/reusify": {
    -      "version": "1.0.4",
    -      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
    -      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
    +      "version": "1.1.0",
    +      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
    +      "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
           "dev": true,
    +      "license": "MIT",
           "engines": {
             "iojs": ">=1.0.0",
             "node": ">=0.10.0"
    @@ -38953,9 +38462,9 @@
           }
         },
         "node_modules/safe-regex2": {
    -      "version": "4.0.1",
    -      "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-4.0.1.tgz",
    -      "integrity": "sha512-goqsB+bSlOmVX+CiFX2PFc1OV88j5jvBqIM+DgqrucHnUguAUNtiNOs+aTadq2NqsLQ+TQ3UEVG3gtSFcdlkCg==",
    +      "version": "5.0.0",
    +      "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.0.0.tgz",
    +      "integrity": "sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw==",
           "dev": true,
           "funding": [
             {
    @@ -38967,6 +38476,7 @@
               "url": "https://opencollective.com/fastify"
             }
           ],
    +      "license": "MIT",
           "dependencies": {
             "ret": "~0.5.0"
           }
    @@ -39013,44 +38523,6 @@
             "node": ">=18"
           }
         },
    -    "node_modules/schema-utils": {
    -      "version": "4.3.3",
    -      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz",
    -      "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@types/json-schema": "^7.0.9",
    -        "ajv": "^8.9.0",
    -        "ajv-formats": "^2.1.1",
    -        "ajv-keywords": "^5.1.0"
    -      },
    -      "engines": {
    -        "node": ">= 10.13.0"
    -      },
    -      "funding": {
    -        "type": "opencollective",
    -        "url": "https://opencollective.com/webpack"
    -      }
    -    },
    -    "node_modules/schema-utils/node_modules/ajv-formats": {
    -      "version": "2.1.1",
    -      "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
    -      "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "ajv": "^8.0.0"
    -      },
    -      "peerDependencies": {
    -        "ajv": "^8.0.0"
    -      },
    -      "peerDependenciesMeta": {
    -        "ajv": {
    -          "optional": true
    -        }
    -      }
    -    },
         "node_modules/secure-json-parse": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.0.0.tgz",
    @@ -41150,71 +40622,6 @@
             "url": "https://github.com/sponsors/sindresorhus"
           }
         },
    -    "node_modules/terser": {
    -      "version": "5.44.1",
    -      "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz",
    -      "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==",
    -      "dev": true,
    -      "license": "BSD-2-Clause",
    -      "dependencies": {
    -        "@jridgewell/source-map": "^0.3.3",
    -        "acorn": "^8.15.0",
    -        "commander": "^2.20.0",
    -        "source-map-support": "~0.5.20"
    -      },
    -      "bin": {
    -        "terser": "bin/terser"
    -      },
    -      "engines": {
    -        "node": ">=10"
    -      }
    -    },
    -    "node_modules/terser-webpack-plugin": {
    -      "version": "5.3.16",
    -      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz",
    -      "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@jridgewell/trace-mapping": "^0.3.25",
    -        "jest-worker": "^27.4.5",
    -        "schema-utils": "^4.3.0",
    -        "serialize-javascript": "^6.0.2",
    -        "terser": "^5.31.1"
    -      },
    -      "engines": {
    -        "node": ">= 10.13.0"
    -      },
    -      "funding": {
    -        "type": "opencollective",
    -        "url": "https://opencollective.com/webpack"
    -      },
    -      "peerDependencies": {
    -        "webpack": "^5.1.0"
    -      },
    -      "peerDependenciesMeta": {
    -        "@swc/core": {
    -          "optional": true
    -        },
    -        "esbuild": {
    -          "optional": true
    -        },
    -        "uglify-js": {
    -          "optional": true
    -        }
    -      }
    -    },
    -    "node_modules/terser-webpack-plugin/node_modules/@jridgewell/trace-mapping": {
    -      "version": "0.3.31",
    -      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
    -      "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@jridgewell/resolve-uri": "^3.1.0",
    -        "@jridgewell/sourcemap-codec": "^1.4.14"
    -      }
    -    },
         "node_modules/text-decoder": {
           "version": "1.2.3",
           "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz",
    @@ -41633,7 +41040,6 @@
           "integrity": "sha512-fhUhgeljcrdZ+9DZND1De1029PrE+cMkIP7ooqkLRTrRLTqcki2AstsyJm0vRNbTbVCNJ0idGlbBrfqc7/nA8w==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "@ts-morph/common": "~0.28.1",
             "code-block-writer": "^13.0.3"
    @@ -41915,7 +41321,6 @@
           "integrity": "sha512-6GH7wXhtfq2D33ZuRXYwIsl/qM5685WZcODZb7noOOcRMteM9KF2x2ap3H0EBjnSV0VO4gNAfJT5Ukp0PkOlvg==",
           "dev": true,
           "license": "MIT",
    -      "peer": true,
           "dependencies": {
             "@sqltools/formatter": "^1.2.5",
             "ansis": "^4.2.0",
    @@ -42145,7 +41550,6 @@
           "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
           "dev": true,
           "license": "Apache-2.0",
    -      "peer": true,
           "bin": {
             "tsc": "bin/tsc",
             "tsserver": "bin/tsserver"
    @@ -42489,37 +41893,6 @@
             "yarn": "*"
           }
         },
    -    "node_modules/update-browserslist-db": {
    -      "version": "1.2.3",
    -      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
    -      "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
    -      "dev": true,
    -      "funding": [
    -        {
    -          "type": "opencollective",
    -          "url": "https://opencollective.com/browserslist"
    -        },
    -        {
    -          "type": "tidelift",
    -          "url": "https://tidelift.com/funding/github/npm/browserslist"
    -        },
    -        {
    -          "type": "github",
    -          "url": "https://github.com/sponsors/ai"
    -        }
    -      ],
    -      "license": "MIT",
    -      "dependencies": {
    -        "escalade": "^3.2.0",
    -        "picocolors": "^1.1.1"
    -      },
    -      "bin": {
    -        "update-browserslist-db": "cli.js"
    -      },
    -      "peerDependencies": {
    -        "browserslist": ">= 4.21.0"
    -      }
    -    },
         "node_modules/uri-js": {
           "version": "4.4.1",
           "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
    @@ -42894,20 +42267,6 @@
             "node": "20 || >=22"
           }
         },
    -    "node_modules/watchpack": {
    -      "version": "2.4.4",
    -      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz",
    -      "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "glob-to-regexp": "^0.4.1",
    -        "graceful-fs": "^4.1.2"
    -      },
    -      "engines": {
    -        "node": ">=10.13.0"
    -      }
    -    },
         "node_modules/wcwidth": {
           "version": "1.0.1",
           "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
    @@ -42927,89 +42286,6 @@
             "node": ">=12"
           }
         },
    -    "node_modules/webpack": {
    -      "version": "5.104.1",
    -      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz",
    -      "integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==",
    -      "dev": true,
    -      "license": "MIT",
    -      "dependencies": {
    -        "@types/eslint-scope": "^3.7.7",
    -        "@types/estree": "^1.0.8",
    -        "@types/json-schema": "^7.0.15",
    -        "@webassemblyjs/ast": "^1.14.1",
    -        "@webassemblyjs/wasm-edit": "^1.14.1",
    -        "@webassemblyjs/wasm-parser": "^1.14.1",
    -        "acorn": "^8.15.0",
    -        "acorn-import-phases": "^1.0.3",
    -        "browserslist": "^4.28.1",
    -        "chrome-trace-event": "^1.0.2",
    -        "enhanced-resolve": "^5.17.4",
    -        "es-module-lexer": "^2.0.0",
    -        "eslint-scope": "5.1.1",
    -        "events": "^3.2.0",
    -        "glob-to-regexp": "^0.4.1",
    -        "graceful-fs": "^4.2.11",
    -        "json-parse-even-better-errors": "^2.3.1",
    -        "loader-runner": "^4.3.1",
    -        "mime-types": "^2.1.27",
    -        "neo-async": "^2.6.2",
    -        "schema-utils": "^4.3.3",
    -        "tapable": "^2.3.0",
    -        "terser-webpack-plugin": "^5.3.16",
    -        "watchpack": "^2.4.4",
    -        "webpack-sources": "^3.3.3"
    -      },
    -      "bin": {
    -        "webpack": "bin/webpack.js"
    -      },
    -      "engines": {
    -        "node": ">=10.13.0"
    -      },
    -      "funding": {
    -        "type": "opencollective",
    -        "url": "https://opencollective.com/webpack"
    -      },
    -      "peerDependenciesMeta": {
    -        "webpack-cli": {
    -          "optional": true
    -        }
    -      }
    -    },
    -    "node_modules/webpack-sources": {
    -      "version": "3.3.3",
    -      "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz",
    -      "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==",
    -      "dev": true,
    -      "license": "MIT",
    -      "engines": {
    -        "node": ">=10.13.0"
    -      }
    -    },
    -    "node_modules/webpack/node_modules/eslint-scope": {
    -      "version": "5.1.1",
    -      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
    -      "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
    -      "dev": true,
    -      "license": "BSD-2-Clause",
    -      "dependencies": {
    -        "esrecurse": "^4.3.0",
    -        "estraverse": "^4.1.1"
    -      },
    -      "engines": {
    -        "node": ">=8.0.0"
    -      }
    -    },
    -    "node_modules/webpack/node_modules/estraverse": {
    -      "version": "4.3.0",
    -      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
    -      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
    -      "dev": true,
    -      "license": "BSD-2-Clause",
    -      "engines": {
    -        "node": ">=4.0"
    -      }
    -    },
         "node_modules/whatwg-encoding": {
           "version": "3.1.1",
           "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
    
  • packages/platform-fastify/adapters/fastify-adapter.ts+5 4 modified
    @@ -50,6 +50,7 @@ import {
     import { pathToRegexp } from 'path-to-regexp';
     // Fastify uses `fast-querystring` internally to quickly parse URL query strings.
     import { parse as querystringParse } from 'fast-querystring';
    +import { safeDecodeURI } from 'find-my-way/lib/url-sanitizer';
     import {
       FASTIFY_ROUTE_CONFIG_METADATA,
       FASTIFY_ROUTE_CONSTRAINTS_METADATA,
    @@ -60,6 +61,7 @@ import {
       FastifyStaticOptions,
       FastifyViewOptions,
     } from '../interfaces/external';
    +import middie from './middie/fastify-middie';
     
     type FastifyAdapterBaseOptions<
       Server extends RawServerBase = RawServerDefault,
    @@ -702,10 +704,11 @@ export class FastifyAdapter<
               normalizedPath,
               (req: any, res: any, next: Function) => {
                 const queryParamsIndex = req.originalUrl.indexOf('?');
    -            const pathname =
    +            let pathname =
                   queryParamsIndex >= 0
                     ? req.originalUrl.slice(0, queryParamsIndex)
                     : req.originalUrl;
    +            pathname = safeDecodeURI(pathname).path;
     
                 if (!re.exec(pathname + '/') && normalizedPath) {
                   return next();
    @@ -791,9 +794,7 @@ export class FastifyAdapter<
     
       private async registerMiddie() {
         this.isMiddieRegistered = true;
    -    await this.register(
    -      import('@fastify/middie') as Parameters<TInstance['register']>[0],
    -    );
    +    await this.register(middie as Parameters<TInstance['register']>[0]);
       }
     
       private getRequestOriginalUrl(rawRequest: TRawRequest) {
    
  • packages/platform-fastify/adapters/middie/fastify-middie.ts+363 0 added
    @@ -0,0 +1,363 @@
    +import {
    +  FastifyInstance,
    +  FastifyPluginCallback,
    +  FastifyReply,
    +  FastifyRequest,
    +  HookHandlerDoneFunction,
    +} from 'fastify';
    +import fp from 'fastify-plugin';
    +import { safeDecodeURI } from 'find-my-way/lib/url-sanitizer';
    +import * as http from 'node:http';
    +import { Path, pathToRegexp } from 'path-to-regexp';
    +import reusify = require('reusify');
    +
    +export type MiddlewareFn<
    +  Req extends { url: string; originalUrl?: string },
    +  Res extends { finished?: boolean; writableEnded?: boolean },
    +  Ctx = unknown,
    +> = (req: Req, res: Res, next: (err?: unknown) => void) => void;
    +
    +interface MiddlewareEntry<
    +  Req extends { url: string; originalUrl?: string },
    +  Res extends { finished?: boolean; writableEnded?: boolean },
    +  Ctx,
    +> {
    +  regexp?: RegExp;
    +  fn: MiddlewareFn<Req, Res, Ctx>;
    +}
    +
    +/**
    + * A clone of `@fastify/middie` engine https://github.com/fastify/middie
    + * with an extra vulnerability fix. Path is now decoded before matching to
    + * avoid bypassing middleware with encoded characters.
    + */
    +function middie<
    +  Req extends { url: string; originalUrl?: string },
    +  Res extends { finished?: boolean; writableEnded?: boolean },
    +  Ctx = unknown,
    +>(complete: (err: unknown, req: Req, res: Res, ctx: Ctx) => void) {
    +  const middlewares: MiddlewareEntry<Req, Res, Ctx>[] = [];
    +  const pool = reusify(Holder as any);
    +
    +  return {
    +    use,
    +    run,
    +  };
    +
    +  function use(
    +    this: unknown,
    +    url:
    +      | string
    +      | null
    +      | MiddlewareFn<Req, Res, Ctx>
    +      | MiddlewareFn<Req, Res, Ctx>[],
    +    f?: MiddlewareFn<Req, Res, Ctx> | MiddlewareFn<Req, Res, Ctx>[],
    +  ) {
    +    if (f === undefined) {
    +      f = url as MiddlewareFn<Req, Res, Ctx> | MiddlewareFn<Req, Res, Ctx>[];
    +      url = null;
    +    }
    +
    +    let regexp: RegExp | undefined;
    +    if (typeof url === 'string') {
    +      const pathRegExp = pathToRegexp(sanitizePrefixUrl(url) as Path, {
    +        end: false,
    +      });
    +      regexp = pathRegExp.regexp;
    +    }
    +
    +    if (Array.isArray(f)) {
    +      for (const val of f) {
    +        middlewares.push({ regexp, fn: val });
    +      }
    +    } else {
    +      middlewares.push({ regexp, fn: f });
    +    }
    +
    +    return this;
    +  }
    +
    +  function run(req: Req, res: Res, ctx: Ctx) {
    +    if (!middlewares.length) {
    +      complete(null, req, res, ctx);
    +      return;
    +    }
    +
    +    req.originalUrl = req.url;
    +
    +    const holder = pool.get() as any as HolderInstance;
    +    holder.req = req;
    +    holder.res = res;
    +    holder.url = sanitizeUrl(req.url);
    +    holder.context = ctx;
    +    holder.done();
    +  }
    +
    +  interface HolderInstance {
    +    req: Req | null;
    +    res: Res | null;
    +    url: string | null;
    +    context: Ctx | null;
    +    i: number;
    +    done: (err?: unknown) => void;
    +  }
    +
    +  function Holder(this: HolderInstance) {
    +    this.req = null;
    +    this.res = null;
    +    this.url = null;
    +    this.context = null;
    +    this.i = 0;
    +
    +    const that = this;
    +
    +    this.done = function (err?: unknown) {
    +      const req = that.req!;
    +      const res = that.res!;
    +      const url = that.url!;
    +      const context = that.context!;
    +      const i = that.i++;
    +
    +      req.url = req.originalUrl!;
    +
    +      if (res.finished === true || res.writableEnded === true) {
    +        cleanup();
    +        return;
    +      }
    +
    +      if (err || middlewares.length === i) {
    +        complete(err, req, res, context);
    +        cleanup();
    +      } else {
    +        const { fn, regexp } = middlewares[i];
    +
    +        if (regexp) {
    +          // Decode URL before matching to avoid bypassing middleware
    +          const decodedUrl = safeDecodeURI(url).path;
    +          const result = regexp.exec(decodedUrl);
    +          if (result) {
    +            req.url = req.url.replace(result[0], '');
    +            if (req.url[0] !== '/') req.url = '/' + req.url;
    +            fn(req, res, that.done);
    +          } else {
    +            that.done();
    +          }
    +        } else {
    +          fn(req, res, that.done);
    +        }
    +      }
    +    };
    +
    +    function cleanup() {
    +      that.req = null;
    +      that.res = null;
    +      that.context = null;
    +      that.i = 0;
    +      pool.release(that as any);
    +    }
    +  }
    +}
    +
    +function sanitizeUrl(url: string): string {
    +  for (let i = 0, len = url.length; i < len; i++) {
    +    const charCode = url.charCodeAt(i);
    +    if (charCode === 63 || charCode === 35) {
    +      return url.slice(0, i);
    +    }
    +  }
    +  return url;
    +}
    +
    +function sanitizePrefixUrl(url: string): string {
    +  if (url === '/') return '';
    +  if (url[url.length - 1] === '/') return url.slice(0, -1);
    +  return url;
    +}
    +
    +const kMiddlewares = Symbol('fastify-middie-middlewares');
    +const kMiddie = Symbol('fastify-middie-instance');
    +const kMiddieHasMiddlewares = Symbol('fastify-middie-has-middlewares');
    +
    +const supportedHooksWithPayload = [
    +  'onError',
    +  'onSend',
    +  'preParsing',
    +  'preSerialization',
    +] as const;
    +
    +const supportedHooksWithoutPayload = [
    +  'onRequest',
    +  'onResponse',
    +  'onTimeout',
    +  'preHandler',
    +  'preValidation',
    +] as const;
    +
    +const supportedHooks = [
    +  ...supportedHooksWithPayload,
    +  ...supportedHooksWithoutPayload,
    +] as const;
    +
    +type SupportedHook = (typeof supportedHooks)[number];
    +
    +interface MiddieOptions {
    +  hook?: SupportedHook;
    +}
    +
    +function fastifyMiddie(
    +  fastify: FastifyInstance,
    +  options: MiddieOptions,
    +  next: (err?: Error) => void,
    +) {
    +  fastify.decorate('use', use as any);
    +  fastify[kMiddlewares] = [];
    +  fastify[kMiddieHasMiddlewares] = false;
    +  fastify[kMiddie] = middie(onMiddieEnd);
    +
    +  const hook = options.hook || 'onRequest';
    +
    +  if (!supportedHooks.includes(hook)) {
    +    next(new Error(`The hook "${hook}" is not supported by fastify-middie`));
    +    return;
    +  }
    +
    +  fastify
    +    .addHook(
    +      hook,
    +      supportedHooksWithPayload.includes(hook as any)
    +        ? runMiddieWithPayload
    +        : runMiddie,
    +    )
    +    .addHook('onRegister', onRegister);
    +
    +  function use(this: FastifyInstance, path: string | null, fn?: Function) {
    +    if (typeof path === 'string') {
    +      const prefix = this.prefix;
    +      path = prefix + (path === '/' && prefix.length > 0 ? '' : path);
    +    }
    +
    +    this[kMiddlewares].push([path, fn]);
    +
    +    if (fn == null) {
    +      this[kMiddie].use(path);
    +    } else {
    +      this[kMiddie].use(path, fn);
    +    }
    +
    +    this[kMiddieHasMiddlewares] = true;
    +    return this;
    +  }
    +
    +  function runMiddie(
    +    this: FastifyInstance,
    +    req: FastifyRequest,
    +    reply: FastifyReply,
    +    next: HookHandlerDoneFunction,
    +  ) {
    +    if (this[kMiddieHasMiddlewares]) {
    +      const raw = req.raw as any;
    +      raw.id = req.id;
    +      raw.hostname = req.hostname;
    +      raw.protocol = req.protocol;
    +      raw.ip = req.ip;
    +      raw.ips = req.ips;
    +      raw.log = req.log;
    +      (req.raw as any).query = req.query;
    +      (reply.raw as any).log = req.log;
    +      if (req.body !== undefined) (req.raw as any).body = req.body;
    +      this[kMiddie].run(req.raw, reply.raw, next);
    +    } else {
    +      next();
    +    }
    +  }
    +
    +  function runMiddieWithPayload(
    +    this: FastifyInstance,
    +    req: FastifyRequest,
    +    reply: FastifyReply,
    +    _payload: unknown,
    +    next: HookHandlerDoneFunction,
    +  ) {
    +    runMiddie.bind(this)(req, reply, next);
    +  }
    +
    +  function onMiddieEnd(
    +    err: unknown,
    +    _req: any,
    +    _res: any,
    +    next: (err?: unknown) => void,
    +  ) {
    +    next(err);
    +  }
    +
    +  function onRegister(instance: FastifyInstance) {
    +    const middlewares = instance[kMiddlewares].slice() as Array<Array<unknown>>;
    +    instance[kMiddlewares] = [];
    +    instance[kMiddie] = middie(onMiddieEnd);
    +    instance[kMiddieHasMiddlewares] = false;
    +    instance.decorate('use', use as any);
    +    for (const middleware of middlewares) {
    +      (instance.use as any)(...middleware);
    +    }
    +  }
    +
    +  next();
    +}
    +
    +declare namespace fastifyMiddie {
    +  export interface FastifyMiddieOptions {
    +    hook?:
    +      | 'onRequest'
    +      | 'preParsing'
    +      | 'preValidation'
    +      | 'preHandler'
    +      | 'preSerialization'
    +      | 'onSend'
    +      | 'onResponse'
    +      | 'onTimeout'
    +      | 'onError';
    +  }
    +
    +  type FastifyMiddie =
    +    FastifyPluginCallback<fastifyMiddie.FastifyMiddieOptions>;
    +
    +  export interface IncomingMessageExtended {
    +    body?: any;
    +    query?: any;
    +  }
    +  export type NextFunction = (err?: any) => void;
    +  export type SimpleHandleFunction = (
    +    req: http.IncomingMessage & IncomingMessageExtended,
    +    res: http.ServerResponse,
    +  ) => void;
    +  export type NextHandleFunction = (
    +    req: http.IncomingMessage & IncomingMessageExtended,
    +    res: http.ServerResponse,
    +    next: NextFunction,
    +  ) => void;
    +
    +  export type Handler = SimpleHandleFunction | NextHandleFunction;
    +
    +  export const fastifyMiddie: FastifyMiddie;
    +  export { fastifyMiddie as default };
    +}
    +
    +declare module 'fastify' {
    +  interface FastifyInstance {
    +    use(fn: fastifyMiddie.Handler): this;
    +    use(route: string, fn: fastifyMiddie.Handler): this;
    +    use(routes: string[], fn: fastifyMiddie.Handler): this;
    +  }
    +}
    +
    +/**
    + * A clone of `@fastify/middie` engine https://github.com/fastify/middie
    + * with an extra vulnerability fix. Path is now decoded before matching to
    + * avoid bypassing middleware with encoded characters.
    + */
    +export default fp(fastifyMiddie, {
    +  fastify: '5.x',
    +  name: '@fastify/middie',
    +});
    +
    +export { fastifyMiddie };
    
  • packages/platform-fastify/package.json+3 1 modified
    @@ -20,11 +20,13 @@
       "dependencies": {
         "@fastify/cors": "11.2.0",
         "@fastify/formbody": "8.0.2",
    -    "@fastify/middie": "9.0.3",
         "fast-querystring": "1.1.2",
         "fastify": "5.6.2",
    +    "fastify-plugin": "5.1.0",
    +    "find-my-way": "9.3.0",
         "light-my-request": "6.6.0",
         "path-to-regexp": "8.3.0",
    +    "reusify": "1.1.0",
         "tslib": "2.8.1"
       },
       "peerDependencies": {
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.