This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch 4.1.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/4.1.x-fixes by this push:
new 83cbcfb00df Fix bug in JSON parsing relating to escaped backslashes
(#3140)
83cbcfb00df is described below
commit 83cbcfb00df107a9706095d6e97c877cfa220b2a
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Mon May 25 13:12:51 2026 +0100
Fix bug in JSON parsing relating to escaped backslashes (#3140)
(cherry picked from commit beff5cc0f3c972c30807f3687fcb504fa4339d1a)
---
.../json/basic/JsonMapObjectReaderWriter.java | 12 +++++-
.../json/basic/JsonMapObjectReaderWriterTest.java | 43 ++++++++++++++++++++++
2 files changed, 54 insertions(+), 1 deletion(-)
diff --git
a/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
b/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
index a99e7c43e73..f6c8abe4145 100644
---
a/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
+++
b/rt/rs/extensions/json-basic/src/main/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriter.java
@@ -309,7 +309,17 @@ public class JsonMapObjectReaderWriter {
nextCurlyBracketIndex = i;
break;
} else if (currentChar == DQUOTE) {
- if (i > from && json.charAt(i - 1) == ESCAPE) {
+ // Count how many consecutive backslashes precede this quote.
+ // An odd count means the quote itself is escaped (e.g. \");
+ // an even count means the backslashes are paired escape
sequences
+ // and the quote is a real string delimiter (e.g. \\" =
escaped \ + closing ").
+ int backslashCount = 0;
+ int k = i - 1;
+ while (k >= from && json.charAt(k) == ESCAPE) {
+ backslashCount++;
+ k--;
+ }
+ if (backslashCount % 2 != 0) {
continue;
}
inString = !inString;
diff --git
a/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
b/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
index 9c66add08c1..c2908b1a75d 100644
---
a/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
+++
b/rt/rs/extensions/json-basic/src/test/java/org/apache/cxf/jaxrs/json/basic/JsonMapObjectReaderWriterTest.java
@@ -196,6 +196,49 @@ public class JsonMapObjectReaderWriterTest {
assertEquals("a\\", entry.getValue());
}
+ /**
+ * Regression test for a bug in {@code getNextSepCharIndex}: the method
only checks whether
+ * the single character immediately before a {@code "} is a backslash when
deciding whether
+ * the quote is escaped. That single-character look-back is wrong when a
string ends with
+ * {@code \\} (an escaped backslash): the second {@code \} is mistaken for
an escape prefix
+ * of the closing {@code "}, so the parser never exits "in-string" mode,
swallows the
+ * subsequent comma, and absorbs the rest of the JSON (including any
following keys) into
+ * the value of the preceding key.
+ *
+ * <p>Correct behaviour: {@code "\\"} in JSON is a string whose value is a
single backslash
+ * {@code \}. The {@code "} that closes it must <em>not</em> be treated
as escaped.
+ */
+ @Test
+ public void testReadStringValueEndingWithEscapedBackslashNotLastKey()
throws Exception {
+ // JSON: {"a":"\\","b":"w"}
+ // "a" has value \ (single backslash); "b" has value w.
+ // Bug: getNextSepCharIndex sees \ before the closing " of "\\" and
skips
+ // that quote, causing "b" to be swallowed into the value of "a".
+ String json = "{\"a\":\"\\\\\",\"b\":\"w\"}";
+ Map<String, Object> map = new
JsonMapObjectReaderWriter().fromJson(json);
+ assertEquals(2, map.size());
+ assertEquals("\\", map.get("a"));
+ assertEquals("w", map.get("b"));
+ }
+
+ /**
+ * Same bug as {@link
#testReadStringValueEndingWithEscapedBackslashNotLastKey} but with a
+ * security-relevant follow-on key, matching the attack scenario described
in the audit:
+ * a crafted value ending in {@code \\} causes a subsequent key such as
{@code "admin"} to
+ * disappear from the parsed map.
+ */
+ @Test
+ public void
testReadStringValueEndingWithEscapedBackslashDropsSubsequentKey() throws
Exception {
+ // JSON: {"role":"user\\","admin":true}
+ // "role" value is user\ (user + single backslash); "admin" value is
Boolean.TRUE.
+ // Bug: "admin" key is consumed as part of the "role" value and absent
from the result.
+ String json = "{\"role\":\"user\\\\\",\"admin\":true}";
+ Map<String, Object> map = new
JsonMapObjectReaderWriter().fromJson(json);
+ assertEquals(2, map.size());
+ assertEquals("user\\", map.get("role"));
+ assertEquals(Boolean.TRUE, map.get("admin"));
+ }
+
@Test
public void testAlreadyEscapedBackslash() throws Exception {
JsonMapObjectReaderWriter jsonMapObjectReaderWriter = new
JsonMapObjectReaderWriter();