JeecgBoot Tenant Privilege Escalation: GET /sys/sysDepartPermission/datarule/{permissionId}/{departId} Department Permission Data Rule Query Without Tenant Validation
Contributors: huangweigang
1. Impact Scope
2. Vulnerable Endpoint
- GET
/sys/sysDepartPermission/datarule/{permissionId}/{departId} (Department Management Authorization Query Data Rule API)
3. Code Analysis
- Controller:
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java
- Route & method:
@GetMapping(value = "/datarule/{permissionId}/{departId}")
public Result<?> loadDatarule(@PathVariable("permissionId") String permissionId,@PathVariable("departId") String departId)
- Key code (lines 177–200):
List<SysPermissionDataRule> list = sysPermissionDataRuleService.getPermRuleListByPermId(permissionId);
if(list==null || list.size()==0) {
return Result.error("Permission configuration information not found");
}else {
Map<String,Object> map = new HashMap(5);
map.put("datarule", list);
LambdaQueryWrapper<SysDepartPermission> query = new LambdaQueryWrapper<SysDepartPermission>()
.eq(SysDepartPermission::getPermissionId, permissionId)
.eq(SysDepartPermission::getDepartId,departId);
SysDepartPermission sysDepartPermission = sysDepartPermissionService.getOne(query);
if(sysDepartPermission==null) { ... }
else {
String drChecked = sysDepartPermission.getDataRuleIds();
if(oConvertUtils.isNotEmpty(drChecked)) {
map.put("drChecked", drChecked.endsWith(",")?drChecked.substring(0, drChecked.length()-1):drChecked);
}
}
return Result.ok(map);
}
- Problem points:
- The endpoint directly uses path parameters
departId and permissionId to query department permission data rules
- Does not verify whether the department belongs to the current tenant
- Attackers can obtain other tenants' department permission data rule configurations by constructing arbitrary department IDs
- Data rules are fine-grained data access control policies; leakage seriously affects data security
4. Reproduction
-- Prerequisites
- Attacker has a valid login session
- Attacker knows or can enumerate the target tenant's department ID and permission ID
- System has department-level data permission rules configured
-- Steps (Cross-tenant Data Permission Rule Disclosure)
- Using attacker account (Tenant A):
curl -X GET -H "Authorization: Bearer <attacker_token>" "http://<host>/jeecgboot/sys/sysDepartPermission/datarule/<permission_id>/<victim_dept_id>"
- Observation: API returns 200 OK, response data contains:
datarule: List of all data rules for this permission (field-level filtering rules)
drChecked: Data rule IDs configured for the target department
- Verification:
- Use Tenant B's administrator account to query the same endpoint and confirm data consistency
- Database query sys_depart_permission table to confirm the returned configuration belongs to another tenant
5. Impact
- Data access control policy disclosure
- Attackers can obtain other tenants' data permission rules (such as filtering rules by field, by condition)
- Understand the target system's fine-grained access control policies for data
- Business logic and data structure disclosure
- Data rules often contain field names, filtering conditions, etc., exposing database structure and business logic
- Complete permission system mapping
- Combined with information disclosure from other endpoints, the target tenant's permission management system can be completely reconstructed
- Provides intelligence for data leakage attacks
- After understanding data filtering rules, attackers can construct targeted bypass strategies
6. Remediation
- Department tenant ownership validation
- Verify whether the department belongs to the current tenant before querying:
SysDepart depart = sysDepartService.getById(departId);
LoginUser currentUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
if(depart == null || !depart.getTenantId().equals(currentUser.getTenantId())) {
return Result.error("Unauthorized to access this department permission configuration");
}
- Force tenant filtering
- Add tenant ID filtering condition when querying department permissions
- Permission level control
- Restrict only department administrators or system administrators to view data permission rules
- Implement Role-Based Access Control (RBAC)
- Data desensitization
- Apply appropriate desensitization to sensitive data rule information before returning
- Audit logging
- Record all data permission rule query operations, including user, time, query parameters, etc.
JeecgBoot Tenant Privilege Escalation: GET /sys/sysDepartPermission/datarule/{permissionId}/{departId} Department Permission Data Rule Query Without Tenant Validation
Contributors: huangweigang
1. Impact Scope
2. Vulnerable Endpoint
/sys/sysDepartPermission/datarule/{permissionId}/{departId}(Department Management Authorization Query Data Rule API)3. Code Analysis
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java@GetMapping(value = "/datarule/{permissionId}/{departId}")public Result<?> loadDatarule(@PathVariable("permissionId") String permissionId,@PathVariable("departId") String departId)List<SysPermissionDataRule> list = sysPermissionDataRuleService.getPermRuleListByPermId(permissionId);if(list==null || list.size()==0) {return Result.error("Permission configuration information not found");}else {Map<String,Object> map = new HashMap(5);map.put("datarule", list);LambdaQueryWrapper<SysDepartPermission> query = new LambdaQueryWrapper<SysDepartPermission>().eq(SysDepartPermission::getPermissionId, permissionId).eq(SysDepartPermission::getDepartId,departId);SysDepartPermission sysDepartPermission = sysDepartPermissionService.getOne(query);if(sysDepartPermission==null) { ... }else {String drChecked = sysDepartPermission.getDataRuleIds();if(oConvertUtils.isNotEmpty(drChecked)) {map.put("drChecked", drChecked.endsWith(",")?drChecked.substring(0, drChecked.length()-1):drChecked);}}return Result.ok(map);}departIdandpermissionIdto query department permission data rules4. Reproduction
-- Prerequisites
-- Steps (Cross-tenant Data Permission Rule Disclosure)
curl -X GET -H "Authorization: Bearer <attacker_token>" "http://<host>/jeecgboot/sys/sysDepartPermission/datarule/<permission_id>/<victim_dept_id>"datarule: List of all data rules for this permission (field-level filtering rules)drChecked: Data rule IDs configured for the target department5. Impact
6. Remediation
SysDepart depart = sysDepartService.getById(departId);LoginUser currentUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();if(depart == null || !depart.getTenantId().equals(currentUser.getTenantId())) {return Result.error("Unauthorized to access this department permission configuration");}