| Title | JeecgBoot 3.9.0 Improper Control of Resource Identifiers |
|---|
| Description | # JeecgBoot Tenant Privilege Escalation: GET /sys/position/getPositionUserList Position Member Query Without Tenant Validation
## Contributors: huangweigang
### 1. Impact Scope
- JeecgBoot (latest)
- https://github.com/jeecgboot/jeecg-boot
### 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)
|
|---|
| Source | ⚠️ https://github.com/Hwwg/cve/issues/39 |
|---|
| User | huangweigang (UID 88993) |
|---|
| Submission | 12/10/2025 01:16 PM (4 months ago) |
|---|
| Moderation | 12/27/2025 10:01 AM (17 days later) |
|---|
| Status | Accepted |
|---|
| VulDB entry | 338504 [JeecgBoot up to 3.9.0 getPositionUserList positionId improper authorization] |
|---|
| Points | 20 |
|---|