Skip to content

net/http: CrossOriginProtection insecure bypass patterns not limited to exact matches #75054

@gazerro

Description

@gazerro

The AddInsecureBypassPattern method of http.CrossOriginProtection, introduced in version 1.25, shows unexpected behavior.

This method is supposed to allow requests matching a given pattern to bypass protection. The issue is that more requests than expected end up being bypassed.

For example, if you define a ServeMux with two paths, /hello and /hello/:

mux := http.NewServeMux()
mux.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("/hello"))
})
mux.HandleFunc("/hello/", func(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("/hello/"))
})

and you configure the bypass for /hello/:

c := http.NewCrossOriginProtection()
c.AddInsecureBypassPattern("/hello/")
h := c.Handler(mux)

the result is that /hello also gets bypassed. Here's a complete example:

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
)

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/hello/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("/hello/"))
	})
	mux.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("/hello"))
	})

	c := http.NewCrossOriginProtection()
	c.AddInsecureBypassPattern("/hello/")
	h := c.Handler(mux)

	r := httptest.NewRequest("POST", "http://example.test/hello", nil)
	r.Header.Set("Sec-Fetch-Site", "cross-site")
	r.Header.Set("Origin", "https://evil.test")

	rec := httptest.NewRecorder()
	h.ServeHTTP(rec, r)

	fmt.Println(rec.Code, rec.Body.String())
}

Why this happens

CrossOriginProtection uses an internal ServeMux to check the bypass pattern. For /hello/, ServeMux would internally redirect /hello to /hello/. As a result, the internal check finds a non-empty match and CrossOriginProtection skips validation.

However, CrossOriginProtection does not actually rewrite or redirect the request path; it forwards the original one. Since the downstream mux defines a real handler for /hello, the request is served without protection.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugReportIssues describing a possible bug in the Go implementation.FixPendingIssues that have a fix which has not yet been reviewed or submitted.NeedsFixThe path to resolution is known, but the work has not been done.Security

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions