Skip to content

Commit 4132414

Browse files
committed
Protect against deeply malformed JSON map keys
Fixes gh-31869
1 parent 6966ebd commit 4132414

File tree

4 files changed

+28
-12
lines changed

4 files changed

+28
-12
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/json/BasicJsonParser.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.List;
2222
import java.util.Map;
2323

24+
import org.springframework.util.Assert;
2425
import org.springframework.util.StringUtils;
2526

2627
/**
@@ -86,6 +87,20 @@ private Object parseInternal(int nesting, String json) {
8687
return json;
8788
}
8889

90+
private Map<String, Object> parseMapInternal(String json) {
91+
Map<String, Object> map = new LinkedHashMap<>();
92+
json = trimLeadingCharacter(trimTrailingCharacter(json, '}'), '{').trim();
93+
for (String pair : tokenize(json)) {
94+
String[] values = StringUtils.trimArrayElements(StringUtils.split(pair, ":"));
95+
Assert.state(values[0].startsWith("\"") && values[0].endsWith("\""),
96+
"Expecting double-quotes around field names");
97+
String key = trimLeadingCharacter(trimTrailingCharacter(values[0], '"'), '"');
98+
Object value = parseInternal(0, values[1]);
99+
map.put(key, value);
100+
}
101+
return map;
102+
}
103+
89104
private static String trimTrailingCharacter(String string, char c) {
90105
if (!string.isEmpty() && string.charAt(string.length() - 1) == c) {
91106
return string.substring(0, string.length() - 1);
@@ -100,18 +115,6 @@ private static String trimLeadingCharacter(String string, char c) {
100115
return string;
101116
}
102117

103-
private Map<String, Object> parseMapInternal(String json) {
104-
Map<String, Object> map = new LinkedHashMap<>();
105-
json = trimLeadingCharacter(trimTrailingCharacter(json, '}'), '{').trim();
106-
for (String pair : tokenize(json)) {
107-
String[] values = StringUtils.trimArrayElements(StringUtils.split(pair, ":"));
108-
String key = trimLeadingCharacter(trimTrailingCharacter(values[0], '"'), '"');
109-
Object value = parseInternal(0, values[1]);
110-
map.put(key, value);
111-
}
112-
return map;
113-
}
114-
115118
private List<String> tokenize(String json) {
116119
List<String> list = new ArrayList<>();
117120
int index = 0;

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/json/AbstractJsonParserTests.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,4 +198,11 @@ void listWithRepeatedOpenArray() throws IOException {
198198
.withMessageContaining("too deeply nested");
199199
}
200200

201+
@Test // gh-31869
202+
void largeMalformed() throws IOException {
203+
String input = StreamUtils.copyToString(
204+
AbstractJsonParserTests.class.getResourceAsStream("large-malformed-json.txt"), StandardCharsets.UTF_8);
205+
assertThatExceptionOfType(JsonParseException.class).isThrownBy(() -> this.parser.parseList(input));
206+
}
207+
201208
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/json/YamlJsonParserTests.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,9 @@ void listWithRepeatedOpenArray() throws IOException {
6161
super.listWithRepeatedOpenArray();
6262
}
6363

64+
@Override
65+
@Disabled("SnakeYaml does not protect against malformed keys")
66+
void largeMalformed() throws IOException {
67+
}
68+
6469
}

0 commit comments

Comments
 (0)