Zalando Skipper OPA Policy Bypass via Chunked Encoding
A critical vulnerability in `zalando/skipper`'s OpenPolicyAgent integration, tracked as GHSA-659f-rgp5-w4wf, allows attackers to bypass `opaAuthorizeRequestWithBody` policies using HTTP/1.1 `Transfer-Encoding: chunked` or HTTP/2 requests lacking a `content-length` pseudo-header, leading to unauthorized access to upstream services with uninspected payloads.
A significant vulnerability (GHSA-659f-rgp5-w4wf) has been identified in zalando/skipper versions <= v0.26.8 that allows threat actors to bypass security policies enforced by the opaAuthorizeRequestWithBody filter. This bypass occurs when HTTP/1.1 requests use Transfer-Encoding: chunked or HTTP/2 requests omit the content-length pseudo-header. Under these conditions, the OpenPolicyAgentInstance.ExtractHttpBodyOptionally helper in Skipper incorrectly produces an empty raw_body for OpenPolicyAgent (OPA) policies, even though the full, potentially malicious, body is forwarded to the upstream service. This means OPA policies designed to inspect and deny requests based on body content (e.g., for admin=true fields, content moderation, or schema validation) will evaluate against an empty document and typically default to allowing the request, effectively neutralizing a critical layer of defense. The vulnerability affects operators relying on Skipper to protect private upstream services using body-content checks.
Attack Chain
- Attacker identifies Skipper instance: An attacker identifies a
zalando/skipperAPI Gateway instance protecting a backend service, configured with theopaAuthorizeRequestWithBodyfilter. - Attacker crafts malicious HTTP request: The attacker prepares an HTTP POST request containing a payload intended to be blocked by an OPA policy (e.g.,
{"admin":true}to gain administrative privileges). - Applies bypass framing: The attacker sends the request using HTTP/1.1 with
Transfer-Encoding: chunkedheaders or as an HTTP/2 request without aContent-Lengthpseudo-header. - Skipper receives and parses request: The
zalando/skipperinstance receives the request. Due to the specific framing, Go'snet/httpparser setsreq.ContentLength = -1. - OPA body extraction fails: The
ExtractHttpBodyOptionallyfunction, which is supposed to buffer the body for OPA, checksreq.ContentLength <= maxBodyBytes. While-1passes this check, the subsequentfillBufferloop's conditionint64(m.bodyBuffer.Len()) < expectedSize(0 < -1) is immediately false, preventing any body data from being read. An emptyraw_bodyis then passed to the OPA SDK. - OPA policy grants unauthorized access: The OPA policy, expecting to evaluate
input.parsed_bodyagainst the actual request body, instead receives an empty document. If the policy is designed to deny based on specific content (e.g.,input.parsed_body.admin == true), it will default to "allow" because the condition is not met in the empty input. - Skipper forwards full payload: Despite the OPA policy effectively being bypassed, Skipper proceeds to forward the original, full, and uninspected malicious payload (e.g.,
{"admin":true}) to the backend upstream service. - Upstream processes unauthorized request: The upstream service receives and processes the unauthorized request and payload, potentially leading to privilege escalation, data modification, or remote code execution, depending on the backend's vulnerabilities.
Impact
This vulnerability allows for a complete bypass of critical security controls implemented via OpenPolicyAgent for body content inspection. Organizations using zalando/skipper with opaAuthorizeRequestWithBody policies to enforce granular authorization, content moderation, or schema validation for incoming requests are at risk. A successful exploitation enables unauthenticated attackers to send arbitrary payloads that OPA policies were explicitly designed to block, potentially leading to unauthorized data access, privilege escalation, command injection, or other severe compromises of protected backend services. There is no observed victim count or specific sector targeting mentioned, but any organization deploying Skipper as an API gateway is affected.
Recommendation
- Upgrade
zalando/skipperto a version that contains the fix for GHSA-659f-rgp5-w4wf immediately upon availability. - Review all OPA policies utilizing
input.parsed_bodywith theopaAuthorizeRequestWithBodyfilter to understand their susceptibility to this bypass. - Deploy the Sigma rule below to detect attempts to use
Transfer-Encoding: chunkedin conjunction with body content that would typically be denied by OPA policies. - Ensure webserver logs or API gateway logs capture HTTP headers, specifically
Transfer-Encoding, for POST requests to sensitive endpoints.
Detection coverage 1
Detect Skipper OPA Bypass Attempt (Chunked Encoding)
highDetects exploitation attempts of GHSA-659f-rgp5-w4wf where an attacker uses Transfer-Encoding: chunked to bypass OPA body inspection in Zalando Skipper. This rule looks for requests to paths typically protected by OPA that contain both chunked encoding and suspicious content (e.g., admin=true).
Detection queries are available on the platform. Get full rules →