docs: record advisories SN-2026-006 to 010 and refresh contributors

Ledger entries for the zero-byte SSE-C key check, GetObjectAttributes
authentication, replication request trust, user and group status
authorization, and DeleteObjectVersion authorization, plus the Go 1.27
toolchain refresh. The ledger names pgsty/silo, CONTRIBUTORS lists the
per-bucket CORS, ChecksumType, and NoSuchBucket contributors, and the CORS
design record states its merged status without the review logs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PvgysXDmhPBBimCReYtA8q
Signed-off-by: Feng Ruohang <rh@vonng.com>
This commit is contained in:
Feng Ruohang
2026-09-02 14:06:56 +08:00
parent 8f2a30d9af
commit 00d864ed0e
5 changed files with 24 additions and 101 deletions
+10 -4
View File
@@ -1,6 +1,6 @@
# pgsty/minio Security Advisories
# pgsty/silo Security Advisories
This document summarizes fork-specific security fixes and closely related upgrade-impacting security notes in `pgsty/minio`. It is intentionally narrower than a full changelog and focuses on release-impacting security behavior.
This document summarizes fork-specific security fixes and closely related upgrade-impacting security notes in `pgsty/silo`. It is intentionally narrower than a full changelog and focuses on release-impacting security behavior.
Entries carry a CVE identifier where one exists. Where none does, they carry a fork-local `SN-<year>-<sequence>` identifier so that a finding without a CVE can still be referenced stably from release notes, commits and issues. An `SN-` identifier is **not** a CVE and is not registered in any vulnerability database; it is deliberately not written in CVE form so that scanners do not mistake it for one. Upstream `minio/minio` is archived, so for findings in inherited code there is no upstream maintainer to coordinate a CVE assignment with. `SN-2026-001` is the streaming-flush regression in `trackingResponseWriter`, which is a reliability defect rather than a security one and is tracked in the release notes rather than here.
@@ -24,10 +24,15 @@ The first Silo community release was cut from upstream history that already cont
| [CVE-2026-40344](https://github.com/advisories/GHSA-9c4q-hq6p-c237) | `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](https://github.com/advisories/GHSA-xh8f-g2qw-gcm7) | `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`](https://github.com/pgsty/silo-pkg/releases/tag/v3.11.0) and [`2f55347f7`](https://github.com/pgsty/minio/commit/2f55347f78352aed8e08866d370c9426c73362cf) | 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](https://silo.pgsty.com/administration/identity-access-management/policy-based-access-control/#condition-value-sources). |
| `SN-2026-003` | [`silo-pkg v3.11.0`](https://github.com/pgsty/silo-pkg/releases/tag/v3.11.0) and [`2f55347f7`](https://github.com/pgsty/silo/commit/2f55347f78352aed8e08866d370c9426c73362cf) | 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](https://silo.pgsty.com/administration/identity-access-management/policy-based-access-control/#condition-value-sources). |
| 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](https://github.com/minio/minio/discussions/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](source-address-trust.md). |
| `SN-2026-004` | [`silo-pkg v3.11.0`](https://github.com/pgsty/silo-pkg/releases/tag/v3.11.0) and [`97b7d2804`](https://github.com/pgsty/minio/commit/97b7d28040d109061c0a46a4c01bfc7800a97cc1) | 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](https://github.com/minio/minio/issues/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. |
| `SN-2026-004` | [`silo-pkg v3.11.0`](https://github.com/pgsty/silo-pkg/releases/tag/v3.11.0) and [`97b7d2804`](https://github.com/pgsty/silo/commit/97b7d28040d109061c0a46a4c01bfc7800a97cc1) | 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](https://github.com/minio/minio/issues/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. |
| `SN-2026-005` | [`silo-pkg v3.12.0`](https://github.com/pgsty/silo-pkg/releases/tag/v3.12.0) and [`eee05a17c`](https://github.com/pgsty/silo/commit/eee05a17c34a07cebb27220d12697be74c8bd617) | IAM named-policy and service-account policy writes | No direct remote exploit; policy-dependent | Rejects S3, S3 Tables, and KMS ARN namespace prefixes that name no resource, including their historical `*arn:...` serialization, in both `Resource` and `NotResource`. A resource-matching `Deny` using such a prefix could silently fail to deny, while an `Allow` with the prefix in `NotResource` could match far more broadly than intended. The guard applies when creating named policies and when creating or updating service-account session policies. | **This is an authorization tightening for new and updated policies.** Existing policies keep loading, matching, importing, and replicating with unchanged runtime behavior, but a policy containing one of these prefixes cannot be submitted unchanged; replace it with the intended concrete resource, or use an explicit wildcard such as `arn:aws:s3:::*` only when all resources are intended. Enabling the strict path also rejects an admin statement that combines `Resource` with `NotResource`, and rejects non-S3 resources on bucket-scoped admin actions. Here “bare ARN prefix” means a namespace with no resource after it (`arn:aws:s3:::`); it is distinct from the valid “bare bucket ARN” in `SN-2026-004` (`arn:aws:s3:::bucket`). IAM import, site-replication receive paths, stored-policy loading, and STS inline policies remain on the permissive compatibility path in this release. |
| `SN-2026-006` | [`b73581b05`](https://github.com/pgsty/silo/commit/b73581b05) and [`c4fd97d0b`](https://github.com/pgsty/silo/commit/c4fd97d0b) ([#82](https://github.com/pgsty/silo/issues/82)) | SSE-C reads of zero-byte objects (`GetObject`, `HeadObject`, `CopyObject` source, `GetObjectAttributes`) | Yes; requires read access to the object | Zero-byte SSE-C objects never unsealed the customer-provided key, so a wrong key was accepted with `200` instead of `403`, and a copy or new version could be created under a key of the caller's choosing without knowing the current one. | Wrong keys now fail with `403 AccessDenied` as on AWS; correct keys behave as before and no client change is needed. Inherited from upstream; every earlier release is affected. |
| `SN-2026-007` | [`474cd5801`](https://github.com/pgsty/silo/commit/474cd5801), [`74c97d005`](https://github.com/pgsty/silo/commit/74c97d005), [`21870fa2e`](https://github.com/pgsty/silo/commit/21870fa2e) ([#84](https://github.com/pgsty/silo/issues/84)) | `GetObjectAttributes` on SSE-C objects | Yes; requires read access to the object | Attributes of SSE-C objects were returned without authenticating the customer key, and a bare `X-Minio-Source-Replication-Request` header skipped the check entirely. | A wrong key returns `403`, a replication marker without the key returns `400`; replication peers holding `s3:ReplicateObject` are unaffected. Inherited from upstream. |
| `SN-2026-008` | [PR #101](https://github.com/pgsty/silo/pull/101) ([`938603458`](https://github.com/pgsty/silo/commit/938603458) through [`04b097fd9`](https://github.com/pgsty/silo/commit/04b097fd9)) | Internal replication request headers such as `X-Minio-Source-Etag`, `X-Minio-Source-Mtime`, `X-Minio-Source-Replication-Request`, the replication SSE key headers, and `X-Amz-Bucket-Replication-Status` on object reads, writes, multipart uploads, deletes, Snowball extraction, and bucket events | Yes; any authenticated principal that can read or write the object | Completes CVE-2026-34204. The server still trusted these internal headers on presence in most handlers: any client could preserve arbitrary ETags and modification times, read SSE-C ciphertext without the key, inject replication checksums and Object Lock timestamps, suppress bucket notifications, and route deletes as replication deletes. | Replication semantics now require the exact marker value together with `s3:ReplicateObject` or `s3:ReplicateDelete`; other requests have these headers removed after signature verification and are processed as ordinary requests. Site replication service accounts and bucket-replication targets that already hold the replication permissions are unaffected. Inherited from upstream. |
| `SN-2026-009` | [`58735ee38`](https://github.com/pgsty/silo/commit/58735ee38) and [`229fe2b3c`](https://github.com/pgsty/silo/commit/229fe2b3c) ([PR #73](https://github.com/pgsty/silo/pull/73)) | Admin `SetUserStatus` and `SetGroupStatus` | Yes; authenticated admin API | Status changes were authorized against `admin:EnableUser` / `admin:EnableGroup` regardless of the requested status, so a principal allowed only to enable could also disable, and vice versa. | Enable and disable now require the action matching the target status. Policies that grant only one of the pair lose the other operation; `admin:*` and the built-in `consoleAdmin` policy are unaffected. Inherited from upstream. |
| `SN-2026-010` | [PR #104](https://github.com/pgsty/silo/pull/104) ([`75a6734e4`](https://github.com/pgsty/silo/commit/75a6734e4) through [`d2d47a41f`](https://github.com/pgsty/silo/commit/d2d47a41f), [#58](https://github.com/pgsty/silo/issues/58)) | `DeleteObject` and `DeleteObjects` with an explicit `versionId` | Yes; authenticated S3 API | Explicit version deletes were authorized as `s3:DeleteObject` with only a deny check on `s3:DeleteObjectVersion`, diverging from AWS. | Explicit version deletes now require `s3:DeleteObjectVersion`, as on AWS. **Two policy effects:** principals granted only `s3:DeleteObject` can no longer delete specific versions, and a policy that relied on `Deny s3:DeleteObject` to block permanent deletes must also deny `s3:DeleteObjectVersion`, because `Allow s3:*` now permits explicit version deletes. Replication targets keep the `s3:ReplicateDelete` contract. Inherited from upstream. |
## Dependency security updates
@@ -36,6 +41,7 @@ The first Silo community release was cut from upstream history that already cont
| `CVE-2026-34986` | `68e0ba997` | Upgrades `go-jose` to `v4.1.4`. |
| `CVE-2026-39883` | `1869bd30b`, `e4fa06394` | Updates OpenTelemetry dependencies. |
| Upstream Go security fixes | [Go 1.26.5](https://go.dev/doc/devel/release#go1.26.5) | Bumps the required toolchain to Go 1.26.5, which includes security fixes to `crypto/tls` and `os`. |
| Toolchain and dependency refresh | [Go 1.27.0](https://go.dev/doc/devel/release#go1.27) via [`43f4bb7ed`](https://github.com/pgsty/silo/commit/43f4bb7ed), [`edc8be6ed`](https://github.com/pgsty/silo/commit/edc8be6ed), [`4d6e1ea8e`](https://github.com/pgsty/silo/commit/4d6e1ea8e) | Moves the toolchain to Go 1.27.0 and refreshes the dependency stack (Silo Go v7.3.1, etcd client v3.7.1, `jwx` v3.0.13, `klauspost/compress` v1.19.2). `govulncheck` reports no reachable vulnerability at `6586fbfd0`. |
| [GO-2026-6061](https://pkg.go.dev/vuln/GO-2026-6061) / [GHSA-hrxh-6v49-42gf](https://github.com/advisories/GHSA-hrxh-6v49-42gf) | gRPC `v1.82.1` | Updates gRPC to the first fixed version for vulnerabilities in the xDS RBAC authorization engine and HTTP/2 transport server. |
| [GO-2026-5970](https://pkg.go.dev/vuln/GO-2026-5970) / `CVE-2026-56852` | `x/text` `v0.39.0` | Updates `x/text` to the first fixed version for an infinite loop on invalid input. |