CVE-2026-41145: Unsigned-Trailer Query Authentication Bypass
Status: Released
First containing release: RELEASE.2026-04-17T00-00-00Z
GitHub advisory: GHSA-hv4r-mvr4-25vw
Query-string SigV4 credentials could enter a STREAMING-UNSIGNED-PAYLOAD-TRAILER data flow, while the old code verified the signature only when an Authorization header was present. A request carrying a valid access-key identifier could therefore complete a write without a correct signature.
The final fix moved presigned rejection and SigV4 verification into newUnsignedV4ChunkedReader(), making every caller consuming that stream share one authentication boundary.
Identifier note
The official CVE had not been assigned when the patch was written, so its commit subject used fake CVE-2026-40027. The final identifier is CVE-2026-41145. The historical commit remains unchanged; public material uses the official identifier.
Root cause: authentication was coupled to transport form
The affected entry points included PutObject and PutObjectPart. The request selected STREAMING-UNSIGNED-PAYLOAD-TRAILER, with its credentials and signature in the query string rather than the Authorization header.
The old handler used header presence to decide whether to verify a signature. The body reader still consumed the data normally, silently degrading query authentication into something close to an anonymous write. The attacker needed to know a valid access-key identifier, but did not need to produce a correct signature.
The problem was not failure to parse the query parameters. It was that authentication depended on how credentials were transported instead of the trust boundary at which the stream was consumed.
Why the patch did not live in each handler
| Option | Risk | Decision |
|---|---|---|
Add header/query checks separately to PutObject and PutObjectPart | Closes today’s entry points, but a new caller can omit the check again | Rejected |
| Invent a compatible presigned unsigned-trailer protocol | Greatly expands protocol and test surface without an existing support contract | Rejected |
Reject and verify centrally in newUnsignedV4ChunkedReader() | Forces every consumer through the same boundary | Accepted |
Anonymous unsigned-trailer requests were not prohibited wholesale. If bucket policy explicitly permits anonymous writes, they can still follow the anonymous authorization path. The forbidden state is the mixture of query credentials with no verification of those credentials.
Implementation and verification
The fix performs presigned rejection and SigV4 verification at the reader entry in cmd/streaming-v4-unsigned.go, while removing the gates in the PutObject and multipart handlers that depended on header presence.
New tests cover forged query PUT, multipart, mixed authentication, and anonymous policy. The historical record also includes a vulnerable-parent write that succeeded, failure on the patched tree, and live-server before/after smoke tests showing that header-authenticated and valid anonymous flows continued to work.
The public fix is fa7c579. The live exploit was not rerun while preparing this article.
Compatibility and residual risk
- Presigned/query unsigned-trailer is now explicitly unsupported, an intentional breaking change.
- Moving the fix into the reader significantly reduces the chance that a sibling handler omits the check again.
- Other streaming authentication modes still need their own audits; this reader fix does not establish that every SigV4 streaming combination is safe.
The shape of this fix matters as much as its payload: when several handlers share an authenticated data stream, authentication belongs to the reader rather than to optional checks in each caller.