high · 7.5CVE-2026-86043Sep 17, 2026

CVE-2026-86043: Skipper opaAuthorizeRequestWithBody OPA Authorization Bypass via Chunked Body

Shubham Kandhare
Security Engagement Manager, SecureLayer7

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…

Packagegithub.com/zalando/skipper
Ecosystemgo
Affected< 0.27.37
Fixed in0.27.37

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.

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

References: [1][2][3][4][5][6]

Related research