CVE-2026-33322 |
d24f449e0 |
OIDC STS (AssumeRoleWithWebIdentity, AssumeRoleWithClientGrants) |
Yes |
Closes JWT algorithm confusion by removing HMAC/shared-secret verification and requiring JWKS-backed verifier keys |
Breaking change: providers issuing HS256, HS384, or HS512 tokens for these STS flows must switch to JWKS-backed RSA or ECDSA signing before upgrading. PS256 and EdDSA are not currently supported. |
CVE-2026-33419 |
3b950f8fa |
LDAP STS authentication |
Yes |
Prevents username enumeration by unifying unknown-user and bad-password responses and adds in-memory login throttling |
Unknown users and invalid passwords now both return 400 InvalidParameterValue. Rate limiting is per-node, in-memory, and not currently configurable. Follow-up hardening landed in 18b712d49, 9e10f6d9a, and f44110890. |
CVE-2026-34204 |
56fa63bfd |
Replication metadata handling |
Yes |
Blocks untrusted X-Minio-Replication-* headers from being smuggled into internal replication metadata and leaving objects unreadable |
Upgrade any server that accepts untrusted PutObject or CopyObject requests, which in practice means almost any production server that accepts writes. |
CVE-2026-39414 |
3252d5b7f |
S3 Select oversized record handling |
Yes |
Rejects oversized CSV records and non-simdjson line-delimited JSON records with OverMaxRecordSize instead of buffering them unchecked |
Split oversized JSON lines client-side if you rely on simdjson input paths until the fast path gains the same pre-check. |
| CVE-2026-41145 |
f444b6f37 |
Unsigned-trailer PUT and multipart upload authentication |
Yes |
Closes the query-string authentication bypass in unsigned-trailer streaming requests |
Upgrade if clients can reach object write endpoints using the STREAMING-UNSIGNED-PAYLOAD-TRAILER content-sha256 mode together with query-string SigV4 credentials. |
| CVE-2026-40344 |
efb6e5b00 |
Snowball auto-extract authentication |
Yes |
Verifies request authentication before tar extraction in Snowball unsigned-trailer flows |
Upgrade if you use PutObjectExtract or Snowball uploads. |
| CVE-2026-42600 |
73ac52472 |
Internode ReadMultiple storage-REST endpoint |
Yes (cluster-root JWT required) |
Removes the unused endpoint that allowed path traversal outside configured drive roots |
Upgrade distributed-erasure deployments. Single-node deployments do not register this route. |
SN-2026-002 |
ca7baa670 and follow-ups |
Internode storage-REST and Grid RPC payloads |
Yes (cluster-root / internode JWT required) |
Completes CVE-2026-42600. Its fix removed one endpoint that exercised the gap; the gap itself -- request bodies and grid frames never reaching the validity middleware, and no containment in the storage layer -- remained across three further protocol surfaces. Closes path traversal on both the volume and path axes (including the peer-S3 bucket RPCs, which bypass the storage-REST wrapper entirely), an unrecoverable divide-by-zero that killed a node per RPC frame, metadata that reported truncated shards as intact, and three allocations sized from caller-declared values. |
Upgrade distributed-erasure deployments. Single-node deployments register none of these routes. No S3 API behaviour changes; object keys containing . or .. path segments were already refused at the S3 boundary. |
SN-2026-003 |
silo-pkg v3.11.0 and 2f55347f7 |
S3/IAM bucket-policy condition values |
Yes (policy-dependent) |
Prevents raw request entries that spell condition-key names from shadowing or synthesizing internal condition values; confines s3:signatureAge to verified SigV4 presigned requests; separates query-only list fields from header-backed x-amz-* fields; and stops client request tags from impersonating stored existing-object tags. |
The compatible query form remains for storage class and upload tagging on handlers that consume it; an explicitly present header wins, including an empty header. The historical X-Amz-Tagging Header mapping remains a client-supplied RequestObjectTag source, so use request-tag conditions only on operations that consume tags. Header-only x-amz-* policy keys no longer accept query substitutes. aws:SourceIp was left following the existing forwarding-header trust model; that model is addressed separately in the next row. See Condition value sources and precedence. |
| Not a vulnerability |
fe6dc4780 |
Client source address (aws:SourceIp, audit remotehost, event notification Host) |
N/A -- opt-in hardening |
Adds an enforceable forwarded-header trust boundary, MINIO_API_TRUSTED_PROXIES. Set to a list of addresses or CIDR blocks, forwarded headers are believed only from those peers and forwarding chains are read right-to-left past listed hops -- which also stops the client-supplied left-most entry that an appending proxy (the stock nginx $proxy_add_x_forwarded_for recipe, or HAProxy's added second header line) leaves in place. Set to none, no forwarded header is believed at all. This is the guarantee _MINIO_API_XFF_HEADER=off never provided: it suppresses X-Forwarded-For alone, so X-Real-IP and RFC 7239 Forwarded remain one-line substitutions for anyone that setting was meant to stop. |
No behaviour change for any existing deployment, so there is nothing to do on upgrade unless you want the new boundary. Not assigned a CVE: the default matches upstream, and upstream's own position (maintainer response in discussion #17878, Aug 2023) is that IP-based restrictions are impractical without reliable source-IP visibility. The gap being closed is that this was never written anywhere an operator would find it -- an IpAddress condition is accepted and behaves as though it works. If you use IpAddress or NotIpAddress conditions, note that they were not enforceable before this change, including behind a reverse proxy whose X-Forwarded-For recipe appends rather than overwrites. If you do not, the change affects only the accuracy of client addresses in logs. The new variable is opt-in and inert when unset; _MINIO_API_XFF_HEADER keeps its exact upstream semantics, and upstream's TestXFFDisabled is retained unmodified as the proof. An IpAddress condition remains unenforceable by default against a client with direct network access to the API port -- that is the condition the allowlist exists to fix, not a regression introduced here. When enabling the allowlist: it must name proxies, not the subnet they sit in, because entries are skipped while walking the chain, so a range that also covers clients lets those clients forge. Multi-node deployments must include their own node addresses, since MinIO forwards some requests between nodes and a client can force a hop through the ListObjectsV2 continuation token; prefer the allowlist over none on a cluster for that reason. Loopback is always trusted as a peer so FTP and SFTP keep attributing their sessions. A malformed value stops startup, as does one that names no proxy at all (",") or one whose env:// remote could not be read -- env.Get discards that error and yields an empty string, which would otherwise read as unset. Whitespace-only remains equivalent to unset. The policy is read after MINIO_CONFIG_ENV_FILE is loaded so environment-file deployments are covered; _MINIO_API_XFF_HEADER deliberately keeps upstream's earlier read timing, where a value written into an environment file is ignored. MINIO_IDENTITY_LDAP_STS_TRUSTED_PROXIES now shares the same list parser, but is behaviourally untouched: the extraction is pure code motion, verified identical to the previous implementation across every combination of 37 allowlist values and 21 peer addresses. See Client source address trust. |
SN-2026-004 |
silo-pkg v3.11.0 and 97b7d2804 |
IAM policy evaluation of bucket-level actions |
Yes (policy-dependent) |
Withholds twelve sensitive bucket-level writes from an object-only resource pattern. The IAM matcher appended a trailing slash for bucket-level requests (empty object name), so a resource of arn:aws:s3:::bucket/* matched "bucket/" and authorized bucket-level actions it was never meant to reach -- upstream minio/minio#20449. The bucket-policy evaluation path never had the slash and was already reference-correct. |
This is an authorization tightening; read this row before upgrading if you write your own bucket-scoped policies. Withheld from bucket/* on Allow statements only: PutBucketPolicy, DeleteBucketPolicy, PutBucketObjectLockConfiguration, PutBucketVersioning, PutReplicationConfiguration, PutBucketLifecycle, DeleteBucket, ForceDeleteBucket, PutBucketCors, DeleteBucketCors, PutBucketQOS, PutInventoryConfiguration. Membership was decided by one question -- does reaching this action give the caller something its object-scoped grant does not already give it? -- because the bug only fires when the statement already grants the bucket action, which in practice means s3:*, so the affected principal already holds full object CRUD. Only actions that hand out access to others, defeat a protection aimed at write-holders, act under server credentials, outlive the grant, or destroy the bucket entity qualify. Deliberately not withheld, and asserted by test so re-adding one is a deliberate act: ListBucket, GetBucketLocation and the read/list family, PutBucketTagging, PutBucketEncryption, PutBucketNotification, and CreateBucket -- so mc ls, SDK session setup and ordinary tenant self-service keep working through bucket/*. Breaking those is what got upstream's own full fix reverted. What to change: add the bare bucket ARN (arn:aws:s3:::bucket) alongside arn:aws:s3:::bucket/* in any statement that legitimately grants one of the twelve. Built-in canned policies are unaffected (all use Resource: "*"). Deny statements are untouched, so no bucket lock is ever weakened, and NotResource exclusions keep their full reach. The hardening is monotone by construction rather than by argument: the protected path requires both the bare and the historical "bucket/" form to match, an intersection with the historical decision -- without that, a fixed-width wildcard such as mybucke? would match "mybucket" while never having matched "mybucket/", and the hardening would have granted a write the buggy matcher refused. MINIO_API_LEGACY_BUCKET_RESOURCE_MATCH=on restores the historical behaviour in full; it is read once at startup. Still deferred to a migration-gated release: the read/list family, a startup audit naming affected policies, and a self-explaining denial log. |