GHSA-8qqm-fp2q-v734: High severity go/github.com/zalando/skipper vulnerability
Summary
A wrong policy can be an open door. You have to check input.attributes.request.http.truncatedbody in your policy.
Description
Incomplete fix for CVE-2026-50197: an oversized declared-Content-Length body still hands OPA an empty parsedbody, 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 parsedbody, while the full forbidden payload still flows to the upstream. A deny-on-presence policy (default allow = true; allow = false if input.parsedbody.<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.
Affected code
- 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). - Corroborated by Skipper's own unit test "Read body exhausting max bytes" ({ "welcome": "world" }, maxBodySize: 5 → bodyInPolicy: "").
Steps to reproduce
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.parsedbody.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). - small chunked {"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.)
Impact
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.
Mitigation
Document how policy owners should block requests with oversized body.
Example deny by default and use "allow if" no oversized body: rego default allow := false
allow if { input.attributes.request.http.truncatedbody == false # ... body-based conditions }
Example allow by default and use "deny if" an oversized body: rego default deny := false
deny if { input.attributes.request.http.truncatedbody == true # ... body-based conditions }
Documentation is published by https://github.com/zalando/skipper/releases/tag/v0.27.26
Credit
Reported as part of an incomplete-patch measurement study (responsible disclosure).
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
go/github.com/zalando/skipperto a version that resolves this vulnerability.Fixed in 0.27.26 - Upgrade
Upgrade
zalando/skipperto a version that resolves this vulnerability.Fixed in v0.27.26 - Configuration
Update deny-on-presence Rego policies that use input.parsed_body so they also deny requests when input.attributes.request.http.truncated_body == true. The material states you must check input.attributes.request.http.truncated_body because oversized declared Content-Length can result in OPA seeing an empty parsed_body while the full payload still reaches upstream.
Open Policy Agent (OPA) policy (deny-on-presence) input.attributes.request.http.truncated_body (include oversized declared Content-Length bypass case) = true - Configuration
Ensure your configured max body size for policy evaluation (e.g., WithMaxRequestBodyBytes(32) / -open-policy-agent-max-request-body-size) is aligned with your policy expectations, and rely on truncated_body-based denial to prevent bypass when the declared Content-Length exceeds the policy max. The material describes an oversized declared Content-Length falling through expectedSize <= maxBodyBytes gating, leaving OPA with an empty parsed_body.
Skipper/OPA authorization setup using opaAuthorizeRequestWithBody WithMaxRequestBodyBytes / -open-policy-agent-max-request-body-size handling = <= expected maximum policy input size (e.g., 32 when WithMaxRequestBodyBytes(32) is used)
Event History
Frequently Asked Questions
What is the severity of GHSA-8qqm-fp2q-v734?
The severity of GHSA-8qqm-fp2q-v734 is high, with a CVSS score of 8.2.
How do I fix GHSA-8qqm-fp2q-v734?
To fix GHSA-8qqm-fp2q-v734, ensure your policy checks the input attributes, specifically `input.attributes.request.http.truncated_body`.
What software is affected by GHSA-8qqm-fp2q-v734?
GHSA-8qqm-fp2q-v734 affects the software go/github.com/zalando/skipper.
What is the main issue described in GHSA-8qqm-fp2q-v734?
GHSA-8qqm-fp2q-v734 describes an incomplete fix for CVE-2026-50197, allowing oversized declared `Content-Length` bodies to bypass certain policy checks.
When was GHSA-8qqm-fp2q-v734 published?
GHSA-8qqm-fp2q-v734 was published on July 17, 2026.