VYPR
Medium severityOSV Advisory· Published Apr 22, 2025· Updated Apr 15, 2026

CVE-2025-32963

CVE-2025-32963

Description

MinIO Operator STS is a native IAM Authentication for Kubernetes. Prior to version 7.1.0, if no audiences are provided for the spec.audiences field, the default will be of the Kubernetes apiserver. Without scoping, it can be replayed to other internal systems, which may unintentionally trust it. This issue has been patched in version 7.1.0.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

MinIO Operator STS uses Kubernetes apiserver audience by default when spec.audiences is empty, enabling token replay attacks to other systems; fixed in version 7.1.0.

Vulnerability

Description

MinIO Operator STS provides native IAM authentication for Kubernetes, allowing applications to obtain temporary credentials via the AssumeRoleWithWebIdentity API. In step 2 of the token validation, the Operator calls the Kubernetes TokenReview API to verify the service account token. The TokenReviewSpec includes an audiences field; if spec.audiences is not provided, the default audience is set to the Kubernetes apiserver audience. This misconfiguration leads to tokens that are not scoped to MinIO’s STS service, making them reusable against other internal systems that may unintentionally trust the apiserver audience. [3]

Exploitation and

Attack Surface

An attacker who obtains a service account token from a pod or application that uses the STS endpoint could replay that token to other internal services that accept the Kubernetes apiserver audience. The prerequisite is that the MinIO Operator is used with STS functionality enabled (default since Operator v6.x) and the spec.audiences field is left empty. No additional authentication is required beyond possessing a valid service account token issued for the MinIO STS flow. [2][3]

Impact

Successful exploitation allows an attacker to leverage a token intended for MinIO Tenant access to impersonate the same service account to other internal services. This could lead to privilege escalation or lateral movement within the Kubernetes cluster, depending on which other services trust the apiserver audience. The impact is limited to environments where the MinIO Operator’s STS endpoint is used without explicit audience scoping. [3]

Mitigation

The issue has been patched in MinIO Operator version 7.1.0. The fix ensures that the TokenReview audience is set to sts.min.io, scoping the token’s validity to the Operator’s STS service. Operators should upgrade to v7.1.0 or later. If immediate upgrade is not possible, administrators can manually set spec.audiences to an appropriate value in the PolicyBinding resource. [2][3]

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/minio/operatorGo
< 7.1.07.1.0

Affected products

4

Patches

2
d586294d526b

Security fix: Use audience `sts.min.io` to invoke TokenReview. (#2418)

https://github.com/minio/operatorPedro JuarezApr 14, 2025via ghsa
6 files changed · +63 20
  • examples/kustomization/sts-example/README.md+7 15 modified
    @@ -2,15 +2,10 @@
     
     Each example in this folder contains an example using a different SDK on how to adopt Operator's STS.
     
    -> ⚠️ This feature is an Beta release now starting Operator v6.x, Operator v5.x released STS as v1alpha1.
    +> ⚠️ This feature is on v1beta1 starting Operator v6.x, Operator v5.x released STS as v1alpha1.
     
     # Requirements
     
    -## Enabling STS functionality
    -
    -At the moment, the STS feature ships off by default, to turn it on switch `OPERATOR_STS_ENABLED` to `on` on
    -the `minio-operator` deployment.
    -
     ## TLS
     
     The STS functionality works only with TLS configured. We can request certificates automatically, but additional you can
    @@ -21,14 +16,6 @@ use `cert-manager` or bring your own certificates.
     To install the example, you need an existing tenant, optionally, you can install the `tenant-lite` example, or
     the `tenant-certmanager` example
     
    -# 0. Enable STS Functionality
    -
    -If you haven't done so, enable the STS feature on operator by turning setting the feature flag `OPERATOR_STS_ENABLED=on`
    -
    -```shell
    -kubectl -n minio-operator set env deployment/minio-operator OPERATOR_STS_ENABLED=on
    -```
    -
     # 1. Install Tenant (Optional)
     
     ```shell
    @@ -114,4 +101,9 @@ kubectl apply -k examples/kustomization/sts-example/sample-clients/minio-sdk/jav
     
     ```shell
     kubectl apply -k examples/kustomization/sts-example/sample-clients/minio-sdk/dotnet
    -```
    \ No newline at end of file
    +```
    +
    +## Disabling STS functionality
    +
    +MinIO Operator is shipped with STS feature on by default, if you want to disable this feature set `OPERATOR_STS_ENABLED` to `off` on
    +the `minio-operator` deployment.
    
  • examples/kustomization/sts-example/sample-data/mc-job-sa.yaml+2 1 modified
    @@ -2,4 +2,5 @@ apiVersion: v1
     kind: ServiceAccount
     metadata:
       namespace: minio-tenant-1
    -  name: mc-job-sa
    \ No newline at end of file
    +  name: mc-job-sa
    +automountServiceAccountToken: false
    \ No newline at end of file
    
  • examples/kustomization/sts-example/sample-data/mc-job-setup-bucket.yaml+21 1 modified
    @@ -42,17 +42,37 @@ spec:
               configMap:
                 name: start-config-script
                 defaultMode: 0744
    +        - name: sa-token
    +          projected:
    +            sources:
    +              - serviceAccountToken:
    +                  audience: "sts.min.io"
    +                  expirationSeconds: 3600
    +                  path: token
    +        - name: root-ca
    +          configMap:
    +            name: kube-root-ca.crt
    +            items:
    +              - key: ca.crt
    +                path: ca.crt
    +            defaultMode: 0644
           containers:
             - name: mc
               image: minio/mc
               command: [ "/start-config/setup.sh" ]
               volumeMounts:
                 - name: start-config
                   mountPath: /start-config/
    +            - name: sa-token
    +              mountPath: /var/run/secrets/sts.min.io/serviceaccount
    +              readOnly: true
    +            - name: root-ca
    +              mountPath: /root/.mc/certs/CAs/
    +              subPath: ca.crt
               env:
                 - name: MC_HOST_myminio
                   value: https://$(ACCESS_KEY):$(SECRET_KEY)@minio.minio-tenant-1.svc.cluster.local
                 - name: MC_STS_ENDPOINT_myminio
                   value: https://sts.minio-operator.svc.cluster.local:4223/sts/minio-tenant-1
                 - name: MC_WEB_IDENTITY_TOKEN_FILE_myminio
    -              value: /var/run/secrets/kubernetes.io/serviceaccount/token
    +              value: /var/run/secrets/sts.min.io/serviceaccount/token
    
  • examples/kustomization/sts-example/sts-app/sts-client.yaml+13 2 modified
    @@ -8,6 +8,7 @@ kind: ServiceAccount
     metadata:
       namespace: sts-client
       name: stsclient-sa
    +automountServiceAccountToken: false
     ---
     apiVersion: v1
     kind: Secret
    @@ -53,7 +54,7 @@ spec:
           serviceAccount: stsclient-sa
           containers:
             - name: sts-client
    -          image: miniodev/operator-sts-example:minio-go
    +          image: miniodev/operator-sts-example:minio-sdk-go
               imagePullPolicy: IfNotPresent
               env:
                 - name: MINIO_ENDPOINT
    @@ -65,7 +66,7 @@ spec:
                 - name: BUCKET
                   value: test-bucket
                 - name: AWS_WEB_IDENTITY_TOKEN_FILE
    -              value: /var/run/secrets/kubernetes.io/serviceaccount/token
    +              value: /var/run/secrets/sts.min.io/serviceaccount/token
                 - name: STS_POLICY
                   value: /tmp/policy.json
                 - name: STS_CA_PATH # When Certmanager is used will load the ca in this file
    @@ -78,6 +79,9 @@ spec:
                   subPath: policy.json
                 - name: tenant-certmanager-tls
                   mountPath: /var/run/secrets/sts.min.io/
    +            - name: sa-token
    +              mountPath: /var/run/secrets/sts.min.io/serviceaccount
    +              readOnly: true
           volumes:
             - name: sts-policy
               configMap:
    @@ -92,3 +96,10 @@ spec:
                       items:
                         - key: ca.crt
                           path: ca.crt
    +        - name: sa-token
    +          projected:
    +            sources:
    +              - serviceAccountToken:
    +                  audience: "sts.min.io"
    +                  expirationSeconds: 3600
    +                  path: token
    
  • pkg/controller/sts.go+7 1 modified
    @@ -39,6 +39,11 @@ const (
     	STSEndpoint        = "/sts"
     )
     
    +const (
    +	// TokenReviewAudience is the audience for the token review request
    +	TokenReviewAudience = "sts.min.io"
    +)
    +
     const (
     	// STSEnabled Env variable name to turn on and off the STS Service is enabled, disabled by default
     	STSEnabled = "OPERATOR_STS_ENABLED"
    @@ -380,7 +385,8 @@ func getTenantClient(ctx context.Context, c *Controller, tenant *miniov2.Tenant)
     func (c *Controller) ValidateServiceAccountJWT(ctx *context.Context, token string) (*authv1.TokenReview, error) {
     	tr := authv1.TokenReview{
     		Spec: authv1.TokenReviewSpec{
    -			Token: token,
    +			Token:     token,
    +			Audiences: []string{TokenReviewAudience},
     		},
     	}
     
    
  • pkg/controller/sts_handlers.go+13 0 modified
    @@ -116,10 +116,23 @@ func (c *Controller) AssumeRoleWithWebIdentityHandler(w http.ResponseWriter, r *
     		return
     	}
     
    +	isSSTSAudience := false
    +	for _, audience := range saAuthResult.Status.Audiences {
    +		if audience == TokenReviewAudience {
    +			isSSTSAudience = true
    +		}
    +	}
    +
    +	if !isSSTSAudience {
    +		writeSTSErrorResponse(w, true, ErrSTSAccessDenied, fmt.Errorf("Access denied: Invalid Token, audience '%s' not found", TokenReviewAudience))
    +		return
    +	}
    +
     	if !saAuthResult.Status.Authenticated {
     		writeSTSErrorResponse(w, true, ErrSTSAccessDenied, fmt.Errorf("Access denied: Invalid Token"))
     		return
     	}
    +
     	chunks := strings.Split(strings.Replace(saAuthResult.Status.User.Username, "system:serviceaccount:", "", -1), ":")
     
     	if len(chunks) < 2 {
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.