spring-projects/spring-security · error · ServerExchangeRejectedException

The request was rejected because the header name

Error message

The request was rejected because the header name "<headerNames>" is not allowed.

What it means

The firewall validates every request header name against the allowedHeaderNames predicate. A header whose name fails the predicate is rejected with ServerExchangeRejectedException. This blocks header-injection attacks using malformed or illegal header names.

Solutions

  1. Inspect the rejected header name in the logs and remove/fix it on the client that sends it.
  2. If the header is legitimate, widen allowedHeaderNames via firewall.setAllowedHeaderNames(name -> name.matches("[a-zA-Z0-9-]+")) or similar safe pattern.
  3. Fix proxy/middleware config that injects malformed header names.
  4. Encode the header name to valid HTTP token characters at the source.

Example fix

// before
StrictServerWebExchangeFirewall firewall = new StrictServerWebExchangeFirewall();
// after: allow standard token header names plus a custom one
firewall.setAllowedHeaderNames(name ->
    name.matches("[A-Za-z0-9-]+") || name.equals("X-Custom-Id"));
Defensive patterns

Strategy: validation

Validate before calling

boolean isSafeHeaderName(String name) {
    return name != null && name.matches("[A-Za-z0-9-]+") && name.length() <= 128;
}

Try / catch

try {
    exchange = firewall.getFirewalledExchange(exchange);
} catch (ServerExchangeRejectedException e) {
    log.warn("Rejected header name: {}", e.getMessage());
    return ResponseEntity.badRequest().build();
}

Prevention

When it happens

Trigger: A request carries a header whose name does not pass allowedHeaderNames — e.g. custom headers with invalid characters, headers containing non-ASCII or control characters, or a default predicate rejecting the name of a header a client/proxy adds.

Common situations: Clients sending unusual custom headers (X-Foo with weird casing/characters) during migration from a less strict setup; middleware adding headers the firewall's default predicate rejects; upgrading Spring Security where default header-name rules tightened; typo'd header names generated dynamically.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at web/src/main/java/org/springframework/security/web/server/firewall/StrictServerWebExchangeFirewall.java:635

		return result;
	}

	private boolean isNormalized(ServerHttpRequest request) {
		if (!isNormalized(request.getPath().value())) {
			return false;
		}
		if (!isNormalized(request.getURI().getRawPath())) {
			return false;
		}
		if (!isNormalized(request.getURI().getPath())) {
			return false;
		}
		return true;
	}

	private void validateAllowedHeaderName(String headerNames) {
		if (!StrictServerWebExchangeFirewall.this.allowedHeaderNames.test(headerNames)) {
			throw new ServerExchangeRejectedException(
					"The request was rejected because the header name \"" + headerNames + "\" is not allowed.");
		}
	}

	private void validateAllowedHeaderValue(Object key, @Nullable String value) {
		if (!StrictServerWebExchangeFirewall.this.allowedHeaderValues.test(value)) {
			throw new ServerExchangeRejectedException("The request was rejected because the header: \"" + key
					+ " \" has a value \"" + value + "\" that is not allowed.");
		}
	}

	private void validateAllowedParameterName(String name) {
		if (!StrictServerWebExchangeFirewall.this.allowedParameterNames.test(name)) {
			throw new ServerExchangeRejectedException(
					"The request was rejected because the parameter name \"" + name + "\" is not allowed.");
		}
	}

View on GitHub (pinned to 96852e8860)