CVE-2026-50197: Skipper opaAuthorizeRequestWithBody OPA Policy Bypass via Chunked Encoding
Skipper's OPA body-inspection filter silently skips reading the request body for chunked or HTTP/2 requests, letting attackers smuggle forbidden payloads past policy checks that should have blocked…
The problem
The opaAuthorizeRequestWithBody filter in zalando/skipper uses ExtractHttpBodyOptionally to buffer the request body before passing it to Open Policy Agent. When a client sends Transfer-Encoding: chunked (HTTP/1.1) or an HTTP/2 request without a content-length pseudo-header, Go's net/http sets req.ContentLength = -1.
The gate condition req.ContentLength <= maxBodyBytes passes because -1 <= positive limit is true. But fillBuffer(-1) immediately exits its loop because 0 < -1 is false, returning an empty buffer. OPA evaluates an empty input.parsed_body, any deny-rule keyed on a body field fails open, and the full attacker payload flows through to the upstream service.
No unauthenticated access is required.
Proof of concept
A working proof-of-concept for CVE-2026-50197 in github.com/zalando/skipper, with the exact payload below.
POST /protected HTTP/1.1
Host: skipper-proxy:9090
Content-Type: application/json
Connection: close
Transfer-Encoding: chunked
e
{"admin":true}
0
The root cause is a sign error in fillBuffer. Passing expectedSize = -1 makes the loop predicate len(buf) < -1 false on the first iteration, so the read loop never executes and the returned buffer is empty. OPA receives raw_body = []byte{}, so input.parsed_body is empty or undefined, and any Rego rule asserting a forbidden field is absent evaluates to the default allow.
The patch (targeting v0.26.10) adds a pre-check: if req.ContentLength < 0, clamp expectedSize to opa.maxBodyBytes before passing it to fillBuffer. This makes chunked bodies read up to the configured cap, matching the documented behavior for Content-Length requests.
CWE-444 (Inconsistent Interpretation of HTTP Requests) applies because the proxy and the authorization layer disagree on what body the request carries.
The fix
Upgrade github.com/zalando/skipper to v0.26.10 or later. The fix clamps expectedSize to opa.maxBodyBytes whenever req.ContentLength < 0, ensuring chunked and HTTP/2 bodies are read before OPA evaluation. No configuration change is needed; the existing -open-policy-agent-max-request-body-size flag continues to bound memory use.
Reported by tonghuaroot.
Related research
- high · 8.2Skipper opaAuthorizeRequestWithBody OPA Policy Bypass via Oversized Content-Length
- high · 7.5CVE-2026-58419CVE-2026-58419: Gitea Notification API Private Issue Metadata Leak After Access Revocation
- highCVE-2026-58422CVE-2026-58422: Gitea OAuth2 Callback Improper Access Control Silently Re-enables Disabled Accounts
- high · 7.1CVE-2026-20779CVE-2026-20779: Gitea TOTP Passcode Capture-Replay via Basic-Auth and TOCTOU Race