-
-
Notifications
You must be signed in to change notification settings - Fork 203
Open
Labels
Description
This has been discussed before in #461, and has been a blocker for us using this library in Hugo. Given the maintenance situation for "the other Go YAML library", I have implemented a workaround in this PR, but I'm still convinced that this is something that needs to be fixed closer to the source.
This program illustrates the problem (aka the Billion laughs attack):
package main
import (
"log"
"github.com/goccy/go-yaml"
)
func main() {
data := []byte(`
a: &a [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _]
b: &b [*a, *a, *a, *a, *a, *a, *a, *a, *a, *a]
c: &c [*b, *b, *b, *b, *b, *b, *b, *b, *b, *b]
d: &d [*c, *c, *c, *c, *c, *c, *c, *c, *c, *c]
e: &e [*d, *d, *d, *d, *d, *d, *d, *d, *d, *d]
f: &f [*e, *e, *e, *e, *e, *e, *e, *e, *e, *e]
g: &g [*f, *f, *f, *f, *f, *f, *f, *f, *f, *f]
h: &h [*g, *g, *g, *g, *g, *g, *g, *g, *g, *g]
i: &i [*h, *h, *h, *h, *h, *h, *h, *h, *h, *h]
`)
target := make(map[string]any)
// This works fine, but produces a very large object graph.
err := yaml.Unmarshal(data, &target)
if err != nil {
log.Fatalf("error: %v", err)
}
// data, err = yaml.Marshal(&target) // This fails/DoSs the system.
// This experimental option makes it work.
data, err = yaml.MarshalWithOptions(&target, yaml.WithSmartAnchor())
if err != nil {
log.Fatalf("error: %v", err)
}
// But rendering it to another format (like JSON) fails/DoSs the system.
/*_, err = json.MarshalIndent(&target, "", " ")
if err != nil {
log.Fatalf("error: %v", err)
}*/
}- Receiving untrusted user YAML and render it into another format (e.g. HTML or JSON) is a very common use case. And this is currently very hard to do safely.
- You can argue that with the experimental
yaml.WithSmartAnchoroption enabled,go-yamlnever DoSs the system, but malicious user input doesn't magically get less malicious if you're able to swallow it, and I think it's a very good security practice to fix any security issue as close to the source as possible.
In SnakeYAML, a popular Java YAML library, they added a maxAliasesForCollections at some point to address this problem (default value being 50, which sounds very low, but I may have misunderstood exactly what that setting do), so I propose to add a similar option here.
jmooring