spring-projects/spring-security · error · ServerExchangeRejectedException

The request was rejected because the domain

Error message

The request was rejected because the domain <hostName> is untrusted.

What it means

The firewall extracts the Host from the request URI and tests it against the configured allowedHostnames predicate. If the host is not allowed, the request is rejected with ServerExchangeRejectedException. This defends against host-header injection and cache-poisoning attacks.

Solutions

  1. Configure the firewall's allowedHostnames to include every legitimate hostname: firewall.setAllowedHostnames(hostname -> allowedSet.contains(hostname)).
  2. Add the new environment's hostname (staging/internal DNS) to the allowlist in configuration.
  3. Fix proxy/load-balancer settings that pass through the wrong Host header (use proxy_set_header Host $host).
  4. If intentional probing, block the client and ignore the rejection.

Example fix

// before: no host check configured, default rejects everything unusual
StrictServerWebExchangeFirewall firewall = new StrictServerWebExchangeFirewall();
// after
firewall.setAllowedHostnames(host ->
    host.equals("example.com") || host.equals("staging.example.com"));
Defensive patterns

Strategy: validation

Validate before calling

Set<String> allowed = Set.of("example.com", "staging.example.com");
boolean isHostAllowed(String host) {
    return host != null && allowed.contains(host.toLowerCase());
}

Try / catch

try {
    exchange = firewall.getFirewalledExchange(exchange);
} catch (ServerExchangeRejectedException e) {
    log.warn("Untrusted host rejected: {}", e.getMessage());
    return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
}

Prevention

When it happens

Trigger: A request arrives whose Host header (request.getURI().getHost()) fails the allowedHostnames predicate — e.g. firewall with no allowedHostnames configured (or a restrictive allowlist) receiving Host: <hostName> from a client, load balancer, or direct IP access.

Common situations: Accessing the app via localhost/IP/cluster-internal DNS while the allowlist only contains the public domain; forgetting to call setAllowedHostnames on the StrictServerWebExchangeFirewall bean; new staging environments with different hostnames; attackers probing with forged Host headers (correctly blocked).

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

			if (encodedUrlContains(request, forbidden)) {
				throw new ServerExchangeRejectedException(
						"The request was rejected because the URL contained a potentially malicious String \""
								+ forbidden + "\"");
			}
		}
		for (String forbidden : this.decodedUrlBlocklist) {
			if (decodedUrlContains(request, forbidden)) {
				throw new ServerExchangeRejectedException(
						"The request was rejected because the URL contained a potentially malicious String \""
								+ forbidden + "\"");
			}
		}
	}

	private void rejectedUntrustedHosts(ServerHttpRequest request) {
		String hostName = request.getURI().getHost();
		if (hostName != null && !this.allowedHostnames.test(hostName)) {
			throw new ServerExchangeRejectedException(
					"The request was rejected because the domain " + hostName + " is untrusted.");
		}
	}

	private static Set<HttpMethod> createDefaultAllowedHttpMethods() {
		Set<HttpMethod> result = new HashSet<>();
		result.add(HttpMethod.DELETE);
		result.add(HttpMethod.GET);
		result.add(HttpMethod.HEAD);
		result.add(HttpMethod.OPTIONS);
		result.add(HttpMethod.PATCH);
		result.add(HttpMethod.POST);
		result.add(HttpMethod.PUT);
		return result;
	}

	private boolean isNormalized(ServerHttpRequest request) {
		if (!isNormalized(request.getPath().value())) {

View on GitHub (pinned to 96852e8860)