SILO 20260804 Release Notes

Internode storage containment, S3/IAM policy hardening, multipart correctness, streaming reliability, notification fixes, Go 1.26.5, and a rebuilt, signed release pipeline.

Version: RELEASE.2026-08-04T00-00-00Z · Commit: d88f46ccee345a9c2fabe2d221d9a9e56bc11aec

SILO 20260804 is a security, correctness, and release-engineering update to the pgsty/minio community fork. It completes the internode storage-containment work begun with CVE-2026-42600, prevents request-controlled values from impersonating server-calculated S3/IAM policy conditions, restores streaming flush behavior, fixes several multipart and versioning edge cases, hardens notification configuration migration, moves the build baseline to Go 1.26.5, and connects the server to the SILO-maintained Console, shared package, and mcli releases. The release pipeline was rebuilt to produce reproducible binaries and GPG-signed packages.

The release covers 50 commits after the pre-2026-06-18 baseline, changing 155 files with 9,241 insertions and 981 deletions. Every change was reviewed against the tagged commit and verified on macOS ARM64 and Linux AMD64, with GitHub CI green on the released HEAD.

Highlights

  • Internode containment completed: validates storage-REST message bodies, storage Grid frames, and peer-S3 Grid requests at the storage boundary, closing the remaining path, volume, erasure-metadata, panic, and unbounded-allocation defects left after removing ReadMultiple.
  • S3/IAM decisions now use effective values: client input can no longer shadow internal condition values; request tags and existing-object tags are separated; s3:signatureAge is confined to verified presigned requests; and s3:versionid follows the version the server actually acts on.
  • Bucket and object resources are separated: twelve sensitive bucket-level writes are no longer authorized through an object-only bucket/* resource pattern. A documented compatibility switch is available for migration.
  • Multipart compatibility and correctness improved: full-object checksum completion works without per-part checksums when the protocol permits it, zero-length multipart checksums are preserved, and duplicate part numbers are rejected instead of assembling duplicated data.
  • Streaming reliability restored: trackingResponseWriter now implements Flush correctly and records implicit HTTP 200 responses, repairing mcli watch, bucket-notification listeners, and S3 Select keep-alives affected by the inherited regression documented in the 20260618 release.
  • Notification configuration hardened: NATS and AMQP keys used by parsers and legacy migration are registered and round-trip correctly; libpq connection parameters are quoted safely; invalid-key errors no longer echo secret values.
  • Reproducible, signed release pipeline: binaries no longer embed the build machine’s paths, packages install under the canonical systemd path, and RPMs are GPG-signed. The container entrypoint now shuts down gracefully on every privilege path.
  • Release baseline refreshed: Go 1.26.5, klauspost/compress 1.18.7, Apache Thrift 0.24.0, SILO Console 2.0.0, silo-pkg 3.11.0, and mcli 20260804.

Security Hardening

Internode storage and Grid containment — SN-2026-002

Removing the obsolete ReadMultiple endpoint in 20260618 closed one reachable path but did not close the underlying defect class. Storage-REST request bodies and Grid RPC frames do not pass through the HTTP query-validation middleware, and peer-S3 RPCs can bypass the storage-REST wrapper entirely.

This release moves containment to the storage boundary and validates every caller-controlled path, volume, erasure parameter, part size, shard length, and allocation length before use. The fixes include:

  • reject traversal on both path and volume axes, including Windows volume-root aliases;
  • cover peer-S3 bucket RPCs that reach drives without the storage-REST wrapper;
  • reject zero or unusable data/parity/block-size combinations before shard arithmetic;
  • reject negative part sizes and truncated shards instead of reporting them healthy;
  • cap storage-REST ReadFile allocations at 5 GiB;
  • bound other allocations derived from internode declarations;
  • contain panics in deadline-bounded storage work without blocking the caller;
  • preserve ReadParts errors across keep-alive responses and avoid the empty-part trace panic.

These routes require cluster-root or internode credentials and are registered only in distributed-erasure deployments. Single-node S3 behavior is unchanged. See Internode Path Containment Audit for the protocol-surface analysis.

Effective policy-condition values — SN-2026-003

The policy condition map historically mixed values calculated by the server with raw request entries. A client-controlled spelling could therefore shadow or synthesize an internal condition value. SILO 20260804 pairs silo-pkg 3.11.0’s exact-key lookup rule with server-side source normalization:

  • internal condition names cannot be supplied as arbitrary client values;
  • s3:prefix, s3:delimiter, and s3:max-keys come from their effective query inputs;
  • header-backed x-amz-* conditions do not accept unrelated query substitutes;
  • when storage class or upload tagging supports both forms, an explicitly present Header wins, including an empty Header;
  • s3:ExistingObjectTag/* comes only from stored object metadata;
  • s3:RequestObjectTag/* is bound to the tag input consumed by the relevant operation;
  • s3:signatureAge is exposed only after verified SigV4 presigned authentication calculates it;
  • s3:versionid is absent when no version is named and is rebound per DeleteObjects entry to the effective resolved version.

The version-ID behavior closes the fail-open trap that a superficial “omit empty values” fix would have created for Multi-Delete. See Absent Is Not Empty.

Bucket/object resource boundary — SN-2026-004

The IAM matcher used to append a slash to a bucket-level request, allowing an object-only resource such as arn:aws:s3:::bucket/* to authorize selected bucket-level operations. This release withholds twelve sensitive writes from that pattern on Allow statements:

PutBucketPolicy, DeleteBucketPolicy, PutBucketObjectLockConfiguration, PutBucketVersioning, PutReplicationConfiguration, PutBucketLifecycle, DeleteBucket, ForceDeleteBucket, PutBucketCors, DeleteBucketCors, PutBucketQOS, and PutInventoryConfiguration.

Deny and NotResource behavior is unchanged. Read/list operations, CreateBucket, bucket tagging, default encryption, and notification configuration remain compatible. Built-in policies use Resource: "*" and are not affected.

Trusted client-address boundary

MINIO_API_TRUSTED_PROXIES provides an enforceable, opt-in boundary for aws:SourceIp, audit remotehost, event notification Host, and the client address shown by mcli admin trace:

  • set it to an address/CIDR list to trust forwarding headers only from those peers and walk forwarding chains from right to left;
  • set it to none to ignore all forwarding headers;
  • leave it unset to preserve historical behavior exactly.

The old _MINIO_API_XFF_HEADER=off switch still suppresses only X-Forwarded-For; it does not protect against X-Real-IP or RFC 7239 Forwarded. If IP-based policy is part of your security boundary, configure trusted proxies explicitly and prevent direct access to the S3 API port. Multi-node deployments should allow their own node addresses. See Client Source Address Trust.

S3 and Storage Correctness

Multipart upload

  • CompleteMultipartUpload accepts the S3 full-object checksum mode when the completed request supplies no per-part checksums and the upload metadata does not require them.
  • The checksum of a zero-length multipart object is retained instead of being discarded as empty metadata.
  • Part numbers must be strictly increasing. Duplicate entries such as [1,1] now return InvalidPartOrder instead of consuming the upload and assembling the same part twice. Legal part lists with gaps or a non-1 start remain accepted. See Duplicate Part Numbers.

Object reads and buffer ownership

  • erasure reads again pool buffers only where ownership permits reuse;
  • update downloads return caller-owned buffers instead of exposing data that can be overwritten after return;
  • the old HTTP streaming helpers orphaned by ReadMultiple removal are deleted after reference and platform-tag checks.

HTTP response tracking and S3 Select

  • trackingResponseWriter.Flush() delegates to the underlying flusher and commits the response state correctly;
  • the first implicit write records HTTP 200, preserving audit and metric accuracy;
  • S3 Select tests no longer race a client parser against response-body ownership;
  • CSV, JSON, and Parquet selection paths remain covered, including range/error and keep-alive behavior.

The inherited silent-flush regression called out in SILO 20260618 is therefore fixed in this release.

IAM, Versioning, and Audit Behavior

  • DeleteObject and each entry in DeleteObjects evaluate s3:versionid against the effective version selected by the server.
  • Request tags can no longer impersonate existing-object tags during policy evaluation.
  • The merrs tag is restored when dangling-object deletion records are emitted, preserving the intended audit classification.
  • Bucket-policy and IAM paths share the hardened condition-source rules while retaining their established S3 routing and error behavior.

Notification Configuration

  • registers the NATS user_credentials, nkey_seed, and tls_handshake_first keys read by the parser;
  • separates the legacy NATS environment-variable spelling from the stored config key;
  • repairs NATS migration round trips and the AMQP immediate/internal mapping;
  • adds a mechanical audit that compares keys read and written by notification code with each subsystem’s registered schema;
  • quotes libpq connection-string parameters so whitespace, quotes, and backslashes retain their intended value;
  • prevents invalid-key diagnostics from echoing secret values.

See Notify Keyspace Registration.

Components and Dependencies

  • Go 1.26.5: includes security fixes in crypto/tls and os plus compiler, runtime, networking, and syscall corrections.
  • klauspost/compress 1.18.7: refreshes the compression stack used by object and archive paths.
  • Apache Thrift 0.24.0: updates the dependency compiled through Parquet support.
  • go-systemd 22.6.0: deliberately retained instead of 22.7.0 because the later version introduced a NetBSD clock dependency incompatible with the supported cross-build matrix.
  • SILO Console 2.0.0: the embedded console is selected from pgsty/silo-console while preserving the compatible github.com/minio/console import path.
  • silo-pkg 3.11.0: provides the companion policy, LDAP, certificate, RNG, and time-format fixes while preserving the github.com/minio/pkg/v3 module path.
  • mcli 20260804: the embedded client comes from pgsty/mc; release images expose it as mcli and keep the mc compatibility alias.

See the companion release notes for silo-pkg 3.11.0, mcli 20260804, and SILO Console 2.0.0.

Build, CI, and Packaging

This release rebuilt the release pipeline for reproducibility and supply-chain integrity:

  • Graceful container shutdown on every path. The entrypoint’s custom UID/GID branches now exec into the server so it runs as PID 1 and receives SIGTERM directly; previously those branches left an intermediate shell as PID 1 and the server was killed at the container stop timeout. A CI smoke test builds the release runtime image and asserts graceful shutdown on both the default and drop-privilege paths.
  • Reproducible binaries. Release binaries no longer embed the build machine’s GOPATH/GOROOT, so -trimpath holds and a third party rebuilding the tag gets matching bytes. The published Linux binary contains no build-host path.
  • Hardened release workflow. The release tag is passed through the environment and whitelisted rather than spliced into the shell, the build is checked out at the tag being released, and an untracked shadow GoReleaser config that could publish or move latest out of band was removed.
  • Honest gates. CI gates build, vet, unit tests, lint, generation drift, race tests, and cross-compilation; the cross-compile matrix is aligned to the exact set of published targets; and the lint and dependency-install steps now fail on real errors instead of masking them.
  • Signed, canonical packages. RPM, DEB, and APK packages are produced with nFPM under the PGSTY identity, the systemd unit installs at /usr/lib/systemd/system/minio.service with Type=notify, and RPMs are GPG-signed offline with the PGSTY maintainer key (fingerprint 9592A7BC 7A682E73 33376E09 E7935D8D B9BD8B20).
  • Release and container publication remain separate gates. GoReleaser produces the platform archives, checksums, and packages; the multi-architecture image is published on demand from the finished release. A local snapshot does not prove a public release or image exists.

Compatibility and Upgrade Notes

  1. Keep every node on one release during a cluster rollout. Internode validation changed across storage-REST and Grid surfaces; mixed binaries were not production-tested.
  2. Audit custom IAM policies. Add the bare bucket ARN for the twelve protected bucket writes. Use MINIO_API_LEGACY_BUCKET_RESOURCE_MATCH=on only as a temporary migration control.
  3. Configure client-address trust deliberately. If aws:SourceIp or audit attribution matters, set MINIO_API_TRUSTED_PROXIES and close direct network paths around the proxy.
  4. Review legacy database notification settings. Convert Postgres/MySQL host/user/password fields to the supported connection-string format before restart.
  5. Expect duplicate multipart completion entries to fail. Clients sending the same part number more than once now receive InvalidPartOrder instead of a corrupted successful object.
  6. Use the matching mcli. The 20260804 client disables self-update and must be upgraded through packages or GitHub Releases; mcli update remains as a compatibility command but exits non-zero.
  7. RPM users can enable signature verification. Packages are signed with the maintainer key above; import it before enabling gpgcheck for the SILO packages.

Verification

Changes were reviewed against the tagged commit and re-verified rather than trusted from prior reports:

  • git diff --check, gofmt, module verification, and YAML/shell syntax;
  • go build ./..., go vet ./..., project lint, and govulncheck ./...;
  • full go test ./..., the complete race suite, and repeated race tests over storage, policy, notification, HTTP tracking, and S3 Select changes;
  • generator idempotence plus deliberate stale-source and untracked-output counterexamples;
  • cross-compilation across every published target;
  • Linux AMD64 native full tests, targeted race tests, live S3/mcli smoke tests (create/upload/download/copy, range, versioning, delete markers, health checks, graceful shutdown, restart persistence), and systemd notify behavior;
  • release-artifact verification: GitHub CI green on the released HEAD, reproducible binaries with no build-host path, the systemd unit installed at /usr/lib/systemd/system, and RPM signatures validated with rpmkeys --checksig.

govulncheck found no vulnerability reachable from the Server or mcli code. One module-level notice remains for the unmaintained golang.org/x/crypto/openpgp package (GO-2026-5932); that package is not imported into these binaries.

Validation boundaries

The following were not proven by this release and must not be inferred from cross-compilation or unit tests:

  • native Windows execution and Windows filesystem semantics;
  • Intel macOS and physical Linux ARM64 hosts;
  • a production multi-node rolling upgrade, site replication, or lifecycle expiration run;
  • real reverse-proxy chains and direct-ingress isolation;
  • external LDAP, OIDC, KMS, STS, Postgres, MySQL, NATS, and AMQP services;
  • installing and upgrading the signed package under a real systemd host.

Artifacts

  • GitHub release RELEASE.2026-08-04T00-00-00Z with checksummed platform archives for Linux, Darwin, and Windows on amd64 and arm64;
  • RPM, DEB, and APK packages under the PGSTY identity, with GPG-signed RPMs;
  • docker.io/pgsty/minio:RELEASE.2026-08-04T00-00-00Z and the release-selected latest tag, published on demand from the release;
  • matching SILO Console 2.0.0, silo-pkg 3.11.0, and mcli 20260804 references.

Selected Changes

  • ca7baa670, 80e8eaa42, b6f70ab08: validate internode paths, erasure metadata, and allocation sizes
  • a36fd8fff: contain panics in deadline-bounded storage work
  • 2f55347f7: bind S3/IAM policy conditions to effective request values
  • 744a9dcd7: bind s3:versionid to the effective object version
  • 97b7d2804: enforce the bucket/object resource boundary
  • fe6dc4780: add the trusted-proxy client-address boundary
  • 22c1e41fd: reject duplicate multipart part numbers
  • c8590413f, 3e14733f1: restore full-object and zero-length multipart checksum behavior
  • 8069a32ac, 65795ee1f: restore response commit and streaming flush semantics
  • 162ded343, 0c14d8151: repair notification key registration and libpq quoting
  • 924717926, 89d346bf5: restore safe buffer pooling and returned-buffer ownership
  • 3b8a55dee: exec into the dropped-privilege process so signals reach the server
  • 2ca4971d9: stop stamping the build machine’s paths into the binary
  • 4c185d5a6, e064b5555: harden the release workflow and remove the shadow config
  • aa5139369: install the systemd unit under /usr/lib
  • 11d79fddc, ca674a696, 021110b45, d88f46cce: gate build, vet, tests, lint, generation, race, and cross-compilation, and smoke-test the release image
Last modified: 2026-08-05: 2026-08-05 release (23a05b5)