Skip to content

LDEV-6699 decodeFromURL(): keep a % that is not a valid escape instead of throwing - #20

Merged
michaeloffner merged 2 commits into
masterfrom
LDEV-6699-decodefromurl-percent
Oct 23, 2026
Merged

michaeloffner merged 2 commits into
masterfrom
LDEV-6699-decodefromurl-percent

Conversation

@GianTschingt

Copy link
Copy Markdown
Contributor

https://luceeserver.atlassian.net/browse/LDEV-6699 (follow-up to LDEV-4743 / #19)

decodeFromURL() (and guardDecode("url", …)) threw IllegalArgumentException: URLDecoder: Illegal hex characters in escape (%) pattern / Incomplete trailing escape (%) pattern for any % that does not start a valid escape, e.g. decodeFromURL("100%").

Cause: GuardDecode.decodeURL used Canonicalize.decode(), whose reflective call into Lucee's URLDecoder always fails (callMethod on a Class instead of a static call), so it fell back to the strict java.net.URLDecoder.

Fix:

  • decodeURL now uses the lenient Canonicalize.decodePercent() added in LDEV-4743 canonicalize(): keep a % that is not a valid escape instead of throwing #19 (now on master): valid %XX escapes (UTF-8) are decoded and any other % is kept as is.
  • + is still decoded to a space, as before (form decoding). It is replaced before the percent decoding, so %2B still decodes to +.
  • The now unused Canonicalize.decode() and its broken reflection are removed.

Tests: tests/LDEV6699.cfc (label guard): trailing %, % followed by non-hex, mixed valid escapes and bare %, UTF-8 (€), + / %2B, and an encodeForURL() round trip.

  • Against the Guard bundled with 7.1.2.184-RC: 4 of 5 specs error with the exception above.
  • With this build: the guard suite passes locally on 7.1.2.184-RC with 81 specs, 0 failures, 0 errors and 0 skipped. The existing DecodeFromURL, ESAPIDecode and LDEV4743 specs still pass.

Based on current master (after #19 was merged).

…d of throwing

decodeURL used Canonicalize.decode(), whose reflective call into Lucee's
URLDecoder always failed and fell back to java.net.URLDecoder, which throws
on a bare %. It now uses the lenient Canonicalize.decodePercent() from
LDEV-4743 after turning + into a space (form decoding as before; %2B still
decodes to +). The now unused Canonicalize.decode() is removed.
@michaeloffner
michaeloffner merged commit b210203 into master Oct 23, 2026
16 checks passed
@GianTschingt GianTschingt mentioned this pull request Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants