{"record":{"id":"2a94d1a5cc418f17","repo":"perwendel/spark","slug":"bad-uri-encoding","errorCode":null,"errorMessage":"Bad URI % encoding","messagePattern":"Bad URI % encoding","errorType":"exception","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/spark/utils/urldecoding/UrlDecode.java","lineNumber":56,"sourceCode":"                switch (c) {\n                    case '%':\n                        if (builder == null) {\n                            builder = new Utf8StringBuilder(path.length());\n                            builder.append(path, offset, i - offset);\n                        }\n                        if ((i + 2) < end) {\n                            char u = path.charAt(i + 1);\n                            if (u == 'u') {\n                                // TODO this is wrong. This is a codepoint not a char\n                                builder.append((char) (0xffff & TypeUtil.parseInt(path, i + 2, 4, 16)));\n                                i += 5;\n                            } else {\n                                builder.append((byte) (0xff & (TypeUtil.convertHexDigit(u) * 16\n                                    + TypeUtil.convertHexDigit(path.charAt(i + 2)))));\n                                i += 2;\n                            }\n                        } else {\n                            throw new IllegalArgumentException(\"Bad URI % encoding\");\n                        }\n\n                        break;\n\n                    case ';':\n                        if (builder == null) {\n                            builder = new Utf8StringBuilder(path.length());\n                            builder.append(path, offset, i - offset);\n                        }\n\n                        while (++i < end) {\n                            if (path.charAt(i) == '/') {\n                                builder.append('/');\n                                break;\n                            }\n                        }\n\n                        break;","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/perwendel/spark/blob/1973e402f5d4c1442ad34a1d38ed0758079f7773/src/main/java/spark/utils/urldecoding/UrlDecode.java#L38-L74","documentation":"UrlDecode.path throws IllegalArgumentException('Bad URI % encoding') when a '%' in a URI path is not followed by two valid hex digits. The decoder requires each %XX triple to be well-formed; anything else is a malformed URI.","triggerScenarios":"Requesting a path containing a bare '%' or an incomplete escape like '/foo%2' or '/foo%zz'; the character after '%' is a reserved char that the decoder rejects instead of treating as a valid escape.","commonSituations":"Clients copying un-encoded URLs containing '%' (e.g. SQL LIKE patterns, format strings) into request paths; proxies/gateways double-decoding URIs; broken template interpolation producing '%{' sequences.","solutions":["Percent-encode the literal '%' as '%25' in client-supplied paths.","Catch IllegalArgumentException in the request pipeline and respond with HTTP 400 Bad Request.","Normalize/validate incoming URIs at an outer layer (filter/proxy) before decoding.","Fix client-side escaping by running the path through proper URL encoding."],"exampleFix":"// before\nString path = \"/files/100%done.txt\";\n// after\nString path = URLEncoder.encode(\"/files/100%done.txt\", StandardCharsets.UTF_8)\n                        .replace(\"%2F\", \"/\"); // '%' becomes %25","handlingStrategy":"try-catch","validationCode":"boolean hasValidEscapes(String path) {\n    for (int i = 0; i < path.length(); i++)\n        if (path.charAt(i) == '%') {\n            if (i + 2 >= path.length()) return false;\n            if (Character.digit(path.charAt(i+1), 16) < 0 || Character.digit(path.charAt(i+2), 16) < 0) return false;\n            i += 2;\n        }\n    return true;\n}","typeGuard":null,"tryCatchPattern":"try {\n    String decoded = UrlDecode.path(rawPath);\n} catch (IllegalArgumentException e) {\n    response.status(400);\n    return \"Bad request: malformed URI encoding\";\n}","preventionTips":["Always %-encode literal '%' as '%25' in URLs.","Sanitize incoming paths at a filter/proxy layer before decoding.","Use standard client-side URL encoding when building links.","Add a route-level guard that maps IllegalArgumentException to HTTP 400."],"tags":["uri","url-decoding","illegal-argument"],"backgroundTag":"invalid-url-format","analyzedSha":"1973e402f5d4c1442ad34a1d38ed0758079f7773","analyzedAt":"2026-09-10T14:38:22.866Z","contentChangedAt":"2026-09-10T14:38:22.866Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}