-
Bug
-
Resolution: Done
-
Major
-
None
-
None
-
None
The cause of this is the Connector.setExchangeRequestPath method, that does not check for special characters in the query string. This method uses the requiresDecode to decide whether to decode the query string. Mistakenly, this is done without evaluating the characters in the query string:
for (int i = 0; i < encodedPath.length(); ++i) { char c = encodedPath.charAt(i); if(!allowUnescapedCharactersInUrl && !HttpRequestParser.isTargetCharacterAllowed(c)) { throw new BadRequestException(UndertowMessages.MESSAGES.invalidCharacterInRequestTarget(c)); } if (c == '?') { String part; String encodedPart = encodedPath.substring(currentPathPartIndex, i); if (requiresDecode) { part = URLUtils.decode(encodedPart, charset, decodeSlashFlag,false, decodeBuffer); } else { part = encodedPart; } pathBuilder.append(part); part = pathBuilder.toString(); exchange.setRequestPath(part); exchange.setRelativePath(part); if(requiresDecode && allowUnescapedCharactersInUrl) { final String uri = URLUtils.decode(encodedPath.substring(0, i), charset, decodeSlashFlag,false, decodeBuffer); exchange.setRequestURI(uri); } else { exchange.setRequestURI(encodedPath.substring(0, i)); } final String qs = encodedPath.substring(i + 1); if(requiresDecode && allowUnescapedCharactersInUrl) { final String decodedQS = URLUtils.decode(qs, charset, decodeSlashFlag,false, decodeBuffer); exchange.setQueryString(decodedQS); } else { exchange.setQueryString(qs); } URLUtils.parseQueryString(qs, exchange, charset, decodeQueryString, maxParameters); return; } else if(c == ';') { String part; String encodedPart = encodedPath.substring(currentPathPartIndex, i); if (requiresDecode) { part = URLUtils.decode(encodedPart, charset, decodeSlashFlag, false, decodeBuffer); } else { part = encodedPart; } pathBuilder.append(part); if(requiresDecode && allowUnescapedCharactersInUrl) { final String uri = URLUtils.decode(encodedPath, charset, decodeSlashFlag,false, decodeBuffer); exchange.setRequestURI(uri); } else { exchange.setRequestURI(encodedPath); } currentPathPartIndex = i + 1 + URLUtils.parsePathParams(encodedPath.substring(i + 1), exchange, charset, decode, maxParameters); i = currentPathPartIndex -1 ; } else if(decode && (c == '+' || c == '%' || c > 127)) { requiresDecode = decode; } }
As you can see in the code block above, requiresDecode is used indiscriminately to define if query string should be decoded. But query string (qs in the code above) is in the interval of the characters that have not been evaluated in the main loop, as only all characters until index i have been evaluated at this point.
- is incorporated by
-
WFCORE-7381 [CVE-2024-4109, CVE-2025-9784] Upgrade Undertow to 2.3.20.Final
-
- Resolved
-