Skip to content

JeecgBoot Tenant Privilege Escalation: GET /sys/sysDepartRole/datarule/{permissionId}/{departId}/{roleId} Data Rule Query Without Tenant Validatio #35

@Hwwg

Description

@Hwwg

JeecgBoot Tenant Privilege Escalation: GET /sys/sysDepartRole/datarule/{permissionId}/{departId}/{roleId} Data Rule Query Without Tenant Validation

Contributors: huangweigang

1. Impact Scope

2. Vulnerable Endpoint

  • GET /sys/sysDepartRole/datarule/{permissionId}/{departId}/{roleId} (Query Data Rule Information API)

3. Code Analysis

  • Controller: jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysDepartRoleController.java
    • Route & method:
      • @GetMapping(value = "/datarule/{permissionId}/{departId}/{roleId}")
      • public Result<?> loadDatarule(@PathVariable("permissionId") String permissionId,@PathVariable("departId") String departId,@PathVariable("roleId") String roleId)
    • Key code (lines 236–260):
      • //Query authorized department rules
      • List<SysPermissionDataRule> list = sysDepartPermissionService.getPermRuleListByDeptIdAndPermId(departId,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<SysDepartRolePermission> query = new LambdaQueryWrapper<SysDepartRolePermission>()
      • .eq(SysDepartRolePermission::getPermissionId, permissionId)
      • .eq(SysDepartRolePermission::getRoleId,roleId);
      • SysDepartRolePermission sysRolePermission = sysDepartRolePermissionService.getOne(query);
      • if(sysRolePermission==null) { ... }
      • else {
      • String drChecked = sysRolePermission.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, roleId, permissionId to query data permission rules
    • Does not verify whether the department and role belong to the current tenant
    • Attackers can obtain other tenants' data permission rule configurations
    • Data permission rules are sensitive permission control information, and leakage may be used to bypass access controls

4. Reproduction

-- Prerequisites

  • Attacker has a valid login session
  • Attacker knows or can enumerate the target tenant's department ID, role ID, permission ID
  • System has 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/sysDepartRole/datarule/<permission_id>/<victim_dept_id>/<victim_role_id>"
  • Observation: API returns 200 OK, returns target tenant's data permission rule configuration, including:
    • datarule: List of department permission data rules
    • drChecked: Data rule IDs selected for this role
  • Verification:
    • Use Tenant B's administrator account to query the same data rule configuration and confirm data consistency
    • Database query confirms the returned data rules belong to another tenant

5. Impact

  • Data permission rule disclosure
    • Attackers can obtain other tenants' data permission control rules
    • Understand the target system's data access control policies (such as filtering rules by department, region, etc.)
  • Complete permission system exposure
    • Combined with other vulnerabilities, attackers can completely map the target tenant's permission architecture
  • Provides intelligence for permission bypass attacks
    • After understanding data permission rules, targeted bypass strategies can be constructed
  • Business logic disclosure
    • Data permission rules often reflect the business's organizational structure and data access policies

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 data rules");
      • }
  • Role tenant ownership validation
    • Verify whether the role belongs to the current tenant's department:
      • SysDepartRole role = sysDepartRoleService.getById(roleId);
      • if(role == null || !role.getDepartId().equals(departId)) {
      • return Result.error("Role does not match department");
      • }
  • Force tenant filtering
    • Add tenant ID filtering conditions in all queries
  • Permission level control
    • Restrict only department administrators or system administrators to view data permission rules
  • Audit logging
    • Record all data permission rule query operations for security auditing

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions