{"record":{"id":"23a6462bae30c0d2","repo":"spring-projects/spring-security","slug":"the-request-was-rejected-because-the-url-was-not-n-23a646","errorCode":null,"errorMessage":"The request was rejected because the URL was not normalized","messagePattern":"The request was rejected because the URL was not normalized","errorType":"exception","errorClass":"ServerExchangeRejectedException","httpStatus":400,"severity":"error","filePath":"web/src/main/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewall.java","lineNumber":195,"sourceCode":"\t}\n\n\tpublic Set<String> getEncodedUrlBlocklist() {\n\t\treturn this.encodedUrlBlocklist;\n\t}\n\n\tpublic Set<String> getDecodedUrlBlocklist() {\n\t\treturn this.decodedUrlBlocklist;\n\t}\n\n\t@Override\n\tpublic Mono<ServerWebExchange> getFirewalledExchange(ServerWebExchange exchange) {\n\t\treturn Mono.fromCallable(() -> {\n\t\t\tServerHttpRequest request = exchange.getRequest();\n\t\t\trejectForbiddenHttpMethod(request);\n\t\t\trejectedBlocklistedUrls(request);\n\t\t\trejectedUntrustedHosts(request);\n\t\t\tif (!isNormalized(request)) {\n\t\t\t\tthrow new ServerExchangeRejectedException(\n\t\t\t\t\t\t\"The request was rejected because the URL was not normalized\");\n\t\t\t}\n\n\t\t\texchange.getResponse().beforeCommit(() -> Mono.fromRunnable(() -> {\n\t\t\t\tServerHttpResponse response = exchange.getResponse();\n\t\t\t\tHttpHeaders headers = response.getHeaders();\n\t\t\t\theaders.forEach((headerName, headerValues) -> {\n\t\t\t\t\tfor (String headerValue : headerValues) {\n\t\t\t\t\t\tvalidateCrlf(headerName, headerValue);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}));\n\t\t\treturn new StrictFirewallServerWebExchange(exchange);\n\t\t});\n\t}\n\n\tprivate static void validateCrlf(String name, String value) {\n\t\tAssert.isTrue(!hasCrlf(name) && !hasCrlf(value), () -> \"Invalid characters (CR/LF) in header \" + name);","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/web/src/main/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewall.java#L177-L213","documentation":"StrictServerWebExchangeFirewall (WebFlux equivalent of StrictHttpFirewall) checks that the request URL is normalized — no directory traversal segments like /../, double slashes, or dot segments. If isNormalized(URI) fails, it throws ServerExchangeRejectedException and refuses the exchange. This blocks path-traversal and URL-obfuscation attacks at the edge of the filter chain.","triggerScenarios":"A request arrives whose path contains non-normalized segments: /../, /./, double slashes (except after scheme), backslashes, or encoded equivalents that Spring's UriComponentsBuilder normalization flags.","commonSituations":"Scanners/probing tools sending traversal-style URLs; front-end proxies rewriting paths incorrectly (e.g. double-encoding); clients appending extra slashes or dot segments; legacy clients with hand-built URLs.","solutions":["Find the offending URL in the exception/access logs and fix the client to send normalized paths.","Normalize at the proxy: configure nginx/Apache to merge slashes and resolve dot segments before forwarding.","Re-check any recent proxy or gateway config changes that may double-encode paths (e.g. proxy_pass without proper decoding).","As a last resort relax specific checks (setAllowUrlEncodedDoubleSlash / setStrictHttpFirewall equivalents on the ServerWebExchange firewall bean), understanding the security tradeoff."],"exampleFix":"// before\n// client calls GET /api//v1/../v1/users\n// after\n// client calls GET /api/v1/users\n// and/or configure the proxy to normalize:\n// nginx: merge_slashes on; before proxy_pass;","handlingStrategy":"validation","validationCode":"// Client-side normalization guard (Java)\nURI uri = URI.create(rawUrl).normalize();\nif (rawUrl.contains(\"../\") || rawUrl.contains(\"//\") || !uri.getPath().equals(new URI(uri.normalize()).getPath())) {\n    throw new IllegalArgumentException(\"URL must be normalized: \" + rawUrl);\n}","typeGuard":null,"tryCatchPattern":"// WebFlux error handling\n@Component\nclass RejectedExchangeHandler implements WebExceptionHandler {\n    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {\n        if (ex instanceof ServerExchangeRejectedException) {\n            exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);\n            return exchange.getResponse().setComplete();\n        }\n        return Mono.error(ex);\n    }\n}","preventionTips":["Enable path merging/normalization on reverse proxies","Never concatenate user input into URL paths unvalidated","Monitor rejected-request logs for probing activity","Keep clients on library-generated URIs (UriComponentsBuilder.normalize)"],"tags":["spring-security","webflux","firewall","path-traversal","url-normalization"],"backgroundTag":"path-traversal-blocked","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}