CVE-2026-86043: Skipper opaAuthorizeRequestWithBody OPA Authorization Bypass via Chunked Body
Sending an oversized request body with chunked transfer encoding (no Content-Length header) to a Skipper proxy causes its OPA body-inspection filter to incorrectly report the body as not truncated…
The problem
The opaAuthorizeRequestWithBody filter in Skipper truncates request bodies exceeding max-request-body-size (default 1 MB) before handing them to Open Policy Agent. Advisory GHSA-8qqm-fp2q-v734 introduced a truncated_body signal to let policies detect this and deny oversized requests.
The signal is unreliable. The OPA envoy plugin (getParsedBody in opa-envoy-plugin/envoyauth/request.go) only sets truncated_body = true by comparing content-length against the received body length. Chunked HTTP/1.1 and HTTP/2 requests carry no content-length header, so the comparison is never reached.
Skipper does truncate the body (ExtractHttpBodyOptionally caps at maxBodyBytes when req.ContentLength < 0), but skipperadapter.go forwards the original headers verbatim, so OPA sees truncated_body = false and a correctly-following mitigation policy allows the request.
The full oversized body is then streamed to the upstream.
Proof of concept
A working proof-of-concept for CVE-2026-86043 in github.com/zalando/skipper, with the exact payload below.
POST /protected HTTP/1.1
Host: skipper.example.internal
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked
42
a=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
0
The root cause is a missing truncation signal path in opa-envoy-plugin/envoyauth/request.go. checkIfHTTPBodyTruncated is only called when a content-length header exists; chunked/HTTP-2 requests reach the return data, false, nil fallback unconditionally, producing truncated_body = false regardless of how many bytes Skipper actually dropped.
The Rego mitigation (allow if { input.truncated_body == false }) therefore evaluates to true on every chunked oversized request. The patch (commit 2cfceabaa6ff0af65b312dcb9bcbe84691b9d507) makes Skipper inject an authoritative truncation signal before forwarding headers to OPA, so the plugin no longer depends on the client-supplied content-length to detect truncation.
CWE-863 (Incorrect Authorization) applies: the authorization check produces the wrong outcome because a precondition (truncated_body) is incorrectly computed from attacker-controlled (or absent) input.
The fix
Upgrade to Skipper v0.27.37. The patch (commit 2cfceabaa6ff0af65b312dcb9bcbe84691b9d507) fixes ExtractHttpBodyOptionally and skipperadapter.go to inject an authoritative truncation indicator when the body is capped, making input.truncated_body reliable for all transfer encodings.
As a short-term workaround before upgrading, configure Skipper to reject (413) requests whose body exceeds max-request-body-size when opaAuthorizeRequestWithBody is in use, or add a policy clause that also denies when input.attributes.request.http.body == null and the content type implies a body.
Reported by Pig-Tail (Thepigtails).
Related research
- high · 8.2Skipper opaAuthorizeRequestWithBody OPA Policy Bypass via Oversized Content-Length
- high · 8.7CVE-2026-50197CVE-2026-50197: Skipper opaAuthorizeRequestWithBody OPA Policy Bypass via Chunked Encoding
- criticalCVE-2026-88007CVE-2026-88007: Traefik HTTP/3 NTLM Backend Connection Reuse
- highCVE-2026-88008CVE-2026-88008: Traefik h2c Upgrade Middleware Bypass via HTTP Request Smuggling