Skip to content

JeecgBoot Tenant Privilege Escalation: GET /sys/position/getPositionUserList Position Member Query Without Tenant Validation #39

@Hwwg

Description

@Hwwg

JeecgBoot Tenant Privilege Escalation: GET /sys/position/getPositionUserList Position Member Query Without Tenant Validation

Contributors: huangweigang

1. Impact Scope

2. Vulnerable Endpoint

  • GET /sys/position/getPositionUserList?positionId=...&pageNo=1&pageSize=10 (Get Position User List API)

3. Code Analysis

  • Controller: jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/controller/SysPositionController.java
    • Route & method:
      • @GetMapping("/getPositionUserList")
      • public Result<IPage<SysUser>> getPositionUserList(@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, @RequestParam(name = "positionId") String positionId)
    • Key code (lines 358–373):
      • Page<SysUser> page = new Page<>(pageNo, pageSize);
      • IPage<SysUser> pageList = userPositionService.getPositionUserList(page, positionId);
      • List<String> userIds = pageList.getRecords().stream().map(SysUser::getId).collect(Collectors.toList());
      • if (null != userIds && userIds.size() > 0) {
      • Map<String, String> useDepNames = userService.getDepNamesByUserIds(userIds);
      • pageList.getRecords().forEach(item -> {
      • item.setOrgCodeTxt(useDepNames.get(item.getId()));
      • });
      • }
      • return Result.ok(pageList);
  • Problem points:
    • The endpoint directly uses the positionId parameter to query the user list under the position
    • Does not verify whether the position belongs to the current tenant
    • Attackers can obtain personnel information of other tenants by enumerating position IDs
    • Returned user information includes username, real name, department affiliation and other sensitive data

4. Reproduction

-- Prerequisites

  • Attacker has a valid login session
  • Attacker knows or can enumerate the target tenant's position ID
  • System has position management functionality configured

-- Steps (Cross-tenant Personnel Information Disclosure)

  • Using attacker account (Tenant A):
    • curl -X GET -H "Authorization: Bearer <attacker_token>" "http://<host>/jeecgboot/sys/position/getPositionUserList?positionId=<victim_position_id>&pageNo=1&pageSize=100"
  • Observation: API returns 200 OK, returns user list under the target tenant's position, including:
    • User ID (id)
    • Username (username)
    • Real name (realname)
    • Department name (orgCodeTxt)
    • Other user attribute information
  • Verification:
    • Use Tenant B's administrator account to query the same position's member list
    • Database query sys_user_position association table to confirm data ownership

5. Impact

  • Cross-tenant personnel information disclosure
    • Attackers can obtain other tenants' employee information (names, accounts, departments, etc.)
    • Serious invasion of user privacy, violating data protection regulations
  • Organizational structure exposure
    • Organization structure can be inferred through the correspondence between positions and personnel
    • Understand personnel allocation for different positions
  • Provides intelligence for social engineering attacks
    • After obtaining real names and position information, targeted phishing attacks can be conducted
    • Impersonate specific position personnel for fraud
  • Account enumeration
    • Obtain a list of valid usernames, providing targets for brute force attacks

6. Remediation

  • Position tenant ownership validation
    • Verify whether the position belongs to the current tenant before querying:
      • SysPosition position = sysPositionService.getById(positionId);
      • LoginUser currentUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
      • if(position == null || !position.getTenantId().equals(currentUser.getTenantId())) {
      • return Result.error("Unauthorized to access this position data");
      • }
  • Force tenant filtering
    • Add tenant validation in the Service layer's getPositionUserList method
    • Ensure only current tenant's position and user information is returned
  • Data desensitization
    • Apply desensitization to sensitive user information (such as phone numbers, emails)
    • Return different granularity of user information based on querier's permissions
  • Permission level control
    • Restrict only HR administrators or department heads to view position member lists
  • Audit logging
    • Record all position member query operations
    • Monitor abnormal query behavior (such as querying many different positions in a short time)

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