spring-projects/spring-security · error · RequestRejectedException

Un-normalized paths are not supported: " +…

Error message

Un-normalized paths are not supported: " + firewalledRequest.getServletPath() + pathInfo

What it means

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.

Solutions

  1. Normalize the URL at the proxy/gateway or client before it reaches the app (resolve dot segments, collapse duplicate slashes, reject encoded dots)
  2. 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
  3. 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
  4. 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

Example fix

# nginx before
proxy_pass http://app$uri;  # may forward /a/../b or //a
# after (normalize in nginx)
merge_slashes on;
# and reject dot segments:
if ($request_uri ~* \.\./) { return 400; }
proxy_pass http://app$normalized_uri;
Defensive patterns

Strategy: try-catch

Validate before calling

String sp = request.getServletPath(), pi = request.getPathInfo();
String full = (sp == null ? "" : sp) + (pi == null ? "" : pi);
boolean normalized = !full.contains("/../") && !full.contains("/./") && !full.contains("//");

Try / catch

try {
    FirewalledRequest fw = firewall.getFirewalledRequest(request);
    chain.doFilter(fw, response);
} catch (RequestRejectedException e) {
    log.warn("Rejected un-normalized path: {}", request.getRequestURI());
    response.sendError(HttpServletResponse.SC_BAD_REQUEST);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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


AI-assisted analysis of spring-projects/spring-security@96852e8860 (2026-09-10). Data as JSON: /api/errors/13308d3ec7c40da8. Report an issue: GitHub.

Appendix: source

Thrown at web/src/main/java/org/springframework/security/web/firewall/DefaultHttpFirewall.java:55

 * valid paths which contain semi-colons.
 * <p>
 * If any un-normalized paths are found (containing directory-traversal character
 * sequences), the request will be rejected immediately. Most containers normalize the
 * paths before performing the servlet-mapping, but again this is not guaranteed by the
 * servlet spec.
 *
 * @author Luke Taylor
 * @see StrictHttpFirewall
 */
public class DefaultHttpFirewall implements HttpFirewall {

	private boolean allowUrlEncodedSlash;

	@Override
	public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {
		FirewalledRequest firewalledRequest = new RequestWrapper(request);
		if (!isNormalized(firewalledRequest.getServletPath()) || !isNormalized(firewalledRequest.getPathInfo())) {
			throw new RequestRejectedException(
					"Un-normalized paths are not supported: " + firewalledRequest.getServletPath()
							+ ((firewalledRequest.getPathInfo() != null) ? firewalledRequest.getPathInfo() : ""));
		}
		String requestURI = firewalledRequest.getRequestURI();
		if (containsInvalidUrlEncodedSlash(requestURI)) {
			throw new RequestRejectedException("The requestURI cannot contain encoded slash. Got " + requestURI);
		}
		return firewalledRequest;
	}

	@Override
	public HttpServletResponse getFirewalledResponse(HttpServletResponse response) {
		return new FirewalledResponse(response);
	}

	/**
	 * <p>
	 * Sets if the application should allow a URL encoded slash character.

View on GitHub (pinned to 96852e8860)