Skip to content

Improper Access Control in InstanceController #1141

@flashzyc

Description

@flashzyc

Improper Access Control in InstanceController

Report Information

Project: PowerJob
Version: 5.1.2
Reporter: Zhang Yichao (Student, Beijing University of Posts and Telecommunications)
Discovery Date: November 21, 2025
Report Date: November 21, 2025
Severity: Critical

Executive Summary

This report identifies critical security vulnerabilities in the PowerJob server's InstanceController class, specifically related to improper access control mechanisms. The vulnerabilities allow unauthorized users to access sensitive instance data, download log files, and perform operations on instances belonging to other applications. These issues pose significant security risks including data leakage, unauthorized access to sensitive information, and potential privilege escalation.

Vulnerability Details

1. Critical: Unauthenticated Log File Download (CVE-2024-XXXX)

Location: /instance/downloadLog endpoint
Severity: Critical
CVSS Score: 8.5

@GetMapping("/downloadLog")
public void downloadLogFile(Long instanceId , HttpServletResponse response) throws Exception {
    File file = instanceLogService.downloadInstanceLog(instanceId);
    OmsFileUtils.file2HttpResponse(file, response);
}

Issue: This endpoint lacks any authentication or authorization checks. Any user with knowledge of an instanceId can download log files from any application instance.

Impact:

  • Unauthorized access to sensitive log data
  • Information disclosure across application boundaries
  • Potential exposure of credentials, API keys, or business logic

2. High: Insufficient Authorization in Instance Detail Access

Location: /instance/detailPlus endpoint
Severity: High
CVSS Score: 7.2

@PostMapping("/detailPlus")
public ResultDTO<InstanceDetailVO> getInstanceDetailPlus(@RequestBody QueryInstanceDetailRequest req, HttpServletRequest hsr) {
    req.setAppId(AuthHeaderUtils.fetchAppIdL(hsr));
    
    // Compatibility code for legacy frontend without appId
    if (req.getAppId() == null) {
        req.setAppId(instanceService.getInstanceInfo(req.getInstanceId()).getAppId());
    }
    
    return ResultDTO.success(InstanceDetailVO.from(instanceService.getInstanceDetail(req.getAppId(), req.getInstanceId(), customQuery)));
}

Issues:

  • Missing @ApiPermission annotation
  • Dangerous compatibility code that bypasses authorization when appId is null
  • No validation that the user has permission to access the specified instance

3. Medium: Inadequate Instance Ownership Validation

Location: Service layer methods
Severity: Medium
CVSS Score: 6.1

The core issue lies in the fetchInstanceInfo method which retrieves instance data without validating ownership:

private InstanceInfoDO fetchInstanceInfo(Long instanceId) {
    InstanceInfoDO instanceInfoDO = instanceInfoRepository.findByInstanceId(instanceId);
    if (instanceInfoDO == null) {
        throw new IllegalArgumentException("invalid instanceId: " + instanceId);
    }
    return instanceInfoDO; // Returns data without appId validation
}

CodeQL Analysis

To systematically identify these vulnerabilities, the following CodeQL query can be used:

/**
 * @name Improper Access Control in PowerJob InstanceController
 * @description Finds endpoints that lack proper authorization checks for instance access
 * @kind problem
 * @problem.severity error
 * @security-severity 8.5
 * @precision high
 * @id java/powerjob-instance-access-control
 * @tags security
 *       external/cwe/cwe-862
 *       external/cwe/cwe-863
 */

import java
import semmle.code.java.frameworks.spring.SpringController
import semmle.code.java.security.RequestForgery

class InstanceControllerMethod extends Method {
  InstanceControllerMethod() {
    this.getDeclaringType().hasQualifiedName("tech.powerjob.server.web.controller", "InstanceController")
  }
}

class ApiPermissionAnnotation extends Annotation {
  ApiPermissionAnnotation() {
    this.getType().hasQualifiedName("tech.powerjob.server.auth.interceptor", "ApiPermission")
  }
}

class SpringMappingAnnotation extends Annotation {
  SpringMappingAnnotation() {
    this.getType().hasQualifiedName("org.springframework.web.bind.annotation", ["GetMapping", "PostMapping", "RequestMapping"])
  }
}

class InstanceIdParameter extends Parameter {
  InstanceIdParameter() {
    this.getType().hasQualifiedName("java.lang", "Long") and
    this.getName().toLowerCase().matches("%instanceid%")
  }
}

predicate lacksApiPermission(InstanceControllerMethod method) {
  method.hasAnnotation() and
  method.getAnAnnotation() instanceof SpringMappingAnnotation and
  not method.getAnAnnotation() instanceof ApiPermissionAnnotation
}

predicate hasInstanceIdParameter(InstanceControllerMethod method) {
  method.getAParameter() instanceof InstanceIdParameter
}

predicate isPublicEndpoint(InstanceControllerMethod method) {
  method.isPublic() and
  method.hasAnnotation() and
  method.getAnAnnotation() instanceof SpringMappingAnnotation
}

from InstanceControllerMethod method
where lacksApiPermission(method) and 
      hasInstanceIdParameter(method) and
      isPublicEndpoint(method)
select method, "Instance controller method $@ lacks proper authorization checks for instance access", 
       method, method.getName()

Additional CodeQL Query for Service Layer Validation

/**
 * @name Missing Instance Ownership Validation
 * @description Finds methods that access instance data without validating application ownership
 * @kind problem
 * @problem.severity warning
 * @security-severity 6.1
 * @precision medium
 * @id java/powerjob-missing-ownership-validation
 */

import java

class InstanceServiceMethod extends Method {
  InstanceServiceMethod() {
    this.getDeclaringType().hasQualifiedName("tech.powerjob.server.core.instance", "InstanceService")
  }
}

class InstanceRepositoryCall extends MethodAccess {
  InstanceRepositoryCall() {
    this.getMethod().hasName("findByInstanceId") and
    this.getMethod().getDeclaringType().hasQualifiedName("tech.powerjob.server.persistence.remote.repository", "InstanceInfoRepository")
  }
}

predicate lacksAppIdValidation(InstanceServiceMethod method, InstanceRepositoryCall repoCall) {
  repoCall.getEnclosingCallable() = method and
  not exists(MethodAccess appIdCheck |
    appIdCheck.getEnclosingCallable() = method and
    appIdCheck.getMethod().getName().matches("%appId%")
  )
}

from InstanceServiceMethod method, InstanceRepositoryCall repoCall
where lacksAppIdValidation(method, repoCall)
select method, "Method $@ accesses instance data without validating application ownership", 
       method, method.getName()

Proof of Concept

Unauthorized Log Download

# Attacker can download logs from any instance without authentication
curl -X GET "http://target-server:7700/instance/downloadLog?instanceId=123456" \
  -o stolen_logs.log

Cross-Application Instance Access

# Attacker can access instance details from other applications
curl -X POST "http://target-server:7700/instance/detailPlus" \
  -H "Content-Type: application/json" \
  -H "AppId: 999" \
  -d '{"instanceId": 123456, "appId": null}'

Recommended Remediation

1. Immediate Fixes

Add Authorization to downloadLog endpoint:

@GetMapping("/downloadLog")
@ApiPermission(name = "Instance-DownloadLog", roleScope = RoleScope.APP, requiredPermission = Permission.READ)
public void downloadLogFile(Long instanceId, HttpServletRequest hsr, HttpServletResponse response) throws Exception {
    Long appId = AuthHeaderUtils.fetchAppIdL(hsr);
    validateInstanceOwnership(appId, instanceId);
    File file = instanceLogService.downloadInstanceLog(instanceId);
    OmsFileUtils.file2HttpResponse(file, response);
}

Fix detailPlus endpoint:

@PostMapping("/detailPlus")
@ApiPermission(name = "Instance-DetailPlus", roleScope = RoleScope.APP, requiredPermission = Permission.READ)
public ResultDTO<InstanceDetailVO> getInstanceDetailPlus(@RequestBody QueryInstanceDetailRequest req, HttpServletRequest hsr) {
    req.setAppId(AuthHeaderUtils.fetchAppIdL(hsr));
    validateInstanceOwnership(req.getAppId(), req.getInstanceId());
    // Remove dangerous compatibility code
    return ResultDTO.success(InstanceDetailVO.from(instanceService.getInstanceDetail(req.getAppId(), req.getInstanceId(), req.getCustomQuery())));
}

2. Add Instance Ownership Validation

private void validateInstanceOwnership(Long appId, Long instanceId) {
    InstanceInfoDO instance = instanceInfoRepository.findByInstanceId(instanceId);
    if (instance == null) {
        throw new IllegalArgumentException("Instance not found: " + instanceId);
    }
    if (!instance.getAppId().equals(appId)) {
        throw new SecurityException("Access denied: Instance belongs to different application");
    }
}

3. Service Layer Improvements

Modify the fetchInstanceInfo method to include application validation:

private InstanceInfoDO fetchInstanceInfo(Long instanceId, Long appId) {
    InstanceInfoDO instanceInfoDO = instanceInfoRepository.findByInstanceIdAndAppId(instanceId, appId);
    if (instanceInfoDO == null) {
        throw new IllegalArgumentException("Invalid instanceId or insufficient permissions: " + instanceId);
    }
    return instanceInfoDO;
}

Risk Assessment

Business Impact: High

  • Potential data breach affecting multiple applications
  • Compliance violations (GDPR, SOX, etc.)
  • Loss of customer trust
  • Possible regulatory fines

Technical Impact: Critical

  • Complete bypass of application-level security
  • Unauthorized access to sensitive operational data
  • Potential for lateral movement within the system

Conclusion

The identified vulnerabilities in the InstanceController represent serious security flaws that could lead to unauthorized data access and potential system compromise. Immediate action is required to implement proper authorization controls and instance ownership validation. The provided CodeQL queries can be integrated into the development workflow to prevent similar issues in the future.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions