high · 8.7CVE-2026-50197Jul 8, 2026

CVE-2026-50197: Skipper opaAuthorizeRequestWithBody OPA Policy Bypass via Chunked Encoding

Rohit Hatagale
AI Security Researcher, SecureLayer7

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 th

Packagegithub.com/zalando/skipper
Ecosystemgo
Affected< 0.26.10
Fixed in0.26.10

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.

http
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.

References: [1][2]

Related research