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.NeedsDecisionFeedback is required from experts, contributors, and/or the community before a change can be made.Security

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions