Executive Summary
CVE-2026-40575 is a critical authentication bypass vulnerability (CVSS 9.1) in OAuth2 Proxy, one of the most widely-deployed reverse proxy solutions for enforcing OAuth2/OIDC authentication in Kubernetes, cloud-native, and self-hosted environments. By spoofing the X-Forwarded-Uri HTTP header, an unauthenticated remote attacker can trick a vulnerable OAuth2 Proxy instance into evaluating its skip-auth rules against a controlled path — rather than the actual request path — granting unauthorized access to any route protected by the proxy. Disclosed on April 22, 2026, all organizations using OAuth2 Proxy v7.5.0 through v7.15.1 with --reverse-proxy and --skip-auth-route or --skip-auth-regex rules configured are at immediate risk. Upgrade to v7.15.2 or later and configure --trusted-proxy-ip without delay.
1. What Is This Vulnerability?
Background: OAuth2 Proxy and How It Works
OAuth2 Proxy is an open-source reverse proxy that sits in front of backend applications and enforces OAuth2 / OpenID Connect authentication before allowing access. It is widely used in Kubernetes ingress chains, Docker Compose stacks, and corporate single-sign-on (SSO) deployments. When a request arrives, OAuth2 Proxy checks whether the user holds a valid session; if not, it redirects them to the configured identity provider (IdP).
To support flexible deployments, OAuth2 Proxy supports skip-auth rules — patterns (regex or explicit routes) that tell the proxy to let certain paths through without authentication. Examples include public health-check endpoints like /healthz or unauthenticated webhook receivers. When deployed behind a load balancer or another reverse proxy, OAuth2 Proxy can be configured with --reverse-proxy to trust upstream X-Forwarded-* headers.
The Flaw: Trusting a Client-Supplied Header
CVE-2026-40575 is a logic error in how OAuth2 Proxy evaluates which URI to check against its skip-auth rules. When --reverse-proxy is enabled, the proxy trusts the X-Forwarded-Uri header to determine the effective request path. However, this header is not stripped or validated before reaching OAuth2 Proxy — meaning an external attacker who can send requests directly (or through a misconfigured upstream that does not overwrite headers) can inject any value they choose.
The vulnerable code path, simplified:
// Pseudocode of the vulnerable logic (pre-v7.15.2)
incomingUri = request.Header.Get("X-Forwarded-Uri")
if incomingUri == "" {
incomingUri = request.URL.Path
}
// skip-auth rules are evaluated against incomingUri
if matchesSkipAuthRule(incomingUri) {
// BYPASS: forward request to upstream without auth check
proxyToUpstream(request)
return
}
// Normal auth enforcement...
enforceAuthentication(request)
Because incomingUri is sourced from the request header first, an attacker can set X-Forwarded-Uri: /public/healthz (a known skip-auth path) while the actual URL they are accessing is /admin/users or another protected endpoint. OAuth2 Proxy sees a match on the skip-auth rule and forwards the request unauthenticated.
Attack Vector
The attack requires:
- OAuth2 Proxy running with
--reverse-proxyflag enabled, AND - At least one
--skip-auth-regexor--skip-auth-routerule configured, AND - The attacker being able to reach the OAuth2 Proxy listener (port 4180 by default) while being able to set arbitrary request headers
If the proxy is correctly isolated behind a load balancer that rewrites X-Forwarded-Uri to the real path, exploitation is significantly harder — but many real-world deployments do not enforce this.
Real-World Impact
While no specific public breach has been attributed to CVE-2026-40575 at the time of writing, the attack's prerequisites match a very common Kubernetes and cloud-native deployment pattern. Exposing OAuth2 Proxy to untrusted network segments, or leaving it reachable on port 4180 without a trusted upstream stripping headers, is a widespread misconfiguration. An attacker who exploits this vulnerability can:
- Access internal dashboards, admin panels, and APIs protected only by OAuth2 Proxy
- Extract sensitive data from authenticated-only API endpoints
- Pivot laterally inside Kubernetes clusters by leveraging compromised backend services
- Exfiltrate secrets, configurations, or PII from internal tooling assumed to be protected
2. Who Is Affected?
Directly vulnerable: OAuth2 Proxy versions 7.5.0 through 7.15.1 running with all three conditions present:
--reverse-proxyflag is enabled (orOAUTH2_PROXY_REVERSE_PROXY=true)- One or more
--skip-auth-regexpatterns or--skip-auth-routerules are configured - The proxy listener is reachable by a client that can set arbitrary HTTP headers
Deployment environments at highest risk:
- Kubernetes clusters where OAuth2 Proxy is deployed as a sidecar or standalone deployment with port 4180 exposed without network policy enforcement
- Docker Compose stacks where OAuth2 Proxy is behind nginx or Traefik but
X-Forwarded-Uriis not overwritten by the upstream proxy - Bare-metal or VM deployments where the proxy is directly reachable on the LAN or public internet
- Helm chart deployments of oauth2-proxy that have not pinned to a patched image tag
Not directly vulnerable if:
- No
--skip-auth-routeor--skip-auth-regexrules are configured (all requests require authentication) --reverse-proxyis disabled- A trusted upstream proxy unconditionally overwrites
X-Forwarded-Uriwith the actual request path before it reaches OAuth2 Proxy - Already upgraded to v7.15.2 or later
3. How to Detect It (Testing)
Manual Testing Steps
Step 1: Enumerate skip-auth paths
Review the OAuth2 Proxy configuration to identify all --skip-auth-route and --skip-auth-regex entries. These are the paths you will use in the spoofed X-Forwarded-Uri header.
# Check running config via process inspection
ps aux | grep oauth2-proxy
# Or review the config file / Kubernetes ConfigMap
kubectl get configmap oauth2-proxy-config -n <namespace> -o yaml
Step 2: Send a spoofed request
Identify a protected path (e.g., /dashboard, /api/v1/users) and a known skip-auth path (e.g., /healthz, /ping). Then send:
# Replace <PROXY_HOST> with the OAuth2 Proxy address and port
curl -v \
-H "X-Forwarded-Uri: /healthz" \
http://<PROXY_HOST>:4180/api/v1/users
Step 3: Evaluate the response
- Vulnerable: You receive a
200 OK(or a response from the upstream application) without being redirected to the OAuth2/OIDC login page. The proxy forwarded the request based on the spoofed header. - Not vulnerable / patched: You receive a
302 Foundredirect to the identity provider login page, or a401 Unauthorizedresponse. The proxy ignored the spoofed header and enforced authentication against the real path.
Step 4: Vary the skip-auth pattern
If the first skip-auth path doesn't produce a bypass, repeat with other configured patterns — especially regex patterns that might match sub-paths (e.g., ^/public/.* matched by X-Forwarded-Uri: /public/anything).
Automated Scanning
Tool: nuclei (ProjectDiscovery)
nuclei -u http://<PROXY_HOST>:4180 \
-t cves/2026/CVE-2026-40575.yaml \
-header "X-Forwarded-Uri: /healthz"
If a community template is not yet available, create a simple custom template:
id: CVE-2026-40575-oauth2-proxy-bypass
info:
name: OAuth2 Proxy X-Forwarded-Uri Auth Bypass
severity: critical
cve-id: CVE-2026-40575
requests:
- method: GET
path:
- "{{BaseURL}}/api/v1/protected"
headers:
X-Forwarded-Uri: /healthz
matchers:
- type: status
status:
- 200
- type: word
negative: true
words:
- "Sign In"
- "Login"
- "oauth2/sign_in"
Tool: Burp Suite
- In Proxy > Intercept, capture a request to a protected path
- In the request editor, add the header:
X-Forwarded-Uri: /healthz - Forward the request and observe the response
- If you receive the upstream application's response rather than an auth redirect, the instance is vulnerable
Expected output indicating vulnerability:
- HTTP 200 with application content
- No
Set-Cookiefor OAuth2 Proxy session - No
Location:header pointing to the IdP
Code Review Checklist
- Is
--reverse-proxyenabled in the OAuth2 Proxy configuration? - Are any
--skip-auth-regexor--skip-auth-routerules defined? - Does the upstream proxy (nginx, Traefik, HAProxy, AWS ALB) unconditionally overwrite
X-Forwarded-Uribefore requests reach OAuth2 Proxy? - Is OAuth2 Proxy port (default 4180) network-restricted so only the upstream proxy can reach it?
- Is the OAuth2 Proxy image/binary version 7.15.2 or later?
- Is
--trusted-proxy-ipconfigured post-upgrade?
4. How to Fix It (Mitigation)
Step-by-Step Remediation
1. Upgrade OAuth2 Proxy to v7.15.2 or later
The official fix ships in v7.15.2, which introduces the --trusted-proxy-ip flag to restrict which source IP addresses may supply X-Forwarded-* headers.
# Pull the patched container image
docker pull quay.io/oauth2-proxy/oauth2-proxy:v7.15.2
# Or for Kubernetes Helm deployments
helm upgrade oauth2-proxy oauth2-proxy/oauth2-proxy \
--set image.tag=v7.15.2 \
--namespace <namespace>
2. Configure --trusted-proxy-ip after upgrading
This flag tells the patched OAuth2 Proxy to only trust X-Forwarded-* headers from listed source IP addresses or CIDR ranges. Any request arriving from outside those ranges will have X-Forwarded-Uri ignored.
# Example: trust only the nginx ingress controller's pod CIDR
oauth2-proxy \
--reverse-proxy \
--trusted-proxy-ip=10.0.0.0/8 \
--skip-auth-route="^/healthz$" \
... other flags ...
In a Kubernetes ConfigMap or Helm values:
extraArgs:
trusted-proxy-ip: "10.100.0.0/16"
reverse-proxy: "true"
3. Strip X-Forwarded-Uri at the upstream proxy (defense-in-depth)
Regardless of the OAuth2 Proxy version, configure your upstream proxy to always overwrite X-Forwarded-Uri with the actual request path. This prevents the attack even if a deployment is slow to upgrade.
nginx:
location / {
# Always overwrite with the real request URI — never trust client-supplied value
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_pass http://oauth2-proxy:4180;
}
Traefik (middleware configuration):
# Traefik does not natively support header overwrite via simple config;
# use a custom ForwardAuth middleware and ensure your backend strips the header,
# or use a Traefik plugin that enforces header sanitization.
HAProxy:
frontend http-in
http-request del-header X-Forwarded-Uri
http-request set-header X-Forwarded-Uri %[path]
4. Apply network-level isolation
Restrict direct access to the OAuth2 Proxy port (4180) at the network layer so only your trusted upstream proxy can reach it. In Kubernetes:
# NetworkPolicy to allow only ingress from the nginx-ingress namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: oauth2-proxy-ingress-restriction
namespace: <your-namespace>
spec:
podSelector:
matchLabels:
app: oauth2-proxy
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- protocol: TCP
port: 4180
5. Audit and narrow skip-auth rules
Review every --skip-auth-route and --skip-auth-regex entry. Remove rules that are no longer needed and tighten patterns to be as specific as possible (e.g., pin exact paths rather than broad regexes).
Code Fix Example
Before (vulnerable behavior — pre-v7.15.2 logic):
// Simplified vulnerable path evaluation
func getEffectiveUri(r *http.Request, reverseProxy bool) string {
if reverseProxy {
if fwdUri := r.Header.Get("X-Forwarded-Uri"); fwdUri != "" {
return fwdUri // ← Trusts client-supplied header unconditionally
}
}
return r.URL.Path
}
After (patched behavior — v7.15.2):
// Simplified patched path evaluation
func getEffectiveUri(r *http.Request, reverseProxy bool, trustedIPs []net.IPNet) string {
if reverseProxy && isTrustedSource(r.RemoteAddr, trustedIPs) {
// Only trust X-Forwarded-Uri if the request comes from a trusted proxy IP
if fwdUri := r.Header.Get("X-Forwarded-Uri"); fwdUri != "" {
return fwdUri
}
}
return r.URL.Path // Fall back to the actual request path
}
Configuration Hardening
Beyond the immediate fix, harden your OAuth2 Proxy deployment:
- Disable
--reverse-proxyif you don't needX-Forwarded-*header trust - Use
--cookie-secure=trueto ensure session cookies are HTTPS-only - Enable
--cookie-httponly=trueto prevent JavaScript access to session cookies - Set
--pass-access-token=falseunless downstream services genuinely need the bearer token - Configure
--email-domainor--allowed-groupto limit who can authenticate, reducing blast radius of any future bypass - Enable audit logging (
--logging-local-users=true) for post-incident forensics
5. How to Test the Fix (Validation)
Regression Test Scenarios
- Scenario A: Upgraded instance ignores spoofed
X-Forwarded-Urifrom untrusted client IP and enforces authentication on protected route - Scenario B: Upgraded instance correctly passes through requests on legitimate skip-auth routes when the real URI matches the pattern
- Scenario C: Trusted upstream proxy (with
--trusted-proxy-ipconfigured) can still supplyX-Forwarded-Uriand have it honored, preserving expected functionality - Scenario D: No legitimate user authentication flows are broken after upgrade
Security Test Cases
Test Case 1: Verify the bypass no longer works
- Precondition: OAuth2 Proxy upgraded to v7.15.2+,
--trusted-proxy-ipset to the upstream proxy's CIDR only - Steps:
curl -v \ -H "X-Forwarded-Uri: /healthz" \ http://<PROXY_HOST>:4180/api/v1/users - Expected Result:
302 Foundredirect to IdP login URL — the bypass is rejected
Test Case 2: Verify legitimate skip-auth still works
- Precondition: Same as Test Case 1; request originates from a trusted proxy IP
- Steps: Send a request to
/healthzthrough the trusted upstream proxy without a session - Expected Result:
200 OK— the real skip-auth path is still bypassed as intended
Test Case 3: Verify authenticated users are unaffected
- Precondition: Valid OAuth2 session cookie exists
- Steps: Send a normal authenticated request (no spoofed headers) to a protected path
- Expected Result:
200 OKwith application content — normal authenticated access works
Test Case 4: Verify --trusted-proxy-ip enforcement
- Precondition: OAuth2 Proxy on v7.15.2+;
--trusted-proxy-ipset to192.168.1.0/24 - Steps: Send from an IP outside that CIDR with
X-Forwarded-Uri: /healthztargeting/admin - Expected Result:
302redirect to IdP — header ignored because source is untrusted
Automated Tests
Add the following to your CI/CD pipeline to permanently catch regressions:
#!/usr/bin/env bash
# oauth2_proxy_bypass_test.sh
# Run after every OAuth2 Proxy upgrade or config change
PROXY_URL="${OAUTH2_PROXY_URL:-http://localhost:4180}"
PROTECTED_PATH="/api/v1/users"
SKIP_AUTH_PATH="/healthz"
echo "=== CVE-2026-40575 Regression Test ==="
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" \
-H "X-Forwarded-Uri: $SKIP_AUTH_PATH" \
"$PROXY_URL$PROTECTED_PATH")
if [ "$RESPONSE" -eq 200 ]; then
echo "FAIL: Authentication bypass succeeded — instance is VULNERABLE"
exit 1
elif [ "$RESPONSE" -eq 302 ] || [ "$RESPONSE" -eq 401 ]; then
echo "PASS: Authentication enforced correctly (HTTP $RESPONSE)"
exit 0
else
echo "WARN: Unexpected response code $RESPONSE — manual review required"
exit 2
fi
6. Prevention & Hardening
Best Practices
Practice 1: Apply a zero-trust model for internal proxies
Never assume that headers arriving at an internal service are trustworthy. Even in a Kubernetes cluster, pod-to-pod traffic can be spoofed if no NetworkPolicy or service mesh (e.g., Istio mTLS) is in place. Treat every HTTP header that originates from outside your trusted proxy tier as untrusted input.
Practice 2: Pin skip-auth rules to the minimum necessary scope
Each --skip-auth-route entry is a potential attack surface. Before adding a skip-auth rule, ask: can this endpoint instead be moved to a separate, unauthenticated service? If the rule must exist, use the most specific regex or route pattern possible and document the business justification.
Practice 3: Run OAuth2 Proxy in a hardened network segment
Place the OAuth2 Proxy behind a network boundary that only allows the trusted upstream proxy to connect to port 4180. Use Kubernetes NetworkPolicy, AWS Security Groups, or firewall rules to enforce this topology. The CVE-2026-40575 attack is substantially harder to execute when direct external access to port 4180 is blocked.
Practice 4: Implement a dependency update policy
OAuth2 Proxy, like all authentication-critical infrastructure components, should be subject to mandatory upgrade SLAs. Critical CVEs (CVSS ≥ 9.0) should trigger an upgrade within 24–72 hours. Subscribe to security advisories via the GitHub Security Advisory feed for oauth2-proxy/oauth2-proxy.
Practice 5: Validate your IdP integration regularly
Even with OAuth2 Proxy correctly configured, verify your identity provider settings: ensure token lifetimes are appropriate, refresh tokens are revoked on logout, and group/role membership is enforced at the IdP level. OAuth2 Proxy is a gatekeeper, but the IdP is the ultimate source of truth.
Monitoring & Detection
Set up alerts for the following indicators of exploitation attempts or active compromise:
Header anomaly detection (nginx/WAF rule):
# Alert if X-Forwarded-Uri does not match the actual request path
# (Indicates potential header spoofing attempts)
if ($http_x_forwarded_uri != "" and $http_x_forwarded_uri != $request_uri) {
access_log /var/log/nginx/suspicious.log combined;
return 400;
}
SIEM query (Splunk example):
index=access_logs sourcetype=nginx
| where isnotnull('http_x_forwarded_uri')
AND 'http_x_forwarded_uri' != request_uri
| stats count by client_ip, http_x_forwarded_uri, request_uri
| where count > 5
| sort -count
Kubernetes audit log alert (Falco rule):
- rule: OAuth2 Proxy Port Accessed Without Upstream
desc: Direct access to OAuth2 Proxy port 4180 bypassing ingress controller
condition: >
ka.target.name startswith "oauth2-proxy" and
ka.request.operation = "GET" and
not ka.source.ip in (trusted_ingress_ips)
output: "Suspicious direct OAuth2 Proxy access from %ka.source.ip%"
priority: WARNING
Metrics to monitor:
- Sudden spike in
4xxresponses from OAuth2 Proxy (could indicate automated probing) - Requests to protected paths without a corresponding session cookie
- High volume of requests from a single IP to known skip-auth paths
- Any
200 OKresponses from OAuth2 Proxy to paths that should require authentication
References
- CVE Record: CVE-2026-40575 — cve.org
- GitHub Security Advisory (GHSA-7x63-xv5r-3p2x): oauth2-proxy/oauth2-proxy — GitHub
- GitHub Advisory Database: GHSA-7x63-xv5r-3p2x — GitHub
- GitLab Advisory Database: CVE-2026-40575 — GLAD
- NVD Entry: CVE-2026-40575 — NIST NVD
- Tenable CVE Page: CVE-2026-40575 — Tenable
- Technical Write-Up: OAuth2 Proxy X-Forwarded-Uri Authentication Bypass — TheHackerWire
- DailyCVE Summary: OAuth2 Proxy Authentication Bypass — DailyCVE
- Patch Releases: oauth2-proxy Releases — GitHub
- Feedly CVE Tracking: CVE-2026-40575 — Feedly