Mar 2, 2026·5 min read·83 visits
CVE-2026-2293 allows unauthenticated attackers to bypass NestJS middleware guards when using the Fastify adapter. By exploiting differences in URL normalization, attackers can access protected endpoints using manipulated paths like `//admin` or `/ADMIN`. Fixed in version 11.1.14.
A high-severity path canonicalization vulnerability exists in the `@nestjs/platform-fastify` adapter of the NestJS framework. The vulnerability arises from a discrepancy between how the NestJS middleware engine matches routes (using raw URLs) and how the underlying Fastify router handles requests (using normalized URLs). This 'Differential Normalization' allows remote attackers to bypass route-scoped authentication and authorization middleware by crafting malformed URLs (e.g., containing double slashes or casing variations) that fail middleware regex matching but are successfully routed to protected controllers.
CVE-2026-2293 represents a critical breakdown in the request processing pipeline of NestJS applications utilizing the Fastify platform adapter. The core issue is a Path Canonicalization Mismatch (CWE-436), commonly referred to as Differential Normalization. In a layered web architecture, security controls (middleware) and request routing often operate as distinct components. When these components disagree on the interpretation of a URL path, security gaps emerge.
In the specific context of NestJS, the framework provides a middleware engine responsible for executing logic—such as authentication guards, logging, or input validation—before a request reaches its final route handler. This engine determines applicability by matching the incoming request path against defined patterns. However, the @nestjs/platform-fastify adapter historically performed this matching against the raw, unnormalized URL (req.originalUrl).
Conversely, the underlying Fastify server is highly configurable regarding URL normalization. It can be instructed to ignore trailing slashes, merge duplicate slashes, or ignore case sensitivity. When Fastify normalizes a request to route it, but NestJS fails to normalize the request before checking middleware applicability, a bypass occurs. The middleware assumes the request does not match the protected route and allows it to proceed, while Fastify subsequently routes the request to the sensitive endpoint.
The vulnerability is rooted in the decoupling of the middleware matching logic from the router's normalization logic. The NestJS middleware dispatcher relies on regular expressions generated from route paths to decide whether to execute a specific middleware. Prior to version 11.1.14, this regex matching was performed against the raw request string without accounting for the specific normalization configuration of the Fastify instance.
Technically, the failure mechanism works as follows:
ignoreDuplicateSlashes: true. This tells Fastify that //api and /api are semantically identical./api/private./api/private into a strict regular expression (e.g., ^/api/private).//api/private.//api/private against the regex ^/api/private. The match fails because of the leading double slash.//api/private to /api/private, and successfully dispatches the request to the route handler.The fix for CVE-2026-2293 introduces a synchronization mechanism between the Fastify adapter's configuration and the URL seen by the middleware matcher. The patch was applied in packages/platform-fastify/adapters/fastify-adapter.ts.
Vulnerable Logic (Conceptual): Previously, the adapter passed the raw request URL directly to the middleware container. There was no pre-processing step to align the URL with Fastify's internal router logic.
Patched Logic:
The fix introduces a sanitizeUrl method. This method inspects the FastifyServerOptions (specifically routerOptions) and manually applies the same transformations that Fastify would apply later in the lifecycle.
// Analysis of the fix in FastifyAdapter
private sanitizeUrl(url: string): string {
const initialConfig = this.instance.initialConfig as FastifyServerOptions;
const routerOptions = initialConfig.routerOptions as Partial<FastifyServerOptions>;
// Replicating 'ignoreDuplicateSlashes'
if (routerOptions.ignoreDuplicateSlashes || initialConfig.ignoreDuplicateSlashes) {
url = this.removeDuplicateSlashes(url);
}
// Replicating 'ignoreTrailingSlash'
if (routerOptions.ignoreTrailingSlash || initialConfig.ignoreTrailingSlash) {
url = this.trimLastSlash(url);
}
// Replicating 'caseSensitive'
if (routerOptions.caseSensitive === false || initialConfig.caseSensitive === false) {
url = url.toLowerCase();
}
// Decoding URI components to match router expectations
return safeDecodeURI(
url,
routerOptions.useSemicolonDelimiter || initialConfig.useSemicolonDelimiter,
).path;
}By ensuring the URL is sanitized before the middleware regex runs, NestJS ensures that any request Fastify would consider a match is also considered a match by the security middleware.
Exploitation of this vulnerability is trivial and requires no authentication or special tools. The attacker merely needs to identify endpoints protected by middleware and manipulate the URL path based on the server's configuration.
Scenario 1: Duplicate Slashes
If ignoreDuplicateSlashes: true (often default or common configuration):
GET /admin/delete-userGET //admin/delete-user/admin is bypassed; Controller for /admin/delete-user executes.Scenario 2: Case Sensitivity
If caseSensitive: false:
GET /api/v1/secureGET /API/v1/SECUREExploit Flow Diagram:
The impact is direct Access Control Bypass. Since NestJS relies heavily on Guards and Interceptors for authorization, bypassing these layers grants full access to the underlying business logic.
The impact of CVE-2026-2293 is rated High (CVSS 8.2) because it completely undermines the integrity of the application's authorization model. While the vulnerability requires specific Fastify configurations to be exploitable, these configurations are common in production environments to ensure user-friendly URL handling.
The vector CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:H/VA:N highlights that the attack is network-adjacent, low complexity, but requires specific attack requirements (AT:P, referring to the Fastify configuration prerequisites).
CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
@nestjs/platform-fastify NestJS | < 11.1.14 | 11.1.14 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-436 |
| Attack Vector | Network |
| CVSS Score | 8.2 (High) |
| EPSS Score | 0.11% |
| Impact | Authorization Bypass |
| Exploit Status | Proof of Concept Available |
Interpretation Conflict (Path Canonicalization Mismatch)
An uncontrolled resource consumption vulnerability in the knative.dev/pkg/webhook package allows network-adjacent attackers within a Kubernetes cluster to trigger Out-Of-Memory (OOM) terminations of admission controller pods. The admission webhook HTTP server processes incoming AdmissionReview requests through an io.TeeReader and json.Decoder pipeline without enforcing an upper bound on request body size. Due to internal buffer reallocation mechanics, incoming payloads experience a 4.5x memory amplification factor. Because knative.dev/pkg provides the shared webhook server foundation for numerous cloud-native projects—including Knative Serving, Knative Eventing, Tekton, KEDA, Sigstore Policy Controller, and Kpack—exploitation can halt resource admission across entire Kubernetes clusters or bypass critical security validation policies.
CVE-2026-115923 (GHSA-w658-mh9p-ww8f) is a path traversal and access control bypass vulnerability in Spotify's Backstage developer portal framework, specifically within the @backstage/plugin-catalog-backend package. Prior to patched versions, DefaultCatalogRulesEnforcer evaluated user-supplied URL catalog locations against configured catalog.rules patterns using raw, uncanonicalized strings. Because downstream URL readers canonicalize URLs and resolve dot segments before fetching resources, an authenticated attacker with location registration permissions can supply percent-encoded traversal sequences (such as %2e%2e) to bypass location restrictions and register untrusted catalog entities.
CVE-2026-116576 (GHSA-3f7j-7jwc-fxfj) is an OS Command Injection vulnerability (CWE-78) in the Node.js systeminformation library prior to version 5.33.16 on Microsoft Windows. The services() API function dynamically constructs a PowerShell Get-CimInstance command using caller-supplied service names passed through sanitizeShellString(). While the sanitizer strips standard ASCII quotation marks, it permits Unicode typographic quotation marks (U+2018 through U+201E). Because the Windows PowerShell tokenizer recognizes Unicode quotation marks as valid string literal delimiters, an attacker who controls the service name input can break out of the CIM filter string and execute arbitrary PowerShell commands within the security context of the Node.js process.
An interpretation conflict vulnerability (CWE-436) exists in the Ruby CSS parser library Crass prior to version 1.0.8. When consuming the remnants of a malformed URL token, the tokenizer erroneously checks the previously consumed character to determine if a valid escape sequence is present. Consequently, a closing parenthesis immediately following an escaped backslash sequence is treated as escaped by Crass, while spec-compliant web browsers treat the closing parenthesis as the end of the bad URL token. Downstream CSS sanitizers such as Sanitize, Loofah, and rails-html-sanitizer that rely on Crass to parse and reserialize untrusted CSS can be bypassed to inject arbitrary CSS declarations, style rules, and external @import directives.
Tornado versions prior to 6.6.0 contain an inefficient algorithmic complexity vulnerability in the HTTP header parser. When processing requests with obsolete line folding (obs-fold), the HTTPHeaders.parse_line method repeatedly concatenates immutable Python strings within a list structure. An unauthenticated remote attacker can send an HTTP request containing thousands of short header continuation lines to trigger quadratic O(N^2) CPU consumption on the main IOLoop thread, starving concurrent connections and resulting in a denial of service.
Tornado versions prior to 6.6.0 contain an open redirect vulnerability (CWE-601) in tornado.web.RedirectHandler. When route templates incorporate regular expression capture groups at the start of a path, directly after a fixed host without a trailing slash, or at the beginning of a destination template, unvalidated URL-decoded parameters allow attackers to manipulate the redirect scheme or network location. Because modern browsers normalize URLs according to the WHATWG specification—treating backslashes as forward slashes and stripping control characters—attackers can bypass naive prefix checks and redirect victims to arbitrary external domains.