Skip to content

Commit a37f594

Browse files
committed
Tests for fixes for previously undisclosed vulnerabilities
These include tests that reproduced fuzzer findings cqommunicated privately by Fabian Meumertzheim of codeintelligence. They were held back, separate from the fixes, until a release had time to propagate. Public disclosure at https://groups.google.com/g/json-sanitizer-support/c/dAW1AeNMoA0
1 parent 18bb943 commit a37f594

2 files changed

Lines changed: 144 additions & 1 deletion

File tree

src/test/java/com/google/json/FuzzyTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,32 @@ public static final void testSanitizerLikesFuzzyWuzzyInputs()
6262
String sanitized0 = JsonSanitizer.sanitize(fuzzyWuzzyString);
6363
String sanitized1 = JsonSanitizer.sanitize(sanitized0);
6464
// Test idempotence.
65+
if (!sanitized0.equals(sanitized1)) {
66+
int commonPrefixLen = 0;
67+
int minLength = Math.min(sanitized0.length(), sanitized1.length());
68+
while (commonPrefixLen < minLength) {
69+
if (sanitized0.charAt(commonPrefixLen) != sanitized1.charAt(commonPrefixLen)) {
70+
break;
71+
}
72+
++commonPrefixLen;
73+
}
74+
75+
int right0 = sanitized0.length();
76+
int right1 = sanitized1.length();
77+
while (right0 > commonPrefixLen && right1 > commonPrefixLen) {
78+
if (sanitized0.charAt(right0 - 1) != sanitized1.charAt(right1 - 1)) {
79+
break;
80+
}
81+
--right0;
82+
--right1;
83+
}
84+
85+
int commonSuffixLen = sanitized0.length() - right0;
86+
87+
System.err.println("Difference at " + commonPrefixLen + " to -" + commonSuffixLen);
88+
System.err.println("Before: " + excerpt(sanitized0, commonPrefixLen, right0));
89+
System.err.println("After: " + excerpt(sanitized0, commonPrefixLen, right1));
90+
}
6591
assertEquals(fuzzyWuzzyString + " => " + sanitized0, sanitized0,
6692
sanitized1);
6793
} catch (Throwable th) {
@@ -90,6 +116,23 @@ private static void hexDump(byte[] bytes, Appendable app)
90116
app.append("0123456789ABCDEF".charAt((b >>> 0) & 0xf));
91117
}
92118
}
119+
120+
private static String excerpt(String s, int left, int right) {
121+
int leftIncl = left - 10;
122+
boolean ellipseLeft = leftIncl > 0;
123+
if (!ellipseLeft) { leftIncl = 0; }
124+
125+
int rightIncl = right + 10;
126+
boolean ellipseRight = s.length() > rightIncl;
127+
if (!ellipseRight) {
128+
rightIncl = s.length();
129+
}
130+
131+
return s.substring(leftIncl, rightIncl)
132+
.replace("\r", "\\r")
133+
.replace("\n", "\\n")
134+
.replace("\\", "\\\\");
135+
}
93136
}
94137

95138
final class FuzzyStringGenerator implements Iterable<String> {

src/test/java/com/google/json/JsonSanitizerTest.java

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
import static com.google.json.JsonSanitizer.DEFAULT_NESTING_DEPTH;
1818
import static com.google.json.JsonSanitizer.sanitize;
19+
20+
import java.util.Locale;
1921
import java.util.logging.Level;
2022
import java.util.logging.Logger;
2123
import junit.framework.TestCase;
@@ -198,7 +200,7 @@ public static final void testMaximumNestingLevelAssignment() {
198200
}
199201

200202
@Test
201-
public static final void testClosedArray() {
203+
public static final void testUnopenedArray() {
202204
// Discovered by fuzzer with seed -Dfuzz.seed=df3b4778ce54d00a
203205
assertSanitized("-1742461140214282", "\ufeff-01742461140214282]");
204206
}
@@ -228,4 +230,102 @@ public static final void testHtmlParserStateChanges() {
228230

229231
assertSanitized("\"\\u003c!--\\u003cscript>\"", "\"<!--<script>\"");
230232
}
233+
234+
@Test
235+
public static final void testLongOctalNumberWithBadDigits() {
236+
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
237+
assertEquals(
238+
"-888888888888888888888",
239+
JsonSanitizer.sanitize("-0888888888888888888888")
240+
);
241+
}
242+
243+
@Test
244+
public static final void testLongNumberInUnclosedInputWithU80() {
245+
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
246+
assertEquals(
247+
"{\"\":{\"\":{\"\":{\"\":{\"\":{\"\":{\"x80\":{\"\":{\"\":[-400557869725698078427]}}}}}}}}}",
248+
JsonSanitizer.sanitize("{{{{{{{\\x80{{([-053333333304233333333333")
249+
);
250+
}
251+
252+
@Test
253+
public static final void testSlashFour() {
254+
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
255+
assertEquals("\"y\\u0004\"", JsonSanitizer.sanitize("y\\4")); // "y\4"
256+
}
257+
258+
@Test
259+
public static final void testUnterminatedObject() {
260+
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
261+
String input = "?\u0000\u0000\u0000{{\u0000\ufffd\u0003]ve{R]\u00000\ufffd\u0016&e{\u0003]\ufffda<!.b<!<!cc1x\u0000\u00005{281<\u0000.{t\u0001\ufffd5\ufffd{5\ufffd\ufffd0\ufffd15\r\ufffd\u0000\u0000\u0000~~-0081273222428822883223759,55\ufffd\u0000\ufffd\t\u0000\ufffd";
262+
String got = JsonSanitizer.sanitize(input);
263+
String want = "{\"\":{},\"ve\":{\"R\":null},\"0\":\"e\",\"\":{},\"a<!.b<!<!cc1x\":5,\"\":{\"281\":0.0,\"\":{\"t\":5,\"\":{\"5\":0,\"15\"\r:-81273222428822883223759,\"55\"\t:null}}}}";
264+
assertEquals(want, got);
265+
}
266+
267+
@Test
268+
public static final void testCrash1() {
269+
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
270+
String input = "?\u0000\u0000\u0000{{\u0000\ufffd\u0003]ve{R]\u00000\ufffd\ufffd\u0016&e{\u0003]\ufffda<!.b<!<!c\u00005{281<\u0000.{t\u0001\ufffd5\ufffd{515\r[\u0000\u0000\u0000~~-008127322242\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd23759,551x\u0000\u00006{281<\u0000.{t\u0001\ufffd5\ufffd{5\ufffd\ufffd0\ufffd15\r[\u0000\u0000\u0000~~-0081273222428822883223759,\ufffd";
271+
String want = "{\"\":{},\"ve\":{\"R\":null},\"0\":\"e\",\"\":{},\"a<!.b<!<!c\":5,\"\":{\"281\":0.0,\"\":{\"t\":5,\"\":{\"515\"\r:[-8127322242,23759,551,6,{\"281\":0.0,\"\":{\"t\":5,\"\":{\"5\":0,\"15\"\r:[-81273222428822883223759]}}}]}}}}";
272+
String got = JsonSanitizer.sanitize(input);
273+
assertEquals(want, got);
274+
}
275+
276+
@Test
277+
public static final void testDisallowedSubstrings() {
278+
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
279+
String[] inputs = {
280+
"x<\\script>",
281+
"x</\\script>",
282+
"x</sc\\ript>",
283+
"x<\\163cript>",
284+
"x</\\163cript>",
285+
"x<\\123cript>",
286+
"x</\\123cript>",
287+
"u\\u\\uu\ufffd\ufffd\\u7u\\u\\u\\u\ufffdu<\\script>5",
288+
"z\\<\\!--",
289+
"z\\<!\\--",
290+
"z\\<!-\\-",
291+
"z\\<\\!--",
292+
"\"\\]]\\>",
293+
};
294+
for (String input : inputs) {
295+
String out = JsonSanitizer.sanitize(input).toLowerCase(Locale.ROOT);
296+
assertFalse(out, out.contains("<!--"));
297+
assertFalse(out, out.contains("-->"));
298+
assertFalse(out, out.contains("<script"));
299+
assertFalse(out, out.contains("</script"));
300+
assertFalse(out, out.contains("]]>"));
301+
assertFalse(out, out.contains("<![cdata["));
302+
}
303+
}
304+
305+
@Test
306+
public static final void testXssPayload() {
307+
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
308+
String input = "x</\\script>u\\u\\uu\ufffd\ufffd\\u7u\\u\\u\\u\ufffdu<\\script>5+alert(1)//";
309+
assertEquals(
310+
"\"x\\u003c/script>uuuu\uFFFD\uFFFDu7uuuu\uFFFDu\\u003cscript>5+alert(1)//\"",
311+
JsonSanitizer.sanitize(input)
312+
);
313+
}
314+
315+
@Test
316+
public static final void testInvalidOutput() {
317+
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
318+
String input = "\u0010{'\u0000\u0000'\"\u0000\"{.\ufffd-0X29295909049550970,\n\n0";
319+
String want = "{\"\\u0000\\u0000\":\"\\u0000\",\"\":{\"0\":-47455995597866469744,\n\n\"0\":null}}";
320+
String got = JsonSanitizer.sanitize(input);
321+
assertEquals(want, got);
322+
}
323+
324+
@Test
325+
public static final void testBadNumber() {
326+
String input = "¶0x.\\蹃4\\À906";
327+
String want = "0.0";
328+
String got = JsonSanitizer.sanitize(input);
329+
assertEquals(want, got);
330+
}
231331
}

0 commit comments

Comments
 (0)