VYPR
Critical severityNVD Advisory· Published Jul 30, 2025· Updated Jul 30, 2025

OAuth2-Proxy has authentication bypass in oauth2-proxy skip_auth_routes due to Query Parameter inclusion

CVE-2025-54576

Description

OAuth2-Proxy is an open-source tool that can act as either a standalone reverse proxy or a middleware component integrated into existing reverse proxy or load balancer setups. In versions 7.10.0 and below, oauth2-proxy deployments are vulnerable when using the skip_auth_routes configuration option with regex patterns. Attackers can bypass authentication by crafting URLs with query parameters that satisfy configured regex patterns, allowing unauthorized access to protected resources. The issue stems from skip_auth_routes matching against the full request URI. Deployments using skip_auth_routes with regex patterns containing wildcards or broad matching patterns are most at risk. This issue is fixed in version 7.11.0. Workarounds include: auditing all skip_auth_routes configurations for overly permissive patterns, replacing wildcard patterns with exact path matches where possible, ensuring regex patterns are properly anchored (starting with ^ and ending with $), or implementing custom validation that strips query parameters before regex matching.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

OAuth2-Proxy v7.10.0 and below can bypass authentication when `skip_auth_routes` uses regex patterns, due to matching against the full request URI including query parameters.

Vulnerability

Overview CVE-2025-54576 affects OAuth2-Proxy versions 7.10.0 and earlier when the skip_auth_routes configuration option is used with regex patterns. The root cause is that the regex matching is applied against the full request URI, which includes query parameters. This allows an attacker to craft URLs with query parameters that satisfy the regex pattern, thereby bypassing authentication for protected resources [2].

Attack

Vector and Exploitation An attacker can exploit this vulnerability by sending HTTP requests where the query string portion of the URI is crafted to match an overly permissive regex defined in skip_auth_routes. For example, a pattern like /api/.* might match /api/protected?ignore_this=true, allowing unauthorized access. The attack requires no prior authentication and can be executed remotely over the network. Deployments using wildcards or broad regex patterns are most at risk [1][2].

Impact

Successful exploitation enables an attacker to access protected endpoints that should require authentication. This could lead to exposure of sensitive data, unauthorized actions, or further compromise of the upstream application. The vulnerability does not require any special privileges or user interaction [2][3].

Mitigation

The issue is fixed in OAuth2-Proxy version 7.11.0. Users should upgrade immediately. As interim workarounds, administrators should audit skip_auth_routes for overly permissive patterns, replace wildcards with exact path matches, ensure regex patterns are properly anchored with ^ and $, or implement custom validation to strip query parameters before regex matching [2].

AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/oauth2-proxy/oauth2-proxy/v7Go
< 7.11.07.11.0

Affected products

2

Patches

1
9ffafad4b2d2

Merge commit from fork

https://github.com/oauth2-proxy/oauth2-proxyJan LarwigJul 30, 2025via ghsa
4 files changed · +85 14
  • CHANGELOG.md+15 0 modified
    @@ -4,8 +4,22 @@
     
     ## Important Notes
     
    +Fixed critical vulnerability where `skip_auth_routes` regex patterns matched against the full request URI (path + query parameters) instead of just the path, allowing authentication bypass attacks.
    +
     ## Breaking Changes
     
    +If your configuration relies on matching query parameters in `skip_auth_routes` patterns, you must update your regex patterns to match paths only. Review all `skip_auth_routes` entries for potential impact.
    +
    +**Example of affected configuration:**
    +```yaml
    +# This pattern previously matched both:
    +# - /api/foo/status (intended)
    +# - /api/private/sensitive?path=/status (bypass - now fixed)
    +skip_auth_routes: ["^/api/.*/status"]
    +```
    +
    +For detailed information, migration guidance, and security implications, see the [security advisory](https://github.com/oauth2-proxy/oauth2-proxy/security/advisories/GHSA-7rh7-c77v-6434).
    +
     ## Changes since v7.10.0
     
     - [#2615](https://github.com/oauth2-proxy/oauth2-proxy/pull/2615) feat(cookies): add option to set a limit on the number of per-request CSRF cookies oauth2-proxy sets (@bh-tt)
    @@ -17,6 +31,7 @@
     - [#3055](https://github.com/oauth2-proxy/oauth2-proxy/pull/3055) feat: support non-default authorization request response mode also for OIDC providers (@stieler-it)
     - [#3138](https://github.com/oauth2-proxy/oauth2-proxy/pull/3138) feat: make google_groups argument optional when using google provider (@sourava01)
     - [#3093](https://github.com/oauth2-proxy/oauth2-proxy/pull/3093) feat: differentiate between "no available key" and error for redis sessions (@nobletrout)
    +- [GHSA-7rh7-c77v-6434](https://github.com/oauth2-proxy/oauth2-proxy/security/advisories/GHSA-7rh7-c77v-6434) fix: skip_auth_routes bypass through query parameter inclusion
     
     
     # V7.10.0
    
  • oauthproxy.go+1 1 modified
    @@ -580,7 +580,7 @@ func isAllowedMethod(req *http.Request, route allowedRoute) bool {
     }
     
     func isAllowedPath(req *http.Request, route allowedRoute) bool {
    -	matches := route.pathRegex.MatchString(requestutil.GetRequestURI(req))
    +	matches := route.pathRegex.MatchString(requestutil.GetRequestPath(req))
     
     	if route.negate {
     		return !matches
    
  • pkg/requests/util/util.go+21 0 modified
    @@ -2,6 +2,8 @@ package util
     
     import (
     	"net/http"
    +	"net/url"
    +	"strings"
     
     	middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
     )
    @@ -43,6 +45,25 @@ func GetRequestURI(req *http.Request) string {
     	return uri
     }
     
    +// GetRequestPath returns the request URI or X-Forwarded-Uri if present and the
    +// request is proxied but always strips the query parameters and only returns
    +// the pure path
    +func GetRequestPath(req *http.Request) string {
    +	uri := GetRequestURI(req)
    +
    +	// Parse URI and return only the path component
    +	if parsedURL, err := url.Parse(uri); err == nil {
    +		return parsedURL.Path
    +	}
    +
    +	// Fallback: strip query parameters manually
    +	if idx := strings.Index(uri, "?"); idx != -1 {
    +		return uri[:idx]
    +	}
    +
    +	return uri
    +}
    +
     // IsProxied determines if a request was from a proxy based on the RequestScope
     // ReverseProxy tracker.
     func IsProxied(req *http.Request) bool {
    
  • pkg/requests/util/util_test.go+48 13 modified
    @@ -13,16 +13,17 @@ import (
     
     var _ = Describe("Util Suite", func() {
     	const (
    -		proto = "http"
    -		host  = "www.oauth2proxy.test"
    -		uri   = "/test/endpoint"
    +		proto              = "http"
    +		host               = "www.oauth2proxy.test"
    +		uriWithQueryParams = "/test/endpoint?query=param"
    +		uriNoQueryParams   = "/test/endpoint"
     	)
     	var req *http.Request
     
     	BeforeEach(func() {
     		req = httptest.NewRequest(
     			http.MethodGet,
    -			fmt.Sprintf("%s://%s%s", proto, host, uri),
    +			fmt.Sprintf("%s://%s%s", proto, host, uriWithQueryParams),
     			nil,
     		)
     	})
    @@ -101,13 +102,13 @@ var _ = Describe("Util Suite", func() {
     				req = middleware.AddRequestScope(req, &middleware.RequestScope{})
     			})
     
    -			It("returns the URI", func() {
    -				Expect(util.GetRequestURI(req)).To(Equal(uri))
    +			It("returns the URI (with query params)", func() {
    +				Expect(util.GetRequestURI(req)).To(Equal(uriWithQueryParams))
     			})
     
    -			It("ignores X-Forwarded-Uri and returns the URI", func() {
    +			It("ignores X-Forwarded-Uri and returns the URI (with query params)", func() {
     				req.Header.Add("X-Forwarded-Uri", "/some/other/path")
    -				Expect(util.GetRequestURI(req)).To(Equal(uri))
    +				Expect(util.GetRequestURI(req)).To(Equal(uriWithQueryParams))
     			})
     		})
     
    @@ -118,13 +119,47 @@ var _ = Describe("Util Suite", func() {
     				})
     			})
     
    -			It("returns the URI if X-Forwarded-Uri is not present", func() {
    -				Expect(util.GetRequestURI(req)).To(Equal(uri))
    +			It("returns the URI if X-Forwarded-Uri is not present (with query params)", func() {
    +				Expect(util.GetRequestURI(req)).To(Equal(uriWithQueryParams))
     			})
     
    -			It("returns the X-Forwarded-Uri when present", func() {
    -				req.Header.Add("X-Forwarded-Uri", "/some/other/path")
    -				Expect(util.GetRequestURI(req)).To(Equal("/some/other/path"))
    +			It("returns the X-Forwarded-Uri when present (with query params)", func() {
    +				req.Header.Add("X-Forwarded-Uri", "/some/other/path?query=param")
    +				Expect(util.GetRequestURI(req)).To(Equal("/some/other/path?query=param"))
    +			})
    +		})
    +	})
    +
    +	Context("GetRequestPath", func() {
    +		Context("IsProxied is false", func() {
    +			BeforeEach(func() {
    +				req = middleware.AddRequestScope(req, &middleware.RequestScope{})
    +			})
    +
    +			It("returns the URI (without query params)", func() {
    +				Expect(util.GetRequestPath(req)).To(Equal(uriNoQueryParams))
    +			})
    +
    +			It("ignores X-Forwarded-Uri and returns the URI (without query params)", func() {
    +				req.Header.Add("X-Forwarded-Uri", "/some/other/path?query=param")
    +				Expect(util.GetRequestPath(req)).To(Equal(uriNoQueryParams))
    +			})
    +		})
    +
    +		Context("IsProxied is true", func() {
    +			BeforeEach(func() {
    +				req = middleware.AddRequestScope(req, &middleware.RequestScope{
    +					ReverseProxy: true,
    +				})
    +			})
    +
    +			It("returns the URI if X-Forwarded-Uri is not present (without query params)", func() {
    +				Expect(util.GetRequestPath(req)).To(Equal(uriNoQueryParams))
    +			})
    +
    +			It("returns the X-Forwarded-Uri when present (without query params)", func() {
    +				req.Header.Add("X-Forwarded-Uri", "/some/other/path?query=param")
    +				Expect(util.GetRequestPath(req)).To(Equal("/some/other/path"))
     			})
     		})
     	})
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.