This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/main by this push:
new fd8674cfc7c escape raw quotes after an escaped backslash in escapeJson
(#3167)
fd8674cfc7c is described below
commit fd8674cfc7cee4eb6af9fddebbf6723d44af1f12
Author: Javid Khan <[email protected]>
AuthorDate: Wed Jun 3 11:47:55 2026 +0530
escape raw quotes after an escaped backslash in escapeJson (#3167)
---
.../jaxrs/json/basic/JsonMapObjectReaderWriter.java | 20 +++++++++++++-------
.../json/basic/JsonMapObjectReaderWriterTest.java | 20 ++++++++++++++++++++
2 files changed, 33 insertions(+), 7 deletions(-)
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 117c6692c4c..22cf717f8d7 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
@@ -551,7 +551,8 @@ public class JsonMapObjectReaderWriter {
private String escapeJson(String value) {
StringBuilder sb = new StringBuilder();
- for (int i = 0; i < value.length(); i++) {
+ int i = 0;
+ while (i < value.length()) {
char c = value.charAt(i);
if (c < 0x20) {
// RFC 8259 section 7: all control characters (U+0000–U+001F)
MUST be escaped.
@@ -563,15 +564,20 @@ public class JsonMapObjectReaderWriter {
case '\r': sb.append("\\r"); break;
default: sb.append(String.format("\\u%04x", (int) c)); break;
}
- // If we have " and the previous char was not \ then escape it
- } else if (c == '"' && (i == 0 || value.charAt(i - 1) != '\\')) {
- sb.append('\\').append(c);
- // If we have \ and the previous char was not \ and the next char
is not an escaped char, then escape it
- } else if (c == '\\' && (i == 0 || value.charAt(i - 1) != '\\')
- && (i == value.length() - 1 ||
!isEscapedChar(value.charAt(i + 1)))) {
+ i++;
+ // A \ that introduces an existing escape sequence (\" \\ \/ \b \f
\n \r \t) is
+ // consumed together with the following char so it is not
re-escaped. Looking only
+ // at the previous char misclassifies a " or \ that follows a
complete \\ pair as
+ // already escaped, leaving it raw and breaking out of the JSON
string.
+ } else if (c == '\\' && i + 1 < value.length() &&
isEscapedChar(value.charAt(i + 1))) {
+ sb.append(c).append(value.charAt(i + 1));
+ i += 2;
+ } else if (c == '"' || c == '\\') {
sb.append('\\').append(c);
+ i++;
} else {
sb.append(c);
+ i++;
}
}
return sb.toString();
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 124a9b1669a..034cc98b7c0 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
@@ -282,6 +282,26 @@ public class JsonMapObjectReaderWriterTest {
assertEquals("a\\", entry.getValue());
}
+ /**
+ * Writer-side counterpart of {@link
#testReadStringValueEndingWithEscapedBackslashDropsSubsequentKey}.
+ * {@code escapeJson} only looked at the single character before a {@code
"}/{@code \} to decide
+ * whether it was already escaped, so a value ending in an escaped
backslash pair ({@code \\})
+ * followed by content left the next quote raw, breaking out of the JSON
string.
+ */
+ @Test
+ public void testEscapeQuoteAfterEscapedBackslash() throws Exception {
+ JsonMapObjectReaderWriter jsonMapObjectReaderWriter = new
JsonMapObjectReaderWriter();
+ Map<String, Object> content = new LinkedHashMap<>();
+ // value is: \ (escaped backslash) followed by a raw quote and an
injected key
+ content.put("role", "user\\\\\",\"admin\":true");
+ String json = jsonMapObjectReaderWriter.toJson(content);
+
+ Map<String, Object> map = jsonMapObjectReaderWriter.fromJson(json);
+ assertEquals(1, map.size());
+ assertEquals("user\\\",\"admin\":true", map.get("role"));
+ assertNull(map.get("admin"));
+ }
+
/**
* Regression test for "[MEDIUM] Unicode Escapes Not Decoded — Potential
Bypass".
*