Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Middleware unduly allow OPTIONS requests #196

Open
jub0bs opened this issue Mar 7, 2025 · 1 comment
Open

Middleware unduly allow OPTIONS requests #196

jub0bs opened this issue Mar 7, 2025 · 1 comment

Comments

@jub0bs
Copy link
Contributor

jub0bs commented Mar 7, 2025

Problem

Contrary to popular belief,

However, all CORS middleware produced by this library implicitly allow OPTIONS requests, even when OPTIONS isn't listed in their configuration's AllowedMethods field. As a result, those middleware unduly allow browser-based clients to send OPTIONS requests to the server.

Proof of concept

Consider the following server (borrowed from the README):

package main

import (
    "net/http"

    "github.com/rs/cors"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        w.Write([]byte("{\"hello\": \"world\"}"))
    })
    handler := cors.Default().Handler(mux)
    http.ListenAndServe(":8080", handler)
}

Note that cors.Default() allows GET, HEAD, POST, but does not allow OPTIONS.

Start the server locally, then simulate a preflight request preceding an actual OPTIONS request by running the following command:

curl -v -XOPTIONS \
  -H "Access-Control-Request-Method: OPTIONS" \
  -H "Origin: https://example.com" \
  localhost:8080

Note that OPTIONS is (but shouldn't be) listed in the response's Access-Control-Allow-Methods header:

HTTP/1.1 204 No Content
Access-Control-Allow-Methods: OPTIONS
Access-Control-Allow-Origin: *
Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers
-snip-

Therefore, preflight would succeed and the browser would (undesirably) proceed to send the client's actual OPTIONS request.

Remediation

 // isMethodAllowed checks if a given method can be used as part of a cross-domain request
 // on the endpoint
 func (c *Cors) isMethodAllowed(method string) bool {
-       if len(c.allowedMethods) == 0 {
-               // If no method allowed, always return false, even for preflight request
-               return false
-       }
-       if method == http.MethodOptions {
-               // Always allow preflight requests
-               return true
-       }
        for _, m := range c.allowedMethods {
                if m == method {
                        return true
@jub0bs
Copy link
Contributor Author

jub0bs commented Mar 16, 2025

The proposed change is a breaking one (in terms of behaviour), but I don't expect that many CORS-aware servers wish to allow clients to send actual OPTIONS requests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant