{"record":{"id":"13308d3ec7c40da8","repo":"spring-projects/spring-security","slug":"un-normalized-paths-are-not-supported-firewal","errorCode":null,"errorMessage":"Un-normalized paths are not supported: \" + firewalledRequest.getServletPath() + pathInfo","messagePattern":"Un-normalized paths are not supported: \" \\+ firewalledRequest\\.getServletPath\\(\\) \\+ pathInfo","errorType":"exception","errorClass":"RequestRejectedException","httpStatus":400,"severity":"error","filePath":"web/src/main/java/org/springframework/security/web/firewall/DefaultHttpFirewall.java","lineNumber":55,"sourceCode":" * valid paths which contain semi-colons.\n * <p>\n * If any un-normalized paths are found (containing directory-traversal character\n * sequences), the request will be rejected immediately. Most containers normalize the\n * paths before performing the servlet-mapping, but again this is not guaranteed by the\n * servlet spec.\n *\n * @author Luke Taylor\n * @see StrictHttpFirewall\n */\npublic class DefaultHttpFirewall implements HttpFirewall {\n\n\tprivate boolean allowUrlEncodedSlash;\n\n\t@Override\n\tpublic FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {\n\t\tFirewalledRequest firewalledRequest = new RequestWrapper(request);\n\t\tif (!isNormalized(firewalledRequest.getServletPath()) || !isNormalized(firewalledRequest.getPathInfo())) {\n\t\t\tthrow new RequestRejectedException(\n\t\t\t\t\t\"Un-normalized paths are not supported: \" + firewalledRequest.getServletPath()\n\t\t\t\t\t\t\t+ ((firewalledRequest.getPathInfo() != null) ? firewalledRequest.getPathInfo() : \"\"));\n\t\t}\n\t\tString requestURI = firewalledRequest.getRequestURI();\n\t\tif (containsInvalidUrlEncodedSlash(requestURI)) {\n\t\t\tthrow new RequestRejectedException(\"The requestURI cannot contain encoded slash. Got \" + requestURI);\n\t\t}\n\t\treturn firewalledRequest;\n\t}\n\n\t@Override\n\tpublic HttpServletResponse getFirewalledResponse(HttpServletResponse response) {\n\t\treturn new FirewalledResponse(response);\n\t}\n\n\t/**\n\t * <p>\n\t * Sets if the application should allow a URL encoded slash character.","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/web/src/main/java/org/springframework/security/web/firewall/DefaultHttpFirewall.java#L37-L73","documentation":"DefaultHttpFirewall rejects requests whose servletPath or pathInfo is not normalized (contain '.', '..', double slashes, or encoded variants like %2e). This is a canonicalization defense: application servers may normalize such paths differently than Spring Security, enabling path-traversal or authorization bypass. It throws RequestRejectedException before the request reaches the filter chain.","triggerScenarios":"A request arrives where getServletPath() or getPathInfo() contains un-normalized segments: '/foo/../bar', '/foo//bar', '/%2e%2e/', or path parameters after semicolons depending on container parsing. Called via FirewallFilter/FilterChainProxy's getFirewalledRequest.","commonSituations":"Proxies/CDNs forwarding double-encoded URLs (%252e); clients sending dot-segment paths; servlet containers that don't strip ';jsessionid' or trailing segments; reverse proxies not normalizing before forwarding; apps mounted behind Apache with mod_proxy passing encoded slashes.","solutions":["Normalize the URL at the proxy/gateway or client before it reaches the app (resolve dot segments, collapse duplicate slashes, reject encoded dots)","If your container/servlet version supports it, upgrade Tomcat/Jetty so the request is rejected or normalized upstream; DefaultHttpFirewall is a fallback, prefer StrictHttpFirewall with a compatibility layer","Temporarily relax by switching to DefaultHttpFirewall's allowUrlEncodedSlash only if that is the specific blocker — note it does NOT allow un-normalized dot paths; do not replace the firewall with a permissive one as a workaround","Rewrite requests in a servlet filter or at the load balancer (e.g. nginx: merge_slashes, proxy_pass with normalized URI) so paths are canonical"],"exampleFix":"# nginx before\nproxy_pass http://app$uri;  # may forward /a/../b or //a\n# after (normalize in nginx)\nmerge_slashes on;\n# and reject dot segments:\nif ($request_uri ~* \\.\\./) { return 400; }\nproxy_pass http://app$normalized_uri;","handlingStrategy":"try-catch","validationCode":"String sp = request.getServletPath(), pi = request.getPathInfo();\nString full = (sp == null ? \"\" : sp) + (pi == null ? \"\" : pi);\nboolean normalized = !full.contains(\"/../\") && !full.contains(\"/./\") && !full.contains(\"//\");","typeGuard":null,"tryCatchPattern":"try {\n    FirewalledRequest fw = firewall.getFirewalledRequest(request);\n    chain.doFilter(fw, response);\n} catch (RequestRejectedException e) {\n    log.warn(\"Rejected un-normalized path: {}\", request.getRequestURI());\n    response.sendError(HttpServletResponse.SC_BAD_REQUEST);\n}","preventionTips":["Normalize URLs at the reverse proxy before forwarding (merge slashes, reject dot segments)","Never build client URLs by raw string concatenation; use a URL builder with normalize()","Add integration tests for paths with '/../', '/./', and '//' through your proxy stack","Keep Spring Security and the servlet container versions aligned; upgrade containers rather than weakening the firewall"],"tags":["spring-security","firewall","url-normalization","request-rejected","security"],"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"}