Handling invalid request target characters in Tomcat 8.5+ under RFC 7230/3986
Symptom
Upgrading to Tomcat 8.5+ (including the embedded Tomcat in Spring Boot) may reject requests whose path or query contains characters such as {, }, [, ], |, \ and others. A typical failure looks like:
java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:467)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:667)
...
Why it happens
Newer Tomcat releases enforce RFC 7230/3986 parsing rules more strictly. RFC 3986 limits unencoded characters in the request target to:
- Unreserved: A–Z, a–z, 0–9, '-', '.', '_', '~'
- Rseerved delimiters when used with proper semantics
- Everything else must be percent-encoded
Tomcat 8.5+ additionally blocks a conservative set of ASCII characters in the path and query unless explicitly allowed or percent-encoded. This commonly impacts braces {}, square brackets [], pipe |, backslash \ , caret ^, backtick `, double quote ", and angle brackets <>.
Remediation options
-
Encode on the client side (preferred)
- Ensure all dynamic path segments and query parameter values are percent-encoded.
- Examples:
- JavaScript (query values):
const raw = 'msg=name|id{}[]'; const url = '/api/search?q=' + encodeURIComponent(raw); fetch(url); - Java (query values):
String raw = "name|id{}[]"; String q = java.net.URLEncoder.encode(raw, java.nio.charset.StandardCharsets.UTF_8.name()); String url = "/api/search?q=" + q;
- JavaScript (query values):
-
Reconfigure Tomcat parsing (when encoding cannot be applied everywhere)
- Global (standalone Tomcat): add allowed characters via system property in conf/catalina.properties. Supported in Tomcat 7.0.76+, 8.0.42+, 8.5.12+; later versions deprecate this in favor of connector attributes.
# conf/catalina.properties tomcat.util.http.parser.HttpParser.requestTargetAllow=|{} - Connector attributes (Tomcat 8.5+): relax the validator for specific characters.
- server.xml example:
Note: In XML, backslash, quotes, and angle brackets must be escaped as shown; Tomcat interprets the actual characters at runtime.<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" relaxedPathChars="[]|" relaxedQueryChars="[]|{}^\`"<>" />
- server.xml example:
- Global (standalone Tomcat): add allowed characters via system property in conf/catalina.properties. Supported in Tomcat 7.0.76+, 8.0.42+, 8.5.12+; later versions deprecate this in favor of connector attributes.
-
Downgrade to Tomcat 7 (not recommended)
- Only as a temporary workaround; stricter parsing is more standards-compliant and safer.
Spring Boot embedded Tomcat configuration
Spring Boot 1.5.x
Define a customizer to set connector attributes at startup.
import org.apache.catalina.connector.Connector;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RelaxedCharsTomcatCustomizer implements EmbeddedServletContainerCustomizer {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
TomcatEmbeddedServletContainerFactory tomcat = (TomcatEmbeddedServletContainerFactory) container;
tomcat.addConnectorCustomizers((Connector conn) -> {
// Allow specific characters in query and path. Encode when possible.
conn.setAttribute("relaxedQueryChars", "[]|{}^\\`\"<>");
conn.setAttribute("relaxedPathChars", "[]|");
});
}
}
}
Spring Boot 2.x+
Use WebServerFactoryCustomizer with TomcatServletWebServerFactory.
import org.apache.catalina.connector.Connector;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TomcatWebServerConfig {
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> allowSpecialChars() {
return (TomcatServletWebServerFactory factory) ->
factory.addConnectorCustomizers((Connector conn) -> {
conn.setAttribute("relaxedQueryChars", "[]|{}^\\`\"<>");
conn.setAttribute("relaxedPathChars", "[]|");
});
}
}
Notes
- Use the smalest set of relaxed characters needed; allowing broad sets may increase security risk.
- The "relaxedQueryChars" and "relaxedPathChars" settings affect validation only; they do not decode. Applications must still handle encoded values correctly.
- Prefer percent-encoding for user input in query parameters and path segments instead of relying solely on parser relaxation.