Skip to content
Permalink
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mikesamuel committed Jan 12, 2021
1 parent 18bb943 commit a37f594
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 1 deletion.
43 changes: 43 additions & 0 deletions src/test/java/com/google/json/FuzzyTest.java
Expand Up @@ -62,6 +62,32 @@ public static final void testSanitizerLikesFuzzyWuzzyInputs()
String sanitized0 = JsonSanitizer.sanitize(fuzzyWuzzyString);
String sanitized1 = JsonSanitizer.sanitize(sanitized0);
// Test idempotence.
if (!sanitized0.equals(sanitized1)) {
int commonPrefixLen = 0;
int minLength = Math.min(sanitized0.length(), sanitized1.length());
while (commonPrefixLen < minLength) {
if (sanitized0.charAt(commonPrefixLen) != sanitized1.charAt(commonPrefixLen)) {
break;
}
++commonPrefixLen;
}

int right0 = sanitized0.length();
int right1 = sanitized1.length();
while (right0 > commonPrefixLen && right1 > commonPrefixLen) {
if (sanitized0.charAt(right0 - 1) != sanitized1.charAt(right1 - 1)) {
break;
}
--right0;
--right1;
}

int commonSuffixLen = sanitized0.length() - right0;

System.err.println("Difference at " + commonPrefixLen + " to -" + commonSuffixLen);
System.err.println("Before: " + excerpt(sanitized0, commonPrefixLen, right0));
System.err.println("After: " + excerpt(sanitized0, commonPrefixLen, right1));
}
assertEquals(fuzzyWuzzyString + " => " + sanitized0, sanitized0,
sanitized1);
} catch (Throwable th) {
Expand Down Expand Up @@ -90,6 +116,23 @@ private static void hexDump(byte[] bytes, Appendable app)
app.append("0123456789ABCDEF".charAt((b >>> 0) & 0xf));
}
}

private static String excerpt(String s, int left, int right) {
int leftIncl = left - 10;
boolean ellipseLeft = leftIncl > 0;
if (!ellipseLeft) { leftIncl = 0; }

int rightIncl = right + 10;
boolean ellipseRight = s.length() > rightIncl;
if (!ellipseRight) {
rightIncl = s.length();
}

return s.substring(leftIncl, rightIncl)
.replace("\r", "\\r")
.replace("\n", "\\n")
.replace("\\", "\\\\");
}
}

final class FuzzyStringGenerator implements Iterable<String> {
Expand Down
102 changes: 101 additions & 1 deletion src/test/java/com/google/json/JsonSanitizerTest.java
Expand Up @@ -16,6 +16,8 @@

import static com.google.json.JsonSanitizer.DEFAULT_NESTING_DEPTH;
import static com.google.json.JsonSanitizer.sanitize;

import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import junit.framework.TestCase;
Expand Down Expand Up @@ -198,7 +200,7 @@ public static final void testMaximumNestingLevelAssignment() {
}

@Test
public static final void testClosedArray() {
public static final void testUnopenedArray() {
// Discovered by fuzzer with seed -Dfuzz.seed=df3b4778ce54d00a
assertSanitized("-1742461140214282", "\ufeff-01742461140214282]");
}
Expand Down Expand Up @@ -228,4 +230,102 @@ public static final void testHtmlParserStateChanges() {

assertSanitized("\"\\u003c!--\\u003cscript>\"", "\"<!--<script>\"");
}

@Test
public static final void testLongOctalNumberWithBadDigits() {
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
assertEquals(
"-888888888888888888888",
JsonSanitizer.sanitize("-0888888888888888888888")
);
}

@Test
public static final void testLongNumberInUnclosedInputWithU80() {
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
assertEquals(
"{\"\":{\"\":{\"\":{\"\":{\"\":{\"\":{\"x80\":{\"\":{\"\":[-400557869725698078427]}}}}}}}}}",
JsonSanitizer.sanitize("{{{{{{{\\x80{{([-053333333304233333333333")
);
}

@Test
public static final void testSlashFour() {
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
assertEquals("\"y\\u0004\"", JsonSanitizer.sanitize("y\\4")); // "y\4"
}

@Test
public static final void testUnterminatedObject() {
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
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";
String got = JsonSanitizer.sanitize(input);
String want = "{\"\":{},\"ve\":{\"R\":null},\"0\":\"e\",\"\":{},\"a<!.b<!<!cc1x\":5,\"\":{\"281\":0.0,\"\":{\"t\":5,\"\":{\"5\":0,\"15\"\r:-81273222428822883223759,\"55\"\t:null}}}}";
assertEquals(want, got);
}

@Test
public static final void testCrash1() {
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
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";
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]}}}]}}}}";
String got = JsonSanitizer.sanitize(input);
assertEquals(want, got);
}

@Test
public static final void testDisallowedSubstrings() {
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
String[] inputs = {
"x<\\script>",
"x</\\script>",
"x</sc\\ript>",
"x<\\163cript>",
"x</\\163cript>",
"x<\\123cript>",
"x</\\123cript>",
"u\\u\\uu\ufffd\ufffd\\u7u\\u\\u\\u\ufffdu<\\script>5",
"z\\<\\!--",
"z\\<!\\--",
"z\\<!-\\-",
"z\\<\\!--",
"\"\\]]\\>",
};
for (String input : inputs) {
String out = JsonSanitizer.sanitize(input).toLowerCase(Locale.ROOT);
assertFalse(out, out.contains("<!--"));
assertFalse(out, out.contains("-->"));
assertFalse(out, out.contains("<script"));
assertFalse(out, out.contains("</script"));
assertFalse(out, out.contains("]]>"));
assertFalse(out, out.contains("<![cdata["));
}
}

@Test
public static final void testXssPayload() {
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
String input = "x</\\script>u\\u\\uu\ufffd\ufffd\\u7u\\u\\u\\u\ufffdu<\\script>5+alert(1)//";
assertEquals(
"\"x\\u003c/script>uuuu\uFFFD\uFFFDu7uuuu\uFFFDu\\u003cscript>5+alert(1)//\"",
JsonSanitizer.sanitize(input)
);
}

@Test
public static final void testInvalidOutput() {
// Found by Fabian Meumertzheim using CI Fuzz (https://www.code-intelligence.com)
String input = "\u0010{'\u0000\u0000'\"\u0000\"{.\ufffd-0X29295909049550970,\n\n0";
String want = "{\"\\u0000\\u0000\":\"\\u0000\",\"\":{\"0\":-47455995597866469744,\n\n\"0\":null}}";
String got = JsonSanitizer.sanitize(input);
assertEquals(want, got);
}

@Test
public static final void testBadNumber() {
String input = "¶0x.\\蹃4\\À906";
String want = "0.0";
String got = JsonSanitizer.sanitize(input);
assertEquals(want, got);
}
}

0 comments on commit a37f594

Please sign in to comment.