CVE-ID: CVE-2025-65542
Vulnerability Description
File Location: youlai-admin/admin-boot/src/main/java/com/youlai/admin/service/impl/SysDeptServiceImpl.java:181-187
Severity Level: High
Attack Vector: REST API Endpoint
Vulnerable Endpoint
@Operation(summary = "Delete Department")
@DeleteMapping("/{ids}")
@PreAuthorize("@ss.hasPerm('sys:dept:delete')")
public Result deleteDepartments(
@Parameter(description = "Department ID, multiple IDs separated by comma (,)")
@PathVariable("ids") String ids
) {
boolean result = deptService.deleteByIds(ids);
return Result.judge(result);
}
Vulnerable Code
@Override
public boolean deleteByIds(String ids) {
AtomicBoolean result = new AtomicBoolean(true);
List<String> idList = Arrays.asList(ids.split(","));
// Delete department and sub-departments
Optional.ofNullable(idList).orElse(new ArrayList<>()).forEach(id ->
result.set(this.remove(new LambdaQueryWrapper<SysDept>()
.eq(SysDept::getId, id)
.or()
.apply("concat (',',tree_path,',') like concat('%,',{0},',%')", id)))
);
return result.get();
}
Vulnerability Details
The vulnerability exists in the data flow from the REST API endpoint to the database query:
- Entry Point: The
ids parameter is received from the URL path variable through the @PathVariable annotation in the controller
- Propagation: This unsanitized input is passed directly to the
deleteByIds() service method
- Exploitation: The
LambdaQueryWrapper.apply() method performs raw string substitution rather than parameterized queries, allowing SQL injection
The path variable ids is directly concatenated into the SQL statement through the {0} placeholder without any escaping or validation.
Proof of Concept
An attacker with the sys:dept:delete permission can craft a malicious request:
DELETE /api/v1/depts/1)%20OR%201=1-- HTTP/1.1
Host: target.com
Authorization: Bearer <valid_token>
This causes the generated SQL to become:
DELETE FROM sys_dept
WHERE id = 1
OR concat(',', tree_path, ',') LIKE concat('%,', '1') OR 1=1--', ',%')
Since OR 1=1 is always true and -- comments out the subsequent content, this will delete all records in the entire department table.
Fix Recommendations
Solution 1: Use like Method (Recommended)
Replace apply with the safe method provided by MyBatis-Plus:
@Override
public boolean deleteByIds(String ids) {
AtomicBoolean result = new AtomicBoolean(true);
List<String> idList = Arrays.asList(ids.split(","));
Optional.ofNullable(idList).orElse(new ArrayList<>()).forEach(id -> {
// Pre-construct the matching pattern
String pattern = "%," + id + ",%";
result.set(this.remove(new LambdaQueryWrapper<SysDept>()
.eq(SysDept::getId, id)
.or()
.like(SysDept::getTreePath, pattern) // Use like method
));
});
return result.get();
}
Note: This solution requires ensuring the tree_path field format is ,1,2,3, (with commas at both ends).
Solution 2: Use Parameterized apply (Alternative)
If the concat function must be used, pre-calculate the pattern value:
Optional.ofNullable(idList).orElse(new ArrayList<>()).forEach(id -> {
String pattern = "%," + id + ",%";
result.set(this.remove(new LambdaQueryWrapper<SysDept>()
.eq(SysDept::getId, id)
.or()
.apply("concat(',', tree_path, ',') like {0}", pattern) // Pass complete pattern
));
});
CVE-ID: CVE-2025-65542
Vulnerability Description
File Location:
youlai-admin/admin-boot/src/main/java/com/youlai/admin/service/impl/SysDeptServiceImpl.java:181-187Severity Level: High
Attack Vector: REST API Endpoint
Vulnerable Endpoint
Vulnerable Code
Vulnerability Details
The vulnerability exists in the data flow from the REST API endpoint to the database query:
idsparameter is received from the URL path variable through the@PathVariableannotation in the controllerdeleteByIds()service methodLambdaQueryWrapper.apply()method performs raw string substitution rather than parameterized queries, allowing SQL injectionThe path variable
idsis directly concatenated into the SQL statement through the{0}placeholder without any escaping or validation.Proof of Concept
An attacker with the
sys:dept:deletepermission can craft a malicious request:This causes the generated SQL to become:
Since
OR 1=1is always true and--comments out the subsequent content, this will delete all records in the entire department table.Fix Recommendations
Solution 1: Use
likeMethod (Recommended)Replace
applywith the safe method provided by MyBatis-Plus:Note: This solution requires ensuring the
tree_pathfield format is,1,2,3,(with commas at both ends).Solution 2: Use Parameterized
apply(Alternative)If the
concatfunction must be used, pre-calculate the pattern value: