Skip to content

CVE-2026-41145: Unsigned-Trailer Query Authentication Bypass

Query-string SigV4 credentials entered STREAMING-UNSIGNED-PAYLOAD-TRAILER uploads without signature verification; fix f444b6f37 enforces presigned rejection and SigV4 verification once inside newUnsignedV4ChunkedReader().

Status: Released
First containing release: RELEASE.2026-04-17T00-00-00Z
Fix commit: f444b6f37
GitHub advisory: GHSA-hv4r-mvr4-25vw

Before f444b6f37, query-string SigV4 credentials could enter a STREAMING-UNSIGNED-PAYLOAD-TRAILER upload while the handlers verified the request signature only when an HTTP Authorization header was present. An attacker who knew a valid access-key identifier could therefore complete an object or multipart write using a forged query-string signature.

The fix moves presigned-credential rejection and SigV4 verification directly into newUnsignedV4ChunkedReader() (cmd/streaming-v4-unsigned.go), ensuring every handler that consumes an unsigned-trailer chunked stream shares a single authentication boundary.

Commit identifier note

When the patch was written on 2026-04-16, the official CVE had not yet been assigned, so the commit subject used the temporary placeholder fake CVE-2026-40027. Upon publication of GHSA-hv4r-mvr4-25vw, the vulnerability was assigned CVE-2026-41145. The historical commit SHA f444b6f37 remains unchanged.

Root cause: coupling signature verification to credential transport

The vulnerable entry points included PutObject and PutObjectPart (UploadPart). When a client sent X-Amz-Content-Sha256: STREAMING-UNSIGNED-PAYLOAD-TRAILER and supplied its SigV4 credentials (X-Amz-Credential, X-Amz-Signature, etc.) in the URL query string rather than the Authorization header, two assumptions collided:

  1. The handler checked whether the Authorization header was non-empty to decide whether to run reqSignatureV4Verify before reading the stream, assuming an empty header meant an anonymous request.
  2. Identity resolution and newUnsignedV4ChunkedReader() still consumed the request normally while attributing the write to the access key named in X-Amz-Credential.

As a result, query-authenticated STREAMING-UNSIGNED-PAYLOAD-TRAILER requests bypassed signature verification altogether. An attacker only needed to know a valid access-key ID; the signature value in the query string was never checked.

Why we placed the check inside the shared reader instead of individual handlers

Option Risk Decision
Add header/query checks separately to PutObject and PutObjectPart Closes the two known handlers, but any sibling or future caller of newUnsignedV4ChunkedReader() can omit the check again (as CVE-2026-40344 demonstrated) Rejected
Invent a custom presigned STREAMING-UNSIGNED-PAYLOAD-TRAILER verification flow Expands the SigV4 streaming state machine without an existing S3 compatibility contract Rejected
Reject presigned credentials and verify SigV4 inside newUnsignedV4ChunkedReader() Forces every caller consuming the stream through one authentication gate Adopted

Note that genuinely anonymous STREAMING-UNSIGNED-PAYLOAD-TRAILER uploads were not disabled. When a request carries neither header nor query credentials and the bucket policy explicitly grants anonymous s3:PutObject, the request still follows the anonymous authorization path. What is forbidden is carrying unverified credentials into the stream.

Implementation and verification

Commit f444b6f37 enforces presigned rejection and SigV4 verification at the entry of newUnsignedV4ChunkedReader() in cmd/streaming-v4-unsigned.go and removes the Authorization-header presence gates from PutObject and multipart upload handlers.

Regression tests in cmd verify:

  • rejection of forged query-string PutObject and PutObjectPart requests in STREAMING-UNSIGNED-PAYLOAD-TRAILER mode;
  • rejection of requests mixing header and query-string SigV4 credentials;
  • continued operation of valid header-authenticated unsigned-trailer uploads and anonymous uploads permitted by bucket policy.
go test ./cmd -run 'Test.*UnsignedTrailer.*|Test.*StreamingUnsigned.*' -count=1

Compatibility and operational boundaries

  • Presigned unsigned-trailer is unsupported: Combining query-string SigV4 credentials with STREAMING-UNSIGNED-PAYLOAD-TRAILER is rejected unconditionally. Clients using unsigned-trailer chunked uploads must pass SigV4 credentials via the Authorization header.
  • Reader-level enforcement: Placing the authentication gate inside newUnsignedV4ChunkedReader() ensures that PutObject, PutObjectPart, and PutObjectExtract (CVE-2026-40344) cannot construct an unsigned-trailer reader without completing SigV4 verification.