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