Vulnerability: An issue was discovered in litemall 0.9.0. Arbitrary file download is possible via ../ directory traversal in linlinjava/litemall/wx/web/WxStorageController.java in the litemall-wx-api component.
Vulnerability ID: CVE-2018-18434
CWE: CWE-22
Severity score: 2.9
Project: https://github.com/linlinjava/litemall
Published: 2018-10-17
File: litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxStorageController.java
Commit message: fix[litemall-wx-api]: 修复文件路径中包含"../"带来的安全问题
Commit author: Junling Bu

Vulnerable version (before fix):
 public Object upload(@RequestParam("file") MultipartFile file) throws IOExceptio     public ResponseEntity<Resource> fetch(@PathVariable String key) {         LitemallStorage litemallStorage = litemallStorageService.findByKey(key);         if (key == null) {             ResponseEntity.notFound();         }         String type = litemallStorage.getType();         MediaType mediaType = MediaType.parseMediaType(type);          Resource file = storageService.loadAsResource(key);         if (file == null) {             ResponseEntity.notFound();         }         return ResponseEntity.ok().contentType(mediaType).body(file);     } public ResponseEntity<Resource> fetch(@PathVariable String key) {     public ResponseEntity<Resource> download(@PathVariable String key) {         LitemallStorage litemallStorage = litemallStorageService.findByKey(key);         if (key == null) {             ResponseEntity.notFound();         }         String type = litemallStorage.getType();         MediaType mediaType = MediaType.parseMediaType(type);          Resource file = storageService.loadAsResource(key);         if (file == null) {             ResponseEntity.notFound();         }         return ResponseEntity.ok().contentType(mediaType).header(HttpHeaders.CONTENT_DISPOSITION,                 "attachment; filename=\"" + file.getFilename() + "\"").body(file);

Fixed version (after fix):
 public Object upload(@RequestParam("file") MultipartFile file) throws IOExceptio     public ResponseEntity<Resource> fetch(@PathVariable String key) {         LitemallStorage litemallStorage = litemallStorageService.findByKey(key);         if (key == null) {             return ResponseEntity.notFound().build();         }         if(key.contains("../")){             return ResponseEntity.badRequest().build();         }         String type = litemallStorage.getType();         MediaType mediaType = MediaType.parseMediaType(type);          Resource file = storageService.loadAsResource(key);         if (file == null) {             return ResponseEntity.notFound().build();         }         return ResponseEntity.ok().contentType(mediaType).body(file);     } public ResponseEntity<Resource> fetch(@PathVariable String key) {     public ResponseEntity<Resource> download(@PathVariable String key) {         LitemallStorage litemallStorage = litemallStorageService.findByKey(key);         if (key == null) {             return ResponseEntity.notFound().build();         }         if(key.contains("../")){             return ResponseEntity.badRequest().build();         }          String type = litemallStorage.getType();         MediaType mediaType = MediaType.parseMediaType(type);          Resource file = storageService.loadAsResource(key);         if (file == null) {             return ResponseEntity.notFound().build();         }         return ResponseEntity.ok().contentType(mediaType).header(HttpHeaders.CONTENT_DISPOSITION,                 "attachment; filename=\"" + file.getFilename() + "\"").body(file);

Patch:
patch: @@ -58,14 +58,17 @@ public Object upload(@RequestParam("file") MultipartFile file) throws IOExceptio
     public ResponseEntity<Resource> fetch(@PathVariable String key) {
         LitemallStorage litemallStorage = litemallStorageService.findByKey(key);
         if (key == null) {
-            ResponseEntity.notFound();
+            return ResponseEntity.notFound().build();
+        }
+        if(key.contains("../")){
+            return ResponseEntity.badRequest().build();
         }
         String type = litemallStorage.getType();
         MediaType mediaType = MediaType.parseMediaType(type);
 
         Resource file = storageService.loadAsResource(key);
         if (file == null) {
-            ResponseEntity.notFound();
+            return ResponseEntity.notFound().build();
         }
         return ResponseEntity.ok().contentType(mediaType).body(file);
     }
@@ -74,14 +77,18 @@ public ResponseEntity<Resource> fetch(@PathVariable String key) {
     public ResponseEntity<Resource> download(@PathVariable String key) {
         LitemallStorage litemallStorage = litemallStorageService.findByKey(key);
         if (key == null) {
-            ResponseEntity.notFound();
+            return ResponseEntity.notFound().build();
+        }
+        if(key.contains("../")){
+            return ResponseEntity.badRequest().build();
         }
+
         String type = litemallStorage.getType();
         MediaType mediaType = MediaType.parseMediaType(type);
 
         Resource file = storageService.loadAsResource(key);
         if (file == null) {
-            ResponseEntity.notFound();
+            return ResponseEntity.notFound().build();
         }
         return ResponseEntity.ok().contentType(mediaType).header(HttpHeaders.CONTENT_DISPOSITION,
                 "attachment; filename=\"" + file.getFilename() + "\"").body(file);
path: litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxStorageController.java