diff --git a/java/src/org/openqa/selenium/json/JsonInput.java b/java/src/org/openqa/selenium/json/JsonInput.java index 4f4220f78fe0c..d40fb51f2b7b2 100644 --- a/java/src/org/openqa/selenium/json/JsonInput.java +++ b/java/src/org/openqa/selenium/json/JsonInput.java @@ -585,6 +585,12 @@ private String readString() { readEscape(builder); break; default: + // RFC 8259 §7: characters U+0000..U+001F MUST be escaped. + if (c < 0x20) { + throw new JsonException( + String.format( + "Illegal unescaped control character U+%04X in string. %s", c, input)); + } builder.append((char) c); } } diff --git a/java/test/org/openqa/selenium/json/JsonInputTest.java b/java/test/org/openqa/selenium/json/JsonInputTest.java index 73245c604e28a..99737c49b8618 100644 --- a/java/test/org/openqa/selenium/json/JsonInputTest.java +++ b/java/test/org/openqa/selenium/json/JsonInputTest.java @@ -309,6 +309,22 @@ void shouldReadU_FFFF_AsALiteralCharacterAndNotEndOfInput() { } } + @Test + void shouldRejectUnescapedControlCharactersInStrings() { + // RFC 8259 §7: characters U+0000..U+001F MUST be escaped in JSON strings. + // A literal newline / tab / etc. inside quotes is not valid JSON. + try (JsonInput input = newInput("\"a\nb\"")) { + assertThatExceptionOfType(JsonException.class) + .isThrownBy(input::nextString) + .withMessageStartingWith("Illegal unescaped control character"); + } + + // Escaped equivalents are still fine. + try (JsonInput input = newInput("\"a\\nb\"")) { + assertThat(input.nextString()).isEqualTo("a\nb"); + } + } + @Test void nullInputsShouldCoerceAsNullValues() throws IOException { try (InputStream is = new ByteArrayInputStream(new byte[0]);