spring-projects/spring-security · error · RequestRejectedException
The request was rejected because the URL was not normalized.
Error message
The request was rejected because the URL was not normalized.
What it means
StrictHttpFirewall rejects any request whose URL is not normalized: it checks the requestURI/contextPath/servletPath/pathInfo for dot-segments ('/./', '/../'), duplicate slashes, and other non-canonical forms. This is a deliberate hardening against path-traversal and authorization-bypass attacks; the request is rejected with RequestRejectedException before filtering.
Solutions
- Fix the URL at the source: normalize/rewrite at your reverse proxy (nginx: merge_slashes on; reject '..' patterns) or in the client/router
- Find the client producing un-normalized URLs from access logs and fix its URL construction (proper path joining instead of string concatenation)
- If a specific pattern is safe and required, use StrictHttpFirewall's configuration instead of reverting to DefaultHttpFirewall: e.g. setAllowUrlEncodedDoubleSlash/setAllowUrlEncodedPercent — note there is no option to allow dot-segments, so those must be normalized upstream
- Wrap with a custom firewall/filter that normalizes the request (HttpFirewall wrapper or Spring Cloud Gateway rewrite filter) before it hits StrictHttpFirewall
Example fix
// before
String url = baseUrl + "/" + path; // path may start with '/' or contain './'
// after
String url = UriComponentsBuilder.fromHttpUrl(baseUrl)
.path(path)
.build().normalize().toUriString(); Defensive patterns
Strategy: try-catch
Validate before calling
String uri = request.getRequestURI();
boolean normalized = uri.equals(URI.create(uri).normalize().getPath()) && !uri.contains("//"); Try / catch
try {
FirewalledRequest fw = strictFirewall.getFirewalledRequest(request);
chain.doFilter(fw, response);
} catch (RequestRejectedException e) {
audit.log("Rejected non-normalized URL", request.getRequestURI(), e.getMessage());
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
} Prevention
- Normalize all URLs at the edge (gateway/proxy rewrite rules) before they reach the app
- Use URI builders that call normalize() instead of string concatenation
- Set up alerting on RequestRejectedException to detect scanning traffic vs. broken clients
- Write smoke tests covering dot-segment and double-slash URLs through your full proxy chain
When it happens
Trigger: getFirewalledRequest sees a URI like '/a/../b', '/a/./b', '/a//b', or containing encoded dot variants; also fired when trailing '..' or '.' segments survive. Any request through FilterChainProxy with such a path is rejected.
Common situations: Crawlers or misbehaving clients sending dot-segment URLs; double-encoding by proxies turning %2e%2e into '..'; apps behind proxies that don't normalize; legitimate deep links with '//' from string-concatenated base URLs; frameworks generating '/foo/./bar' links.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- Un-normalized paths are not supported: " +…
- The request was rejected because the domain
- The request was rejected because the header name
- The request was rejected because the parameter name
- The request was rejected because the URL was not normalized
AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10).
Data as JSON: /api/errors/f7e0f7c074283f59.
Report an issue: GitHub.
Appendix: source
Thrown at web/src/main/java/org/springframework/security/web/firewall/StrictHttpFirewall.java:521
}
private void urlBlocklistsAddAll(Collection<String> values) {
this.encodedUrlBlocklist.addAll(values);
this.decodedUrlBlocklist.addAll(values);
}
private void urlBlocklistsRemoveAll(Collection<String> values) {
this.encodedUrlBlocklist.removeAll(values);
this.decodedUrlBlocklist.removeAll(values);
}
@Override
public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {
rejectForbiddenHttpMethod(request);
rejectedBlocklistedUrls(request);
rejectedUntrustedHosts(request);
if (!isNormalized(request)) {
throw new RequestRejectedException("The request was rejected because the URL was not normalized.");
}
rejectNonPrintableAsciiCharactersInFieldName(request.getRequestURI(), "requestURI");
return new StrictFirewalledRequest(request);
}
private void rejectNonPrintableAsciiCharactersInFieldName(String toCheck, String propertyName) {
if (!containsOnlyPrintableAsciiCharacters(toCheck)) {
throw new RequestRejectedException(String
.format("The %s was rejected because it can only contain printable ASCII characters.", propertyName));
}
}
private void rejectForbiddenHttpMethod(HttpServletRequest request) {
if (this.allowedHttpMethods == ALLOW_ANY_HTTP_METHOD) {
return;
}
if (!this.allowedHttpMethods.contains(request.getMethod())) {
throw new RequestRejectedException(View on GitHub (pinned to 96852e8860)