Skip to content

JeecgBoot Tenant Privilege Escalation: GET /sys/sysDepartPermission/list Department Permission List Query Without Tenant Validation #37

@Hwwg

Description

@Hwwg

JeecgBoot Tenant Privilege Escalation: GET /sys/sysDepartPermission/list Department Permission List Query Without Tenant Validation

Contributors: huangweigang

1. Impact Scope

2. Vulnerable Endpoint

  • GET /sys/sysDepartPermission/list?departId=...&pageNo=1&pageSize=10 (Department Permission Table Paginated List Query 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 = "/list")
      • public Result<?> queryPageList(SysDepartPermission sysDepartPermission, @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, HttpServletRequest req)
    • Key code (lines 75–84):
      • QueryWrapper<SysDepartPermission> queryWrapper = QueryGenerator.initQueryWrapper(sysDepartPermission, req.getParameterMap());
      • Page<SysDepartPermission> page = new Page<SysDepartPermission>(pageNo, pageSize);
      • IPage<SysDepartPermission> pageList = sysDepartPermissionService.page(page, queryWrapper);
      • return Result.ok(pageList);
  • Problem points:
    • The endpoint uses QueryGenerator.initQueryWrapper to automatically build query conditions, supporting filtering via departId parameter
    • Does not validate tenant ownership of the departId parameter
    • Attackers can query other tenants' department permission configurations by specifying arbitrary department IDs
    • Completely relies on frontend-provided query parameters, lacking server-side permission verification

4. Reproduction

-- Prerequisites

  • Attacker has a valid login session
  • Attacker knows or can enumerate the target tenant's department ID
  • System has department-level permission authorization configured

-- Steps (Cross-tenant Department Permission Configuration Disclosure)

  • Using attacker account (Tenant A):
    • curl -X GET -H "Authorization: Bearer <attacker_token>" "http://<host>/jeecgboot/sys/sysDepartPermission/list?departId=<victim_dept_id>&pageNo=1&pageSize=100"
  • Observation: API returns 200 OK, returns the target department's permission configuration list, including:
    • Department ID (departId)
    • Permission ID (permissionId)
    • Data Rule IDs (dataRuleIds)
    • Metadata such as creation time
  • Verification:
    • Use Tenant B's administrator account to query the same department's permission configuration and confirm data consistency
    • Database query sys_depart_permission table to confirm data ownership

5. Impact

  • Cross-tenant permission configuration disclosure
    • Attackers can obtain any tenant's department permission configuration information
    • Understand which menus and functions are authorized to which departments
  • Organizational structure and permission system exposure
    • Permission configuration can be reverse-engineered to infer the organization's department structure and functional divisions
  • Business functions and modules disclosure
    • Permission IDs correspond to functional modules, exposing the system's business functional architecture
  • Provides foundation for privilege escalation attacks
    • After understanding permission configuration, attackers can specifically search for privilege escalation vulnerabilities

6. Remediation

  • Department tenant ownership validation
    • When accepting departId parameter, verify whether the department belongs to the current tenant:
      • if(oConvertUtils.isNotEmpty(sysDepartPermission.getDepartId())) {
      • SysDepart depart = sysDepartService.getById(sysDepartPermission.getDepartId());
      • LoginUser currentUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
      • if(depart == null || !depart.getTenantId().equals(currentUser.getTenantId())) {
      • return Result.error("Unauthorized to access this department permission data");
      • }
      • }
  • Force tenant filtering
    • Forcibly add tenant ID filtering condition in QueryWrapper:
      • queryWrapper.eq("tenant_id", TenantContext.getTenant());
  • Database-level tenant isolation
    • Configure MyBatis-Plus multi-tenancy plugin for automatic filtering at SQL level
  • Parameter whitelist
    • Restrict allowed query parameter fields to prevent cross-tenant queries via arbitrary fields
  • Audit logging
    • Record all department permission query operations, especially focus on cross-tenant access attempts

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