spring-projects/spring-security · error · ServerExchangeRejectedException

The request was rejected because the header

Error message

The request was rejected because the header: "<key> " has a value "<value>" that is not allowed.

What it means

The firewall validates each header's value against the allowedHeaderValues predicate. A value that fails the test causes a ServerExchangeRejectedException naming the header key and offending value. This blocks CRLF injection and other header-value smuggling attacks.

Solutions

  1. Sanitize the header value on the client: strip CR/LF and control/non-ASCII characters before sending.
  2. Review the rejected value in logs and relax the setAllowedHeaderValues predicate if the value is legitimate (e.g. allow printable ASCII).
  3. Fix intermediary proxies/servers that append or rewrite the header with illegal characters.
  4. If it's an attack probe, block the source; the firewall is working as intended.

Example fix

// before: client sets raw user input in header
request.headers.set("X-Note", userInput); // may contain \n or control chars
// after
request.headers.set("X-Note",
    userInput.replaceAll("[\\r\\n\\x00-\\x1F]", ""));
Defensive patterns

Strategy: validation

Validate before calling

boolean isSafeHeaderValue(String value) {
    return value != null && value.matches("[\\x20-\\x7E]+") && !value.contains("\r") && !value.contains("\n");
}

Try / catch

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

Prevention

When it happens

Trigger: A request header (key) has a value failing allowedHeaderValues — typically values containing CR/LF, non-printable characters, non-ASCII text, or control characters inserted by clients or intermediaries.

Common situations: Users pasting multi-line content into a header value (e.g. custom tracing or locale headers); clients setting values with unencoded Unicode; proxies appending suspicious values; overly strict custom allowedHeaderValues predicates rejecting legitimate values after a config change.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

		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.");
		}
	}

	private void validateAllowedParameterValue(String name, String value) {
		if (!StrictServerWebExchangeFirewall.this.allowedParameterValues.test(value)) {
			throw new ServerExchangeRejectedException("The request was rejected because the parameter: \"" + name
					+ " \" has a value \"" + value + "\" that is not allowed.");
		}
	}

View on GitHub (pinned to 96852e8860)