Skip to content

fix: require signature verification in Snowball extract handler (CVE-2026-40344)#33

Merged
sergiodj merged 1 commit into
chainguard-forks:masterfrom
8none1:fix/cve-2026-40344-snowball-extract-sig-verify
Jun 4, 2026
Merged

fix: require signature verification in Snowball extract handler (CVE-2026-40344)#33
sergiodj merged 1 commit into
chainguard-forks:masterfrom
8none1:fix/cve-2026-40344-snowball-extract-sig-verify

Conversation

@8none1

@8none1 8none1 commented Jun 2, 2026

Copy link
Copy Markdown

Summary

Patches Vulnerability 1 of CVE-2026-40344 (GHSA-9c4q-hq6p-c237) — High, missing signature verification in the Snowball auto-extract handler. No upstream OSS patch (AIStor-only); EmeritOSS best-effort source patch.

The bug

When authTypeStreamingUnsignedTrailer support was added upstream (PR minio#16484), it was wired into PutObjectHandler and PutObjectPartHandler but never into PutObjectExtractHandler. That handler's switch rAuthType has no authTypeStreamingUnsignedTrailer case and no default, so a Snowball extract PUT with X-Amz-Content-Sha256: STREAMING-UNSIGNED-PAYLOAD-TRAILER, X-Amz-Meta-Snowball-Auto-Extract: true, a valid access key and a fabricated signature falls through with zero signature verification and the tar is extracted into the bucket. isPutActionAllowed only checks the access key + IAM, not the signature.

(Vulnerability 2 of this CVE — query-string credential bypass — was already fixed in b94db7d78; this PR is scoped to Vuln 1.)

The fix

Adds the missing case authTypeStreamingUnsignedTrailer: to PutObjectExtractHandler, wrapping the body in newUnsignedV4ChunkedReader(r, true, hasCreds) with the post-CVE-2026-41145 hasCreds := Authorization || X-Amz-Credential gate — so unsigned-trailer requests get signature verification and Vuln 2 is not reintroduced. Also extends the X-Amz-Decoded-Content-Length size-decode guard to cover authTypeStreamingUnsignedTrailer (otherwise the decoded read size would be wrong for aws-chunked unsigned-trailer bodies), matching PutObjectHandler.

Change site carries a CVE-2026-40344 comment.

Scope assessment

Within EmeritOSS best-effort policy: small, contained, mirrors the already-patched sibling handlers, no API change. Should get ProdSec PSIRT review before merge.

Test plan

  • CI green
  • Added TestCVE202640344SnowballExtract (end-to-end, runs across ErasureSD/Erasure/ErasureSet): attack request with clobbered signature is rejected; legitimate signed request returns 200 and the extracted object reads back correctly. Negative control (fix removed) confirmed the test FAILS, so it genuinely detects the missing verification.
  • go build ./cmd/... + targeted go test ./cmd/... pass locally.

Refs: GHSA-9c4q-hq6p-c237 / CVE-2026-40344 · Tracking: chainguard-dev/customer-issues#3598 · Linear OS-2158

…2026-40344)

PutObjectExtractHandler (the X-Amz-Meta-Snowball-Auto-Extract handler) was
missing a case for authTypeStreamingUnsignedTrailer in its `switch rAuthType`
block. When STREAMING-UNSIGNED-PAYLOAD-TRAILER support was added upstream
(PR minio#16484 / commit 76913a9), the new auth type was wired into
PutObjectHandler and PutObjectPartHandler but never into the extract handler.

As a result, a request carrying
`X-Amz-Content-Sha256: STREAMING-UNSIGNED-PAYLOAD-TRAILER`, the Snowball
auto-extract header, and an Authorization header with a valid access key but a
FABRICATED signature fell through the switch (no matching case, no default)
with ZERO cryptographic signature verification. isPutActionAllowed, called
before the switch, only authorizes the access key against IAM policy and does
not verify the request signature, so the tar payload was extracted into the
bucket unauthenticated.

This adds the missing `case authTypeStreamingUnsignedTrailer:` mirroring the
protected handlers: the body is wrapped in newUnsignedV4ChunkedReader, which
verifies the request signature when credentials are present. The hasCreds gate
(Authorization header OR X-Amz-Credential query param) matches the
post-CVE-2026-41145 form so the query-string credential bypass (Vuln 2) is not
reintroduced. The Content-Length / X-Amz-Decoded-Content-Length size-decode
guard is also extended to cover the unsigned-trailer auth type, matching
PutObjectHandler.

A regression test (TestCVE202640344SnowballExtract in cmd/server_test.go)
exercises the full handler over HTTP: a Snowball extract PUT with a fabricated
signature is now rejected, while a legitimately signed extract still succeeds
and unpacks the tar into the bucket. The test fails without this fix and
passes with it.

Refs: GHSA-9c4q-hq6p-c237 / CVE-2026-40344

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Will Cooke <will.cooke@chainguard.dev>
@8none1

8none1 commented Jun 3, 2026

Copy link
Copy Markdown
Author

Second-pass review

Did an independent review of this change and it looks sound. Findings:

Root cause confirmed. On master, the auth switch in PutObjectExtractHandler only had cases for streaming-signed / signed-trailer, SigV2, and presigned/signed, with no authTypeStreamingUnsignedTrailer case and no default. So an unsigned-trailer Snowball extract request fell straight through the switch with zero signature verification, while isPutActionAllowed only checks the access key + IAM policy and not the signature. An attacker holding a valid access key but a fabricated Authorization signature could extract an arbitrary tar payload into the bucket. Real bug.

Fix approach is the lowest-risk option. The new case is a faithful mirror of the already-merged PutObjectHandler unsigned-trailer case: newUnsignedV4ChunkedReader(r, true, hasCreds), with the same hasCreds check across both the Authorization header and the X-Amz-Credential query param, which also closes the CVE-2026-41145 query-string bypass on this code path. Reusing the reviewed primitive rather than inventing a new one is exactly right. Extending the content-length guard to the unsigned-trailer type is also correct.

Tests cover the right cases: the fabricated-signature attack (must be rejected) and the legitimate signed extract (must still succeed, with the extracted object present). Good positive and negative coverage.

Within EmeritOSS source-CVE policy: small, contained, no API changes, reuses existing primitives. LGTM.

@sergiodj sergiodj merged commit 6871921 into chainguard-forks:master Jun 4, 2026
18 of 20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants