This is an automated email from the ASF dual-hosted git repository. joerghoh pushed a commit to branch SLING-13366 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-engine.git
commit 8f46f1d1d142963576d6cedf4735b60fab8e583d Author: Joerg Hoh <[email protected]> AuthorDate: Fri Sep 25 14:33:18 2026 +0200 SLING-13366 don't log un-escaped input --- .../apache/sling/engine/impl/parameters/Util.java | 25 +++++++++++++++++++++- .../sling/engine/impl/parameters/UtilTest.java | 22 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/apache/sling/engine/impl/parameters/Util.java b/src/main/java/org/apache/sling/engine/impl/parameters/Util.java index 03d0852..4e0a4ac 100644 --- a/src/main/java/org/apache/sling/engine/impl/parameters/Util.java +++ b/src/main/java/org/apache/sling/engine/impl/parameters/Util.java @@ -360,11 +360,34 @@ public class Util { final int hi = hexDigit(chCode[0]); final int lo = hexDigit(chCode[1]); if (hi < 0 || lo < 0) { - throw new IllegalArgumentException("Bad escape sequence: %" + new String(chCode)); + throw new IllegalArgumentException("Bad escape sequence: %" + toSafeString(chCode)); } return (hi << 4) + lo; } + /** + * Returns a representation of the given raw request input that is safe to + * embed in exception and, transitively, log messages: every character + * outside the printable US-ASCII range - in particular CR and LF, which + * would split a log record into what looks like two separate, + * attacker-authored entries - is replaced by its unicode escape. Raw, + * unvalidated request bytes must never reach a log message unneutralized. + * + * @param raw the raw input characters + * @return a printable representation of {@code raw} + */ + private static String toSafeString(final char[] raw) { + final StringBuilder sb = new StringBuilder(raw.length); + for (final char c : raw) { + if (c >= 0x20 && c < 0x7f) { + sb.append(c); + } else { + sb.append(String.format("\\u%04x", (int) c)); + } + } + return sb.toString(); + } + private static int hexDigit(final char c) { if (c >= '0' && c <= '9') { return c - '0'; diff --git a/src/test/java/org/apache/sling/engine/impl/parameters/UtilTest.java b/src/test/java/org/apache/sling/engine/impl/parameters/UtilTest.java index 7bde849..963f79c 100644 --- a/src/test/java/org/apache/sling/engine/impl/parameters/UtilTest.java +++ b/src/test/java/org/apache/sling/engine/impl/parameters/UtilTest.java @@ -172,4 +172,26 @@ public class UtilTest extends TestCase { } } } + + public void test_bad_escape_sequence_message_is_sanitized() throws Exception { + // raw CR/LF bytes after the '%' escape, as they may occur in an + // application/x-www-form-urlencoded POST body; the exception message + // (which ends up in the error log) must not carry them unneutralized, + // otherwise the attacker can split the log record (CVE-2022-32549 class) + final String query = "a=%\r\n&b=2"; + try { + Util.parseQueryString( + new ByteArrayInputStream(query.getBytes(Util.ENCODING_DIRECT)), + Util.ENCODING_DIRECT, + new ParameterMap(), + false); + fail("Expected IllegalArgumentException for the bad escape sequence"); + } catch (IllegalArgumentException expected) { + final String message = expected.getMessage(); + assertFalse("message must not contain a raw CR", message.contains("\r")); + assertFalse("message must not contain a raw LF", message.contains("\n")); + assertTrue("message must contain the escaped CR", message.contains("\\u000d")); + assertTrue("message must contain the escaped LF", message.contains("\\u000a")); + } + } }
