From: Daniel Owens via Fulldisclosure <fulldisclosure () seclists org>
Date: Thu, 29 Oct 2026 11:34:48 +0000
Description
The Apache Struts2 REST Plugin's `DefaultContentTypeHandlerManager.getHandlerForResponse(HttpServletRequest,
HttpServletResponse)` splits the `Accept` header on commas and passes each resulting token directly to
`findHandler(String)` without trimming leading or trailing whitespace. `findHandler(String)` only retries a trimmed
lookup when a token contains a semicolon (`;`), so a token that merely carries a leading space has no such fallback and
fails the direct map lookup.
Impact
Any client that sends a standard, comma-space-separated `Accept` header -- the typical of most Hypertext Transfer
Protocol (HTTP) client libraries -- triggers this. As the lookup fails silently, `getHandlerForResponse()` falls
through to the `defaultExtension` handler instead of the content type the caller actually requested, silently returning
a representation that the client neither asked for nor can necessarily parse. In deployments that rely on content
negotiation to select between differently-scoped representations of the same resource -- such as a minimal public
representation served as the default extension against a fuller representation only intended for a specific,
explicitly-requested type -- this fallback can cause the wrong representation to be returned, degrading
interoperability and, where the two representations differ in which fields they expose, create a data-exposure
vulnerability (insecure serialisation). While attackers cannot choose the default representation, they can abuse this
to search for insecure serialisation, data exposures, and similar information disclosure issues, as well as to see if
there is a difference between various representations and the default. Importantly, the default representation and
ensuing serialisation library can be used against the information system (a trivial task).
Examples
Sample Code
`getHandlerForResponse(HttpServletRequest, HttpServletResponse)` splits the raw `Accept` header on commas and sends
each token to `findHandler(String)`, whose direct map lookup only has a trimming fallback when the token contains a
semicolon, as shown below.
```java
/**
* Gets the handler for the response by looking at the extension of the request
* @param request The request
* @return The appropriate handler
*
* WW-4588: modified to get a handler for the response side and auto generate the response type
* from the Accept: header
*
*/
@Override
public ContentTypeHandler getHandlerForResponse(HttpServletRequest request, HttpServletResponse res) {
String extension = getExtensionIfPresent(request.getRequestURI());
if (extension == null) {
extension = defaultExtension;
final String acceptHeader = request.getHeader("accept") ;
if (acceptHeader != null) {
final String[] types = acceptHeader.split(",");
for (final String type : types) {
final ContentTypeHandler handler = findHandler(type);
if (handler != null) {
return handler;
}
}
}
}
return handlersByExtension.get(extension);
}
private ContentTypeHandler findHandler(final String type) {
ContentTypeHandler handler = handlersByContentType.get(type);
if (handler == null) {
// strip off encoding and search again (e.g., application/json;charset=ISO-8859-1)
final int index = type.indexOf(';');
if (index != -1) {
return handlersByContentType.get(type.substring(0, index).trim());
}
}
return handler;
}
```
Code snippet from `struts2-rest-plugin`'s
plugins/rest/src/main/java/org/apache/struts2/rest/DefaultContentTypeHandlerManager.java, lines 128-158
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/
Current thread:
- Apache Struts2 REST Plugin Untrimmed `Accept` Header Tokens Break Content Negation Fallback Daniel Owens via Fulldisclosure (Nov 01)