Go · github.com/zalando/skipper
Skipper: Incomplete fix for CVE-2026-50197: an oversized body can bypass OPA deny-on-presence Rego policies
A wrong policy can be an open door.
You have to check input.attributes.request.http.truncated_body in your policy.
Incomplete fix for CVE-2026-50197: an oversized declared-Content-Length body still hands OPA an empty parsed_body, so deny-on-presence Rego policies fail OPEN while the full payload reaches upstream.
The CVE-2026-50197 fix (commit 3152f3b0, PR #4041, v0.26.10) substituted expectedSize = maxBodyBytes
only when req.ContentLength < 0 (chunked / HTTP/2 without content-length). But when a request declares a
Content-Length larger than maxBodyBytes, expectedSize > maxBodyBytes, the body-extraction if is
skipped entirely, and ExtractHttpBodyOptionally returns rawBodyBytes = nil — so OPA evaluates an empty
parsed_body, while the full forbidden payload still flows to the upstream. A deny-on-presence policy
(default allow = true; allow = false if input.parsed_body.<forbidden>) — the exact Rego shape the
advisory describes — fails OPEN. The fix's own comment reasons only about ContentLength == -1; the
oversized branch was never considered, and the added PoC test only covers small bodies.
filters/openpolicyagent/openpolicyagent.go ExtractHttpBodyOptionally: the
expectedSize <= maxBodyBytes gate lets an oversized declared body fall through to
return req.Body, nil, func() {}, nil (OPA sees an empty document).{ "welcome": "world" },
maxBodySize: 5 → bodyInPolicy: "").See attached docker-compose.yml (official golang image) + setup.sh + exploit.sh, which run a real
Skipper proxy (proxytest) with a real OPA control plane (opasdktest),
WithMaxRequestBodyBytes(32), policy allow = false if input.parsed_body.action == "delete", route
* -> opaAuthorizeRequestWithBody("test") -> upstream:
{"action":"delete"} (19B ≤ 32) → 403 (denied).{"action":"delete","pad":"X..64"} (> 32) → 200, upstream received the full body (BYPASS).{"action":"delete"} → 403 (positive control: the original CVE is fixed).(Library-tier: validated via Skipper's real proxy test harness, not a deploy of the official image; benign oracle = status diff + upstream-received body; no RCE.)
Deployments authorizing on request-body content via opaAuthorizeRequestWithBody + deny-on-presence Rego
can be bypassed by inflating the request body past -open-policy-agent-max-request-body-size (default
1 MB); the full payload still reaches the upstream.
Document how policy owners should block requests with oversized body.
Example deny by default and use "allow if" no oversized body:
default allow := false
allow if {
input.attributes.request.http.truncated_body == false
# ... body-based conditions
}
Example allow by default and use "deny if" an oversized body:
default deny := false
deny if {
input.attributes.request.http.truncated_body == true
# ... body-based conditions
}
Documentation is published by https://github.com/zalando/skipper/releases/tag/v0.27.26
Reported as part of an incomplete-patch measurement study (responsible disclosure).
Is your project exposed to this? Stateward checks every dependency on every pull request and flags it only if your code actually reaches it.
Check my repoSources: CISA KEV (public domain), OSV.dev & GitHub Advisory Database (CC-BY-4.0), FIRST EPSS, NVD/CWE (public domain). Served live from the Stateward advisory database.