# MinIO AIStor EDGE.2026-08-18T04-46-14Z

Released: 2026-08-18

This EDGE build closes a significant set of authorization and disclosure defects
across IAM policy evaluation, STS session tokens, batch jobs and the GPU-Direct
RDMA write path. It brings GPU-Direct and internode RDMA to native InfiniBand
fabrics, extends AIStor Tables with Iceberg SQL function catalog metadata and
on-demand snapshot maintenance, and extends config.yaml coverage to identity,
STS and server-wide settings. Operators running batch jobs with non-admin
submitters, or dashboards built on the scanner excess-folders/versions alerts,
should read Breaking Changes before upgrading.

---

## Downloads

### Binary Downloads

| Platform | Architecture | Download                                                                 |
| -------- | ------------ | ------------------------------------------------------------------------ |
| Linux    | amd64        | [minio](https://dl.min.io/aistor/minio/edge/linux-amd64/minio)           |
| Linux    | arm64        | [minio](https://dl.min.io/aistor/minio/edge/linux-arm64/minio)           |
| macOS    | arm64        | [minio](https://dl.min.io/aistor/minio/edge/darwin-arm64/minio)          |
| macOS    | amd64        | [minio](https://dl.min.io/aistor/minio/edge/darwin-amd64/minio)          |
| Windows  | amd64        | [minio.exe](https://dl.min.io/aistor/minio/edge/windows-amd64/minio.exe) |

### FIPS Binaries

| Platform | Architecture | Download                                                                 |
| -------- | ------------ | ------------------------------------------------------------------------ |
| Linux    | amd64        | [minio.fips](https://dl.min.io/aistor/minio/edge/linux-amd64/minio.fips) |

### GPU-Direct RDMA Binaries

| Platform | Architecture | Download                                                                 |
| -------- | ------------ | ------------------------------------------------------------------------ |
| Linux    | amd64        | [minio.rdma](https://dl.min.io/aistor/minio/edge/linux-amd64/minio.rdma) |
| Linux    | arm64        | [minio.rdma](https://dl.min.io/aistor/minio/edge/linux-arm64/minio.rdma) |

### Package Downloads

| Format | Architecture | Download                                                                                                                         |
| ------ | ------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| DEB    | amd64        | [minio_20260818044614.0.0_amd64.deb](https://dl.min.io/aistor/minio/edge/linux-amd64/minio_20260818044614.0.0_amd64.deb)         |
| DEB    | arm64        | [minio_20260818044614.0.0_arm64.deb](https://dl.min.io/aistor/minio/edge/linux-arm64/minio_20260818044614.0.0_arm64.deb)         |
| RPM    | amd64        | [minio-20260818044614.0.0-1.x86_64.rpm](https://dl.min.io/aistor/minio/edge/linux-amd64/minio-20260818044614.0.0-1.x86_64.rpm)   |
| RPM    | arm64        | [minio-20260818044614.0.0-1.aarch64.rpm](https://dl.min.io/aistor/minio/edge/linux-arm64/minio-20260818044614.0.0-1.aarch64.rpm) |

RDMA-enabled packages are published alongside the standard ones as
`minio.rdma_20260818044614.0.0_amd64.deb` and
`minio.rdma-20260818044614.0.0-1.x86_64.rpm`.

<details>
<summary>All published assets, including checksums and signatures</summary>

#### darwin-amd64

- [minio](https://dl.min.io/aistor/minio/edge/darwin-amd64/archive/minio)
- [minio.EDGE.2026-08-18T04-46-14Z](https://dl.min.io/aistor/minio/edge/darwin-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z)
- [minio.EDGE.2026-08-18T04-46-14Z.sha256sum](https://dl.min.io/aistor/minio/edge/darwin-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z.sha256sum)
- [minio.sha256sum](https://dl.min.io/aistor/minio/edge/darwin-amd64/archive/minio.sha256sum)
- [minio.EDGE.2026-08-18T04-46-14Z.asc](https://dl.min.io/aistor/minio/edge/darwin-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z.asc)
- [minio.EDGE.2026-08-18T04-46-14Z.minisig](https://dl.min.io/aistor/minio/edge/darwin-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z.minisig)
- [minio.asc](https://dl.min.io/aistor/minio/edge/darwin-amd64/archive/minio.asc)
- [minio.minisig](https://dl.min.io/aistor/minio/edge/darwin-amd64/archive/minio.minisig)

#### darwin-arm64

- [minio](https://dl.min.io/aistor/minio/edge/darwin-arm64/archive/minio)
- [minio.EDGE.2026-08-18T04-46-14Z](https://dl.min.io/aistor/minio/edge/darwin-arm64/archive/minio.EDGE.2026-08-18T04-46-14Z)
- [minio.EDGE.2026-08-18T04-46-14Z.sha256sum](https://dl.min.io/aistor/minio/edge/darwin-arm64/archive/minio.EDGE.2026-08-18T04-46-14Z.sha256sum)
- [minio.sha256sum](https://dl.min.io/aistor/minio/edge/darwin-arm64/archive/minio.sha256sum)
- [minio.EDGE.2026-08-18T04-46-14Z.asc](https://dl.min.io/aistor/minio/edge/darwin-arm64/archive/minio.EDGE.2026-08-18T04-46-14Z.asc)
- [minio.EDGE.2026-08-18T04-46-14Z.minisig](https://dl.min.io/aistor/minio/edge/darwin-arm64/archive/minio.EDGE.2026-08-18T04-46-14Z.minisig)
- [minio.asc](https://dl.min.io/aistor/minio/edge/darwin-arm64/archive/minio.asc)
- [minio.minisig](https://dl.min.io/aistor/minio/edge/darwin-arm64/archive/minio.minisig)

#### linux-amd64

- [minio](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio)
- [minio.EDGE.2026-08-18T04-46-14Z](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z)
- [minio.EDGE.2026-08-18T04-46-14Z.rdma](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z.rdma)
- [minio.rdma](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.rdma)
- [aistor-20260818044614.0.0-1.x86_64.rpm.sha256sum](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/aistor-20260818044614.0.0-1.x86_64.rpm.sha256sum)
- [aistor_20260818044614.0.0_amd64.deb.sha256sum](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/aistor_20260818044614.0.0_amd64.deb.sha256sum)
- [aistor_20260818044614.0.0_x86_64.apk.sha256sum](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/aistor_20260818044614.0.0_x86_64.apk.sha256sum)
- [minio-20260818044614.0.0-1.x86_64.rpm.sha256sum](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio-20260818044614.0.0-1.x86_64.rpm.sha256sum)
- [minio.EDGE.2026-08-18T04-46-14Z.rdma.sha256sum](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z.rdma.sha256sum)
- [minio.EDGE.2026-08-18T04-46-14Z.sha256sum](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z.sha256sum)
- [minio.rdma.sha256sum](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.rdma.sha256sum)
- [minio.sha256sum](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.sha256sum)
- [minio_20260818044614.0.0_amd64.deb.sha256sum](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio_20260818044614.0.0_amd64.deb.sha256sum)
- [minio_20260818044614.0.0_x86_64.apk.sha256sum](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio_20260818044614.0.0_x86_64.apk.sha256sum)
- [minio.EDGE.2026-08-18T04-46-14Z.asc](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z.asc)
- [minio.EDGE.2026-08-18T04-46-14Z.minisig](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z.minisig)
- [minio.EDGE.2026-08-18T04-46-14Z.rdma.asc](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z.rdma.asc)
- [minio.EDGE.2026-08-18T04-46-14Z.rdma.minisig](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z.rdma.minisig)
- [minio.asc](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.asc)
- [minio.minisig](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.minisig)
- [minio.rdma.asc](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.rdma.asc)
- [minio.rdma.minisig](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.rdma.minisig)
- [aistor-20260818044614.0.0-1.x86_64.rpm](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/aistor-20260818044614.0.0-1.x86_64.rpm)
- [aistor.apk](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/aistor.apk)
- [aistor.deb](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/aistor.deb)
- [aistor.rpm](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/aistor.rpm)
- [aistor_20260818044614.0.0_amd64.deb](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/aistor_20260818044614.0.0_amd64.deb)
- [aistor_20260818044614.0.0_x86_64.apk](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/aistor_20260818044614.0.0_x86_64.apk)
- [minio-20260818044614.0.0-1.x86_64.rpm](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio-20260818044614.0.0-1.x86_64.rpm)
- [minio.apk](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.apk)
- [minio.deb](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.deb)
- [minio.rdma-20260818044614.0.0-1.x86_64.rpm](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.rdma-20260818044614.0.0-1.x86_64.rpm)
- [minio.rdma_20260818044614.0.0_amd64.deb](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.rdma_20260818044614.0.0_amd64.deb)
- [minio.rdma_20260818044614.0.0_x86_64.apk](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.rdma_20260818044614.0.0_x86_64.apk)
- [minio.rpm](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.rpm)
- [minio_20260818044614.0.0_amd64.deb](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio_20260818044614.0.0_amd64.deb)
- [minio_20260818044614.0.0_x86_64.apk](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio_20260818044614.0.0_x86_64.apk)

#### linux-amd64 (FIPS)

- [minio.EDGE.2026-08-18T04-46-14Z.fips](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z.fips)
- [minio.fips](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.fips)
- [minio.EDGE.2026-08-18T04-46-14Z.fips.sha256sum](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z.fips.sha256sum)
- [minio.fips.sha256sum](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.fips.sha256sum)
- [minio.EDGE.2026-08-18T04-46-14Z.fips.asc](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z.fips.asc)
- [minio.EDGE.2026-08-18T04-46-14Z.fips.minisig](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.EDGE.2026-08-18T04-46-14Z.fips.minisig)
- [minio.fips.asc](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.fips.asc)
- [minio.fips.minisig](https://dl.min.io/aistor/minio/edge/linux-amd64/archive/minio.fips.minisig)

#### linux-arm64

- [minio](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio)
- [minio.EDGE.2026-08-18T04-46-14Z](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.EDGE.2026-08-18T04-46-14Z)
- [minio.EDGE.2026-08-18T04-46-14Z.rdma](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.EDGE.2026-08-18T04-46-14Z.rdma)
- [minio.rdma](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.rdma)
- [aistor-20260818044614.0.0-1.aarch64.rpm.sha256sum](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/aistor-20260818044614.0.0-1.aarch64.rpm.sha256sum)
- [aistor_20260818044614.0.0_aarch64.apk.sha256sum](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/aistor_20260818044614.0.0_aarch64.apk.sha256sum)
- [aistor_20260818044614.0.0_arm64.deb.sha256sum](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/aistor_20260818044614.0.0_arm64.deb.sha256sum)
- [minio-20260818044614.0.0-1.aarch64.rpm.sha256sum](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio-20260818044614.0.0-1.aarch64.rpm.sha256sum)
- [minio.EDGE.2026-08-18T04-46-14Z.rdma.sha256sum](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.EDGE.2026-08-18T04-46-14Z.rdma.sha256sum)
- [minio.EDGE.2026-08-18T04-46-14Z.sha256sum](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.EDGE.2026-08-18T04-46-14Z.sha256sum)
- [minio.rdma.sha256sum](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.rdma.sha256sum)
- [minio.sha256sum](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.sha256sum)
- [minio_20260818044614.0.0_aarch64.apk.sha256sum](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio_20260818044614.0.0_aarch64.apk.sha256sum)
- [minio_20260818044614.0.0_arm64.deb.sha256sum](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio_20260818044614.0.0_arm64.deb.sha256sum)
- [minio.EDGE.2026-08-18T04-46-14Z.asc](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.EDGE.2026-08-18T04-46-14Z.asc)
- [minio.EDGE.2026-08-18T04-46-14Z.minisig](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.EDGE.2026-08-18T04-46-14Z.minisig)
- [minio.EDGE.2026-08-18T04-46-14Z.rdma.asc](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.EDGE.2026-08-18T04-46-14Z.rdma.asc)
- [minio.EDGE.2026-08-18T04-46-14Z.rdma.minisig](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.EDGE.2026-08-18T04-46-14Z.rdma.minisig)
- [minio.asc](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.asc)
- [minio.minisig](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.minisig)
- [minio.rdma.asc](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.rdma.asc)
- [minio.rdma.minisig](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.rdma.minisig)
- [aistor-20260818044614.0.0-1.aarch64.rpm](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/aistor-20260818044614.0.0-1.aarch64.rpm)
- [aistor.apk](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/aistor.apk)
- [aistor.deb](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/aistor.deb)
- [aistor.rpm](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/aistor.rpm)
- [aistor_20260818044614.0.0_aarch64.apk](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/aistor_20260818044614.0.0_aarch64.apk)
- [aistor_20260818044614.0.0_arm64.deb](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/aistor_20260818044614.0.0_arm64.deb)
- [minio-20260818044614.0.0-1.aarch64.rpm](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio-20260818044614.0.0-1.aarch64.rpm)
- [minio.apk](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.apk)
- [minio.deb](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.deb)
- [minio.rdma-20260818044614.0.0-1.aarch64.rpm](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.rdma-20260818044614.0.0-1.aarch64.rpm)
- [minio.rdma_20260818044614.0.0_aarch64.apk](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.rdma_20260818044614.0.0_aarch64.apk)
- [minio.rdma_20260818044614.0.0_arm64.deb](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.rdma_20260818044614.0.0_arm64.deb)
- [minio.rpm](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio.rpm)
- [minio_20260818044614.0.0_aarch64.apk](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio_20260818044614.0.0_aarch64.apk)
- [minio_20260818044614.0.0_arm64.deb](https://dl.min.io/aistor/minio/edge/linux-arm64/archive/minio_20260818044614.0.0_arm64.deb)

#### windows-amd64

- [minio.exe](https://dl.min.io/aistor/minio/edge/windows-amd64/archive/minio.exe)
- [minio.exe.EDGE.2026-08-18T04-46-14Z](https://dl.min.io/aistor/minio/edge/windows-amd64/archive/minio.exe.EDGE.2026-08-18T04-46-14Z)
- [minio.exe.EDGE.2026-08-18T04-46-14Z.sha256sum](https://dl.min.io/aistor/minio/edge/windows-amd64/archive/minio.exe.EDGE.2026-08-18T04-46-14Z.sha256sum)
- [minio.exe.sha256sum](https://dl.min.io/aistor/minio/edge/windows-amd64/archive/minio.exe.sha256sum)
- [minio.exe.EDGE.2026-08-18T04-46-14Z.asc](https://dl.min.io/aistor/minio/edge/windows-amd64/archive/minio.exe.EDGE.2026-08-18T04-46-14Z.asc)
- [minio.exe.EDGE.2026-08-18T04-46-14Z.minisig](https://dl.min.io/aistor/minio/edge/windows-amd64/archive/minio.exe.EDGE.2026-08-18T04-46-14Z.minisig)
- [minio.exe.asc](https://dl.min.io/aistor/minio/edge/windows-amd64/archive/minio.exe.asc)
- [minio.exe.minisig](https://dl.min.io/aistor/minio/edge/windows-amd64/archive/minio.exe.minisig)

<!-- Release notes generated using configuration in .github/release.yml at EDGE.2026-08-18T04-46-14Z -->

</details>

### Container Images

```bash
# Standard
docker pull quay.io/minio/aistor/minio:EDGE.2026-08-18T04-46-14Z
podman pull quay.io/minio/aistor/minio:EDGE.2026-08-18T04-46-14Z

# FIPS
docker pull quay.io/minio/aistor/minio:EDGE.2026-08-18T04-46-14Z.fips
podman pull quay.io/minio/aistor/minio:EDGE.2026-08-18T04-46-14Z.fips
```

Note: Homebrew is only available for RELEASE builds, not EDGE builds.

---

## Breaking Changes

- **Batch jobs are now authorized as the submitting identity.** Batch
  `replicate`, `expire` and `keyrotate` previously discarded the submitter
  credential and ran data-plane operations on the unauthenticated object layer,
  so `admin:StartBatchJob` alone was enough to read, write or delete objects in
  any bucket. Jobs are now authorized at submission (`s3:ListBucket` on the
  configured prefixes) and per object at execution (`GetObject`, `PutObject`,
  `DeleteObject`, with version-aware variants). A non-admin submitter whose job
  previously succeeded because batch bypassed its S3 permissions now receives
  `AccessDenied` (HTTP 403) for any operation it lacks permission for. Grant the
  submitter the matching S3 permissions before upgrading. Persisted job records
  remain forward- and backward-compatible across a rolling upgrade, and jobs
  written before this change fall back to live policy evaluation rather than
  deny-all (#5783, #5807).

- **The `scanner-excess-folders` and `scanner-excess-versions` alerts have been
  removed.** Neither was actionable through a single operator control, so
  detection belongs in diagnostics rather than the alert stream. Scanner
  detection itself is unchanged — the Prometheus counters, the `ScannerMetrics`
  report fields and the `PrefixManyFolders` event all remain. Alert rules,
  dashboards or automation keyed on these two alert names must be updated
  (#6055).

- **Object tag names no longer collapse into policy condition keys.** Tag
  condition keys were built with a path join that cleaned the path, so a tag
  named `../CurrentTime` collapsed onto the server-owned `aws:CurrentTime` key.
  Tag names are now concatenated as plain text and always stay under
  `ExistingObjectTag/` or `RequestObjectTag/`. A policy written to match a
  previously collapsed tag name will stop matching — that collapse was the
  defect, but the difference is visible to anyone who wrote such a policy
  (#6613, fixes #5827).

---

## Security Updates

Upgrading is recommended for all deployments. The IAM policy-merge, session
token and RDMA write-path fixes below allow privilege escalation.

### Authorization

- Closed five authorization holes in IAM policy merge and its cache: policy
  merge failed open, so a transient storage error on the policy carrying a
  `Deny` let the request through; the merged-policy cache key omitted the policy
  source; the `PolicyDBGet` singleflight omitted groups, so a concurrent caller
  could be answered with another caller's group policies; `CreateSession`
  ignored the caller's own policy, letting a session bypass an explicit `Deny`;
  and the periodic IAM reload did not invalidate the derived cache. A storage
  blip in the policy prefix now produces `AccessDenied` instead of silently
  widening access (#6776, fixes #6773).

- Enforced the access-key binding on temporary session tokens. `DeriveCredentials`
  loaded claims from the session token without checking that the token and the
  presented access key belonged together, so any legitimately issued STS key
  could be paired with an unrelated leaked token to impersonate that token's
  owner — up to root. Because presigned URLs carry the session token in the
  query string by design, a leak through logs, referrers or shared links was
  enough to sign arbitrary requests as the victim. The signed `accessKey` claim
  recorded at issuance is now verified (#6719, fixes #6666).

- Authenticated the GPU-Direct RDMA write path before performing any write. The
  RDMA branches of `PutObject` and `PutObjectPart` completed the write and
  returned before reaching signature verification, so a caller who knew only a
  victim's non-secret access key ID could write objects as that principal —
  including root — over an RDMA fabric (#6724).

- Rejected renames of objects under retention or legal hold.
  `RenameObjectHandler` never checked object-lock state, so an ordinary
  read/write user could destroy a COMPLIANCE-retained or legal-held object
  version, or relocate it out of its retained path, with nothing more than
  `PutObject`/`DeleteObject` permission (#6710).

- Closed the Cortex reserved namespace in both directions: `s3:PutObject` can no
  longer forge a Memory API resource and `s3:GetObject` can no longer read one,
  including via `CopyObject` and `UploadPartCopy` as a source. `s3:ListBucket` is
  filtered so secret and agent names cannot be enumerated (#6641).

- Enforced the system-warehouse source-bucket guard on server-side scan planning
  (#6435, fixes #6414).

### Information Disclosure

- Restored header-only tracing on the `inspect-data`, `metrics`, `profile` and
  `profiling-download` admin routes, which recorded full HTTP response bodies
  for `mc admin trace` subscribers. An admin holding only `admin:ServerTrace`
  could lift the AES-256-GCM key from a legacy inspect response published to the
  trace stream and decrypt raw drive data that `admin:InspectData` is meant to
  protect (#6658).

- Scoped the unsealed object-encryption-key cache to the SSE-C key it was derived
  from. The per-request cache ignored the presented SSE-C key on a hit, so once
  warm, a caller presenting the _wrong_ SSE-C key was served the key material a
  previous caller derived from the correct one. Failed unseals were also cached,
  turning a subsequent legitimate decrypt into a spurious `AccessDenied`
  (#6598).

- Kept unverified OIDC claims out of the STS audit record. An id_token that
  failed signature verification still deposited its attacker-chosen claims into
  the deferred audit record, so anyone able to reach the STS endpoint could write
  arbitrary keys and values into the audit stream attributed to a denied
  request. No credentials were issued and no policy decision changed, but
  anything parsing the audit stream inherited the injected values (#6673, fixes #6657).

- Parsed untrusted Kubernetes STS tokens into a throwaway claims map.
  Detection parsed an unverified service-account token directly into the map used
  to mint the credential, letting token claims overwrite request-derived claims
  such as the session policy and revoke type (#6572, fixes #5830).

- Replaced the console's PDF object preview, which rendered attacker-controlled
  files in a bare same-origin `<iframe>` with full access to the console session,
  with canvas rendering through pdf.js. No iframe, no native viewer, and no
  PDF-embedded JavaScript execution by design (#6627).

### Denial of Service

- Bounded the checksum part-count allocation, which was sized directly from an
  unbounded part count decoded out of stored checksum bytes before any
  validation. An attacker-controlled value crashed the process with an
  unrecoverable OOM on every subsequent metadata read of the object — GET, HEAD,
  list, replication, scanner and heal. The `X-Minio-Replication-Ssec-Crc` header
  is now gated on `ReplicateObjectAction`, closing the path by which a caller
  holding only `s3:PutObject` could plant the poisoned bytes (#6715, fixes #6664).

- Bounded RDMA transfer work by the servable object size rather than the client
  token. The large-object GET fast path derived its part count, result slice and
  one-goroutine-per-chunk fan-out straight from the client-declared content
  length, so a single crafted GET drove a terabyte-scale allocation and tens of
  millions of goroutines. The path is compiled into every build and needs no RDMA
  hardware. Negative token fields are now rejected, and the RDMA PUT path no
  longer skips the shared Tables write-authorization check (#6669).

- Bounded the `_last_checkpoint` parts count to prevent an OOM crash (#6415,
  #6440).

- Limited the console login request body to 1 MiB. `LoginHandler` and
  `LDAPLoginHandler` decoded unauthenticated request bodies with no size limit,
  so a multi-GB JSON body forced unbounded heap allocation (#4983).

- Fixed a client-reachable panic in `etag.Parse`: the single-byte input `"`
  satisfied both the prefix and suffix quote checks with no length guard, so
  `CompleteMultipartUpload` on a client-supplied part ETag of `"` returned 500
  with a stack dump per request instead of 400 `InvalidPart`. Also bounded the
  multipart part number outside strict mode, fixed RDMA ranged reads truncating
  by the starting offset, fixed a netperf receive buffer freed mid-benchmark, and
  fixed `WaitForWriteComplete` unregistering another waiter on cancel (#6621).

### Dependencies

- Moved the Go directive to 1.26.6 across all modules, clearing four stdlib
  advisories: GO-2026-6089, GO-2026-6090, GO-2026-6091 and GO-2026-6218
  (`7aa9e8338`).
- Upgraded `golang.org/x/mod` to v0.40.0, pulling crypto, net, text, tools and
  telemetry forward with upstream security and bug fixes (#6836).
- Bumped gRPC, compress and stdlib dependencies to clear the live govulncheck
  database (#6539).
- Replaced `react-router-dom`, frozen at 7.x with an unpatched high-severity
  CSRF-bypass advisory (GHSA-qwww-vcr4-c8h2), with `react-router`, which exports
  the identical API. Moved the `shadcn` dev-only CLI out of production
  dependencies and bumped the `dompurify` override (#6620, fixes #6619).

---

## New Features

### AIStor Tables

- **Iceberg SQL function (UDF) catalog metadata.** Adds read-side catalog support
  for Iceberg SQL functions, including scalar UDF and table-function metadata,
  through the standardized REST endpoints for listing functions in a namespace
  and loading all definitions and overloads for a named function. Tables, views
  and functions may now share a name without colliding. Function endpoints are
  advertised only when every node in the cluster supports the required internode
  types, and the replica catalog scanner discovers and reconciles function
  metadata including creation, updates, renames, namespace moves and orphan
  cleanup. Create, replace, drop and execution APIs are deliberately not exposed,
  since Iceberg has not standardized those REST operations (#6224, fixes #6273).

- **On-demand snapshot expiry and per-table maintenance exclusion.** Snapshot
  expiration can now be triggered externally for a named table, and tables can be
  excluded from selected maintenance operations by pattern. Together these let a
  Spark structured-streaming reader disable automatic snapshot expiration for the
  tables it is reading and expire snapshots once the read has finished, removing
  the race between expiry and a reader that has not advanced far enough (#6455, #6488, fixes #6278).

- **Automatic primary/replica selection on `mc admin replicate add`.** Site
  replication now sets the Tables roles when replication is added, so the replica
  catalog scanner no longer has to be enabled by hand. The site the command runs
  against stays the writable primary and its peer becomes the read-only replica.
  Roles are left untouched when the topology is not exactly two sites, when
  either site is already a replica, or when the peer holds user warehouses of its
  own. Three rules protect the topology against ending up with two writable sites
  that diverge (#6617).

- **Table-level encryption override removal.** `DELETE
/{warehouse}/namespaces/{namespace}/tables/{table}/encryption` removes a
  table's own encryption override so it returns to inheriting the warehouse
  default. Previously an override, once set, could never be removed. The call is
  idempotent, is authorized with the new `s3tables:DeleteTableEncryption` policy
  action, and the console table detail page gains a **Remove Override** action
  (#6693, fixes #6684).

- Table metadata now honors the configured compression property (#6494, fixes #3311).

### Cortex and the Memory API

- **`GetObjectBio`.** `GET /_mem/v1/cortexes/{cortex}/bio?key=` returns one
  object's whole version history in a single call — the server-attested `mem-*`
  stamps, session id, tags and agent metadata per version, plus whether each is
  current or a delete marker. It replaces the `ListObjectVersions` walk plus
  per-version lookup agents use today: that walk hits every drive of every
  erasure set however narrow the key, while bio hashes the key to its owning set
  and decodes one metadata record. Gated on `s3:GetObject` (#6771).

- **The agent record is now a first-class Memory API resource,** on a storage
  layer shared with secrets: names hash to a two-level fan-out of 65,536 leaf
  directories so no directory holds millions of entries, and listing is served by
  a log-structured index merged on read (#6641).

- **System inventory on Cortex buckets.** Cortex buckets were excluded from
  system inventory because every Cortex also carries the Tables warehouse
  capability. They now get an inventory table while plain warehouses and the
  system warehouse stay excluded, with the object and annotation walks skipping
  Cortex-reserved and warehouse-state prefixes so no internal or secret object
  names reach the queryable table (#6517).

### RDMA on InfiniBand

- **GPU-Direct S3 now initializes on native InfiniBand fabrics.** Server init was
  passed an IPv4 address, which `libs3rdma` resolves to a device through the GID
  table — a lookup that only works on RoCE, where IP addresses are encoded in
  GIDs. On InfiniBand it found nothing and the whole feature was unreachable. The
  address is now resolved to its RDMA device through sysfs and the device name
  passed instead, preserving the operator's choice of NIC. RoCE behavior is
  unchanged by construction, and the underlying library error is now surfaced
  instead of an address with no cause (#6828).

- **Internode RDMA now works on InfiniBand.** Internode RDMA moved zero bytes on
  IB: every write failed at address-handle creation because InfiniBand routes by
  LID inside a subnet and the buffer descriptor exchanged over the grid described
  each NIC by GID, rkey and DCTN only — the LID was never on the wire. RoCE is
  unaffected, since there the GRH carries the address (#6846).

### Cluster diagnostics

- **Memory bandwidth speedtest.** `POST /speedtest/mem`, surfaced by `mc support
perf` through madmin-go's `MemPerf()`, has each node run a saturating streaming
  copy over per-thread buffers larger than cache and report what its memory
  subsystem actually delivered, alongside the DIMM topology that figure should be
  judged against. Memory bandwidth is what caps large-object throughput on a
  many-core storage node and is the one resource no utilization counter shows —
  DMA from a drive or a NIC never touches a core, so CPU, disk and network can
  all read idle while DRAM is saturated. Theoretical bandwidth is derived from the
  configured clock rather than the rated one, so a downclocked node stays visible
  instead of reading as broken; nodes do not cooperate, so the test is meaningful
  on a single-node deployment (#6648).

- **Outlier-aware object speedtest.** Instead of reporting only a straight sum of
  every node's throughput, the server now analyzes the per-node distribution,
  flags nodes falling below the cluster's true capability, and reports the
  projected aggregate the cluster would deliver once those nodes are healthy
  alongside the raw observed number (#5764, fixes #5528).

### Cluster operations

- **Per-task named leader locks.** Background monitoring tasks shared one global
  leader lock, so every task ran on whichever single node held it. Each task now
  acquires its own named lock and elects a leader independently, with a
  load-proportional backoff so a node already holding several task locks backs off
  in proportion, plus a 0–60s startup jitter to stagger initial elections. New
  grid RPCs let any node resolve the current leader for a named task without a
  full `ServerInfo` fanout, and the full leaders map is exposed in `ServerInfo`
  (#5698).

- **Bounded parity-upgrade cost.** Parity upgrade is not a transient cost:
  healing restores the shards an object is missing but never returns it to the
  configured erasure coding, so an object written at 11+5 instead of 12+4 stays
  about 9% larger for its whole life, and one written with four drives down stays
  50% larger. A drive that stays offline therefore costs a share of everything
  written while it is gone, and nothing bounded that. Each erasure set now has a
  budget, `erasure.parity_upgrade_budget`, expressed as a percent of its
  capacity; the chance of upgrading falls as the budget is spent rather than
  stopping dead at a ceiling, spreading reduced redundancy across the outage
  instead of protecting objects on nothing more meaningful than arrival order. A
  set seen whole starts again with the full budget (#6834).

### Configuration

Continuing the config.yaml full-coverage work whose site, scanner and
storage/data phases shipped in the previous EDGE build:

- **Identity providers and the policy plugin** can now be declared in
  config.yaml and applied at boot — `openid`, `ldap`, `tls`, `plugin`,
  `kubernetes` and the built-in IAM store under `identity.*`, plus
  `policy.plugin`. This adds the first multi-target section, so
  `identity.provider.openid` accepts a list of named provider entries (#6498).
- **The STS subsystem** gains an `sts:` section covering `duration`, the three
  rate limits, `secure`, `strictExpiration`, `tokenRevoke` and
  `browserSessionDuration` (#6573).
- **Server-wide settings** `serverUrl`, `domain`, `ntpServer` and a `browser`
  section (`enable`, `redirectUrl`) are now wired to config.yaml (#6207, part of #6169).

### Console

- A shared `DataTable` component standardizes table rendering across the console
  (#6730), and a new `SheetLayout` component is now used by every sheet-bearing
  component (#6749, #6783).
- The System warehouse's tables and their statistics are now shown in the console
  (#6467, fixes #6452), and table replication statistics have been redesigned (#5989).
- The Table Properties tab adopts the design-system layout and table item
  redesign (#6686, #6709, fixes #6505).
- Bucket encryption gains an Edit action and support for deleting multiple keys
  at once (#6688, fixes #6677).
- The login page background is replaced with the website animation (#6805).

---

## Performance Improvements

- **Large RDMA transfers stay on the direct path, and the coordinating node now
  takes a share of chunk dispatch.** The direct/chunked crossover is now tunable
  through `MINIO_RDMA_DIRECT_MAX_SIZE` (default 64 MiB, unchanged): above it an
  object is split into 16 MiB chunks pulled by a fixed worker pool, but chunk
  count grows with object size while the pool does not, and each chunk costs a
  peer RPC plus a fresh erasure read on a node chosen by hashing the offset —
  which then has to pull the object across the network before it can answer.
  Separately, chunk dispatch hashed over the remote-only peer list, sending 100%
  of chunks off-box even though the coordinator holds shards of the object too;
  it now takes its share (#6859).

- **RDMA buffer registration is roughly 2x faster on multi-rail hosts.** Pinning
  registered a buffer on every rail while a transfer names only one, so a caller
  registering per operation paid an `ibv_reg_mr` per rail on every transfer.
  Rails now register when a token first names them. Measured on a two-rail mlx5
  host, register plus deregister of a 4 MiB buffer went from 241.5µs to 114.5µs;
  failover is unchanged, since a buffer reused across transfers still ends up
  registered everywhere (#6854).

- **Site-replication state reads are now single atomic loads.** The
  `SiteReplicationSys` state moves from an RWMutex to an atomic pointer holding
  immutable snapshots, deleting all ~75 read-lock sites. A lock audit had found
  15+ sites reading the state without the documented read lock, several of them
  fatal concurrent-map-access crashes (`startResync`, `EditPeerCluster`
  validation, `AddPeerClusters`) plus a recursive-RLock deadlock hazard in the
  heal path; immutable snapshots make every such site correct by construction.
  Also fixes the `errs` map race in `EditPeerCluster`'s peer fan-out (#6399).

- **Temporary write staging is now flat-cost regardless of write volume.**
  Temporary write data stages under a time-window directory and the delete trash
  moves out of `tmp` to a sibling, so the sweep can age a directory from its name
  with one readdir and reclaim it with a single rename. Previously
  `cleanupStaleUploads` only inspected the top level of `.minio.sys/tmp`, whose
  sixteen shard directories have their mtime moved by every new write — so they
  never aged out and a long-running server leaked abandoned writes indefinitely.
  Keeping the trash inside `tmp` had also made the startup wipe delete pending
  deletes as an unthrottled bulk removal on every restart (#6813).

- Updated `minio/mux` to v1.10.1 for router performance improvements (#6801), and
  the form middleware now parses the query once and reads the parsed result
  instead of re-parsing per access (#6774).

---

## Bug Fixes

### Erasure coding, healing and decommission

- Heal no longer orphans staged parts when the target drive goes faulty. Cleanup
  was registered only after all parts were staged, so a write failure part way
  through returned without deleting what it had already written — and the cleanup
  it did register was refused by the drive health gate precisely when the heal
  failed _because_ that drive had just been taken offline. A field case leaked an
  entire 14 TB drive. Reclamation moves from roughly 30 hours to roughly 5
  minutes (#6704, fixes #6683).
- Decommission now absorbs transient failures through retry discipline instead of
  turning a quorum blip into a terminal `Failed` status: a run is attempted up to
  three times, failure counters reset per attempt so a resumed run no longer
  inherits its predecessor's count, buckets are re-queued between attempts, and
  migrations cancelled at shutdown are no longer counted as failures. The
  authoritative leftover check is unchanged, so no genuine migration failure can
  become a false `Complete` (#6447).
- Metadata-only `CopyObject` is now routed to the pool holding the requested
  version. It resolved the pool holding the _latest_ version, so after a
  decommission or rebalance split a version stack across pools the call reached a
  pool without that version and returned `VersionNotFound`. On one 2-site
  replicated cluster this produced ~4,800 indefinite replication retries over 33
  versions, saturating the workers and delaying replication by more than 5 hours
  (#6625).
- `NumVersions` is now populated at write time, so the `ObjectManyVersions`
  check fires from API traffic as well as the scanner. It was zero-valued on
  every write and only ever computed on read, and the five API call sites also
  used `>` where the scanner used `>=` (#6652).

### Tiering

- Tier configuration now recovers on demand. It was loaded once at startup and
  otherwise refreshed only by a 15-minute background loop that runs in
  distributed mode alone, so a minor quorum blip during a full-cluster restart
  left the config unloaded — breaking reads of transitioned objects, ILM
  transitions and untier job submission, with no recovery at all on a single-node
  erasure deployment. Any consumer that needs the config now attempts a
  singleflight reload and returns `503 Service Unavailable` until it succeeds,
  dropping recovery latency from up to 15 minutes (or never) to the first request
  that needs the config (#6432). The remaining paths — `Empty()`, `TierType()`
  and `ListTiers()`, which previously reported "no tiers" from empty startup
  state and led callers to act on it — now recover on demand under a shorter
  best-effort bound (#6527, fixes #6511). A failed startup load is also retried with
  backoff on every deployment type, not just distributed ones (#6653, fixes #6638).
- Batch untier is re-routed when the source pool refuses the recall, instead of
  failing the job. The same-pool decision comes from a cached point-in-time
  space estimate, so a refusal for lack of space or write quorum on the
  framework's final attempt now re-routes once to the pool currently reporting
  the most available space (#6546).
- Legacy pre-2025 batch job report IDs now age out during cleanup (#6628, SUBNET #17575).

### AIStor Tables and Delta Sharing

- Fixed three server-side scan-planning interoperability issues found during
  Spark testing: an explicit `{"type":"true"}` residual is now always returned
  when no row filter remains, which stops Spark/Iceberg 1.11 crashing when
  reading files written under different partition specs; selected columns are
  validated against the schema actually requested, so a column missing from an
  older snapshot schema returns `400 Bad Request` instead of an invalid completed
  plan; and the REST-standard constant expressions are now accepted (#6485, fixes #6269).
- A lost compaction commit race is no longer recorded as a completed run. The
  failure path advanced `LastRunAt` and marked the table as having run, so a
  table under concurrent writes waited a full compaction interval — 24 hours by
  default — with no operator recourse, since a trigger only wakes the loop and
  does not bypass the due check (#6777).
- Delta Sharing now fails a request when an Iceberg manifest cannot be read,
  instead of swallowing the error and returning an empty or partial file set as
  HTTP 200 — which clients treat as the complete table, silently dropping rows
  (#6323).
- Fixed a race where two tables dropped at the same time could leave one still
  referenced by a Delta Sharing share. The cascade now treats `index.json` as
  authoritative and re-checks missing or unreadable shares while holding their
  mutation lock (#6822, fixes #6668).
- Fixed a code path returning HTTP 500 when maintenance features were disabled,
  and added the missing table-maintenance documentation (#6703).

### Cortex

- A failed Tables enablement no longer force-deletes a pre-existing bucket. When
  upgrading an existing bucket into a Cortex, the previous rollback path
  force-deleted the bucket including any data that existed before the upgrade.
  Rollback is now ownership-aware: a newly created bucket is still removed, a
  pre-existing one never is, and upgrade/encryption/KMS provenance is preserved
  across retries. Missing or corrupt provenance now returns `409
CortexProvenanceUnavailable` without changing registry state rather than
  guessing from the retry request (#6700, fixes #6675).

### Encryption and KMS

- Batch keyrotate no longer breaks internal-subsystem decryption. A job's
  `encryption.context` was merged into the AAD used to re-encrypt IAM, server
  config, tier config and bucket metadata — none of which can persist or
  reproduce a caller-supplied context — so any non-empty context permanently
  bricked decryption on the next read while the job itself reported success.
  Internal-subsystem rotation no longer accepts a KMS context at all (#6711, fixes #6690).
- Batch keyrotate now preserves the encoded checksum when encrypting a plaintext
  multipart object, which previously failed for any full-object-checksum object
  such as the default CRC64NVME (#6590).
- A bucket SSE-KMS rule naming no key now uses the KMS default key, matching AWS
  S3, instead of being rejected. The default key is resolved when the
  configuration is set purely to verify it is usable, so a missing or unreachable
  key fails `PutBucketEncryption` rather than every subsequent `PutObject`
  (#6794, fixes #6793).
- A free-tier license no longer auto-encrypts object writes. Since the free-tier
  encryption gates began running after the server injects its own SSE header, and
  auto-encryption defaults to on whenever KMS is configured, a free-tier server
  with `MINIO_KMS_SECRET_KEY` rejected _every_ plain object write with 405
  `XMinioPaidTierLicenseRequired` — including writes carrying no encryption
  headers at all (#6509).
- Users holding `kms:*` can now call the rotate, status and enable endpoints
  (#6553).

### Replication, events and notifications

- `GlobalQueue.SendWithFilter` now reports a torn-down target as failed rather
  than silently skipping it in the same branch used for targets intentionally
  excluded by the filter. A fully-skipped send returned an empty failure list,
  indistinguishable from full delivery: the alerts dispatcher marked a dropped
  alert as delivered and suppressed it for the 24-hour dedup window, disk replay
  and migration loops deleted the source entry instead of retrying, and the
  bucket-notification `failedEvents` metric under-counted (#6764, fixes #6723).
- A refused conditional request is now answered exactly once. Precondition checks
  ran inside the object layer and wrote the 412 themselves, then returned for the
  handler to write a second response; the extra body overshoots the declared
  `Content-Length`, so the connection is dropped — which a replication worker
  reads as the whole remote target being down (#6765, fixes minio/minio#21633).
- Grid error handling now distinguishes an unreachable peer from an error the
  peer actually reported. `ErrDisconnected` was itself a remote error even though
  a disconnect is local transport information, and pointer-shaped remote errors
  did not work with `errors.Is` because the comparison used pointer addresses. A
  fanout group representative now returns an explicit result for every offline
  group member instead of silently omitting it, and the new wire field is
  backward-compatible in both directions (#6838).

### Metrics and statistics

- The S3-over-RDMA counters are now fed instead of reporting zero.
  `minio_api_rdma_read_bytes_total`, `read_ops_total`, `write_bytes_total` and
  `write_ops_total` were declared and read into their metrics but incremented
  nowhere, so they answered "no" for a healthy cluster carrying RDMA traffic —
  worse than having no metric, since a reading of 0 looks like a definitive
  negative. Only successful transfers are counted, so a transfer that falls back
  to TCP does not inflate the totals (#6567).
- Whole-window reads in the windowed statistics package now anchor at the active
  segment, fixing reads that returned nothing when the caller's timestamp fell
  behind it — the root cause of lost replication retry counts (#6563).
  `GetTotalWithActive` now also counts each segment exactly once when a stats
  restore runs during a read, and the push callback no longer includes a late
  past-slot entry (#6616).
- The drive-top `SetIndex` filter is now scoped to the set rather than the pool,
  which made single-pool clusters report every set drive offline (#6379).

### Logging

- Suppression IDs are now scoped to the entity that failed. Sites paired a fixed
  suppression ID with a message carrying per-object or per-set data, so only the
  first few events were ever logged — nonce corruption is now keyed per upload,
  manually-modified-disk errors per pool/set, and transitioned self-heal per
  bucket. A related defect discarded the dedup keys and context passed through
  `errKind` at 28 call sites, including a line emitted on every peer RPC
  (#6655, #6659, #6694, #6695, #6745).
- An offline peer no longer logs an error on every Tables refresh interval.
  Pointer-shaped grid disconnect errors were missed by the existing checks, and
  recurring Tables compaction and stats failures are now rate-limited on stable
  peer, warehouse and table keys (#6795, fixes #6691).
- The health check no longer floods Crit-level logs: it runs on every liveness
  probe and metrics scrape, so a set below quorum logged unsuppressed on each
  call (#6781). The alerts `Health()` probe no longer emits spurious quorum logs
  (#6733), and KMS decryption failures no longer flood the checksum log path when
  the KMS is unreachable or requests are cancelled (#6731).

### Configuration and administration

- `SetConfigKV` no longer silently drops a config change. Its no-op shortcut
  compared the submitted change against an unlocked backend read of `config.json`
  alone, so when that read was stale and happened to match the submitted value,
  the handler returned success without saving, applying or notifying peers —
  leaving the node's in-memory config permanently stale until the next change to
  that subsystem or a restart. The applied in-memory config must now agree as
  well (#6525).
- The documentation URLs a running server and a package install print to
  operators now point at the current docs base path; all seven distinct
  destinations were verified against the live site (#6772).
- Corrected the heal-worker default in the config help text (4, not
  GOMAXPROCS/2) (#6755).

### Packaging

- The published RDMA deb/rpm/apk packages could not start: the binary hard-links
  `libs3rdma.so.0` and the package shipped `libcuobjserver` instead, which the
  binary no longer links. Package contents now match the shipped binary's
  `DT_NEEDED` closure exactly, and the post-install ldconfig hook is regated
  accordingly. The container image escaped this only because it copies the whole
  architecture library directory (#6558).
- The RDMA buffer address and size are now derived from the cuObject descriptor,
  which already carries both as its own leading fields, so a client sends exactly
  the descriptor (#6759).

### Console

- Single-object downloads now stream to disk through the File System Access API
  instead of fully buffering the object into a browser blob, which risked an OOM
  on a multi-GB object; the multi-object zip path already streamed correctly
  (#6682, fixes #6681).
- Share links now work on proxied and port-mapped deployments. They resolved to
  the console SPA instead of downloading the object, because the previous handler
  tried to synthesize a reachable S3 host from the console request and had no
  signal to work with when console and S3 share a public port. The console now
  presigns against its internal endpoint and returns a wrapper link on the same
  host the browser used, host-validated to prevent open-proxy use, and works in
  every ingress topology without `MINIO_SERVER_URL` or `X-Forwarded-*` (#6406, fixes #6402).
- Resource-scoped `Deny` gating now extends to bulk delete and select-all
  (#6565), and object-browser row actions are gated per object (#6503, fixes #6418).
- Edit properties and Maintenance fields are disabled for read-only users
  (#6756).
- Encryption UI is now KMS-aware for Tables warehouses and tables (#6706).
- Dashboard charts distinguish loading from empty state (#6631), chart card
  descriptions move to tooltips (#6654), bucket monitoring chart x-axis labels are
  computed from the data segments (#6387), and only one object-size distribution
  popover stays open at a time (#6538, fixes #6534).
- Fixed page header visibility, empty-state clutter and component inconsistencies
  (#6604), dialog widths across confirmations and detail views (#6529), the
  diagnostics page layout and results table (#6633), the bucket compression sheet
  Cancel button and size validation (#6676), the QoS Add Rule sheet's required
  indicator, validation styling and combobox consistency (#6697), save-button text
  consistency across the Tables UI (#6599, fixes #6592), search and filter controls
  showing on empty pages (#6547), and dead command-palette bucket actions (#6591).

---

## Improvements

- Console components migrate from raw `<button>` elements to shadcn primitives
  (#6433, #6492) and drop custom class-name overrides from Sheet components so
  the base styles apply consistently (#6491), alongside design-system token and
  layout fixes (#6528) and a cleanup of inconsistent UI patterns (#6510).
- Console TypeScript `any`/`unknown` escape hatches are typed and the refetch
  interval is centralized (#6557).
- The KMS v2 metric deprecation notes are corrected. Both pointed operators at
  per-endpoint tracking, but the v3 KMS family is deliberately aggregate — the
  metrics carry no endpoint label because the KES SDK round-robins without
  exposing which endpoint served a request. `minio_cluster_kms_online` also named
  the wrong replacement: it reports online/offline, so its v3 counterpart is
  `minio_kms_online`, not the duration metric `minio_kms_online_seconds` (#6716, fixes #6678).

---

## Security & Compliance

### Software Bill of Materials (SBOM)

This release includes comprehensive SBOM documentation in multiple formats:

- [SPDX JSON](https://dl.min.io/aistor/minio/edge/notes/sbom-EDGE.2026-08-18T04-46-14Z.spdx.json) - Standard SBOM format
- [CycloneDX JSON](https://dl.min.io/aistor/minio/edge/notes/sbom-EDGE.2026-08-18T04-46-14Z.cyclonedx.json) - Security scanner compatible
- [Go Modules](https://dl.min.io/aistor/minio/edge/notes/go-modules-EDGE.2026-08-18T04-46-14Z.txt) - Human-readable dependency list

SBOM files document all direct and transitive dependencies for security auditing and compliance requirements.

---

## Upgrade Instructions

For detailed upgrade instructions, please read: https://docs.min.io/aistor/upgrade-aistor-server/

Platform-specific upgrade guides:

- **Linux/Bare Metal**: https://docs.min.io/aistor/upgrade-aistor-server/upgrade-aistor-linux/
- **Kubernetes with Helm**: https://docs.min.io/aistor/upgrade-aistor-server/upgrade-aistor-kubernetes-helm/

### New Configuration Options

| Setting                                         | Purpose                                                                                                                                                                                                               |
| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `erasure.parity_upgrade_budget`                 | Percent of an erasure set's capacity that parity upgrade may permanently consume. The upgrade probability falls as the budget is spent; a set seen whole starts again with the full budget (#6834).                   |
| `MINIO_RDMA_DIRECT_MAX_SIZE`                    | Size at which an RDMA transfer switches from a single direct write to 16 MiB chunked transfer. Default 64 MiB, unchanged from previous behavior (#6859).                                                              |
| `sts.*`                                         | New config.yaml section: `duration`, the three rate limits, `secure`, `strictExpiration`, `tokenRevoke`, `browserSessionDuration` (#6573).                                                                            |
| `sts.browserSessionDuration`                    | Console browser session duration, now a first-class STS setting independent of `sts.duration`. Default 12h. The deprecated `MINIO_BROWSER_SESSION_DURATION` still applies when the derived variable is unset (#6573). |
| `identity.*`, `policy.plugin`                   | config.yaml coverage for `openid` (a list of named providers), `ldap`, `tls`, `plugin`, `kubernetes`, the built-in IAM store, and the policy plugin (#6498).                                                          |
| `serverUrl`, `domain`, `ntpServer`, `browser.*` | config.yaml coverage for the server endpoint, domain names, object-lock NTP server, and browser enable/redirect settings (#6207).                                                                                     |

Two STS fixes are worth noting alongside the new section: `MINIO_STS_DURATION`
previously had no effect because the 1h default was assigned outside the range
check, so STS credential validity had been pinned to 1h since February 2025; and
an unparseable `secure`/`strictExpiration` value used to fail open, with `secure`
falling back to "TLS not required". Both now fail closed (#6573).

### Migration Notes

- **Batch job permissions.** Before upgrading, grant every non-admin batch job
  submitter the S3 permissions its jobs need — `s3:ListBucket` on the configured
  prefixes for submission, and per-object `GetObject`/`PutObject`/`DeleteObject`
  at execution. See Breaking Changes (#5807).

- **Alert rules on scanner excess-folders/versions.** Update any alert routing,
  dashboards or automation keyed on the `scanner-excess-folders` or
  `scanner-excess-versions` alert names; the underlying Prometheus counters and
  the `PrefixManyFolders` event are unchanged (#6055).

- **Bucket SSE-KMS rules without an explicit key.** A rule stored without a
  `KMSMasterKeyID` is rejected by servers predating this change, and such a
  server fails the entire bucket metadata load for that bucket — policy, object
  lock, lifecycle and versioning all read as unset. Take care during a downgrade
  or a mixed-version rolling upgrade (#6794).

- **Temporary write staging layout.** Temporary write data now stages under
  `.minio.sys/tmp/<window>/` and the delete trash moves to `.minio.sys/.trash`.
  No operator action is required; the change is noted because it alters the
  on-disk layout under `.minio.sys` (#6813).

- **Internode grid disconnect identity.** Disconnects keep their local identity
  through direct grid calls, mux teardown and fanout once all nodes are upgraded.
  The new wire field is optional in both directions, so a mixed-version cluster
  falls back to the previous behavior rather than failing (#6838).

### Support

For enterprise support:

- SUBNET Support: https://subnet.min.io
- Documentation: https://docs.min.io
