Skip to content

Commit

Permalink
Remove node and recursive limits for YAML
Browse files Browse the repository at this point in the history
Update `OriginTrackedYamlLoader` to remove node limits and recursive
parsing restrictions. SnakeYAML 1.26 introduced these options in order
to protect against the "billion laugh attacks" but since we consider
`application.yml` files to be trusted, we don't need these restrictions.

Fixes gh-23096
  • Loading branch information
philwebb committed Aug 31, 2020
1 parent ee91462 commit 0d80f46
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,18 @@ class OriginTrackedYamlLoader extends YamlProcessor {

@Override
protected Yaml createYaml() {
BaseConstructor constructor = new OriginTrackingConstructor();
LoaderOptions loaderOptions = new LoaderOptions();
loaderOptions.setAllowDuplicateKeys(false);
loaderOptions.setMaxAliasesForCollections(Integer.MAX_VALUE);
loaderOptions.setAllowRecursiveKeys(true);
return createYaml(loaderOptions);
}

private Yaml createYaml(LoaderOptions loaderOptions) {
BaseConstructor constructor = new OriginTrackingConstructor(loaderOptions);
Representer representer = new Representer();
DumperOptions dumperOptions = new DumperOptions();
LimitedResolver resolver = new LimitedResolver();
LoaderOptions loaderOptions = new LoaderOptions();
loaderOptions.setAllowDuplicateKeys(false);
return new Yaml(constructor, representer, dumperOptions, loaderOptions, resolver);
}

Expand All @@ -82,6 +88,10 @@ List<Map<String, Object>> load() {
*/
private class OriginTrackingConstructor extends SafeConstructor {

OriginTrackingConstructor(LoaderOptions loadingConfig) {
super(loadingConfig);
}

@Override
protected Object constructObject(Node node) {
if (node instanceof ScalarNode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,35 @@ void unsupportedType() throws Exception {
assertThatExceptionOfType(ConstructorException.class).isThrownBy(this.loader::load);
}

@Test
void loadWhenLargeNumberOfNodesLoadsYaml() {
StringBuilder yaml = new StringBuilder();
int size = 500;
yaml.append("defs:\n");
for (int i = 0; i < size; i++) {
yaml.append(" - def" + i + ": &def" + i + "\n");
yaml.append(" - value: " + i + "\n");
}
yaml.append("refs:\n");
for (int i = 0; i < size; i++) {
yaml.append(" ref" + i + ":\n");
yaml.append(" - value: *def" + i + "\n");
}
Resource resource = new ByteArrayResource(yaml.toString().getBytes(StandardCharsets.UTF_8));
this.loader = new OriginTrackedYamlLoader(resource);
Map<String, Object> loaded = this.loader.load().get(0);
assertThat(loaded).hasSize(size * 2);
}

@Test
void loadWhenRecursiveLoadsYaml() {
Resource resource = new ClassPathResource("recursive.yml", getClass());
this.loader = new OriginTrackedYamlLoader(resource);
Map<String, Object> loaded = this.loader.load().get(0);
assertThat(loaded.get("test.a.spring")).hasToString("a");
assertThat(loaded.get("test.b.boot")).hasToString("b");
}

private OriginTrackedValue getValue(String name) {
if (this.result == null) {
this.result = this.loader.load();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
&def1
*def1: a
test:
a:
spring: 'a'
b:
boot: 'b'

0 comments on commit 0d80f46

Please sign in to comment.