{"record":{"id":"d682e4698d4f05d5","repo":"SonarSource/sonarqube","slug":"insufficient-privileges-d682e4","errorCode":null,"errorMessage":"Insufficient privileges","messagePattern":"Insufficient privileges","errorType":"exception","errorClass":"ForbiddenException","httpStatus":403,"severity":"error","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java","lineNumber":227,"sourceCode":"        return Optional.empty();\n      }\n      // get the gate status as it was computed during the specified analysis\n      String analysisUuid = projectAndSnapshot.snapshotDto.get().getUuid();\n      return dbClient.projectMeasureDao().selectMeasure(dbSession, analysisUuid, projectAndSnapshot.branch.getUuid(), CoreMetrics.QUALITY_GATE_DETAILS_KEY)\n        .map(ProjectMeasureDto::getData);\n    }\n\n    // do not restrict to a specified analysis, use the live measure\n    return dbClient.measureDao().selectByComponentUuid(dbSession, projectAndSnapshot.branch.getUuid())\n      .map(m -> m.getString(CoreMetrics.QUALITY_GATE_DETAILS_KEY));\n  }\n\n  private void checkPermission(ProjectDto project) {\n    if (!userSession.hasEntityPermission(ProjectPermission.ADMIN, project) &&\n        !userSession.hasEntityPermission(ProjectPermission.USER, project) &&\n        !userSession.hasEntityPermission(ProjectPermission.SCAN, project) &&\n        !userSession.hasPermission(GlobalPermission.SCAN)) {\n      throw insufficientPrivilegesException();\n    }\n  }\n\n  @Immutable\n  private static class ProjectAndSnapshot {\n    private final BranchDto branch;\n    private final Optional<SnapshotDto> snapshotDto;\n    private final ProjectDto project;\n\n    private ProjectAndSnapshot(ProjectDto project, BranchDto branch, @Nullable SnapshotDto snapshotDto) {\n      this.project = project;\n      this.branch = branch;\n      this.snapshotDto = Optional.ofNullable(snapshotDto);\n    }\n  }\n}\n","sourceCodeStart":209,"sourceCodeEnd":244,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java#L209-L244","documentation":"The api/qualitygates/project_status web service requires that the caller hold at least one of: project ADMIN, project USER, project SCAN, or global SCAN (Execute Analysis) permission. checkPermission throws insufficientPrivilegesException when none are present. This endpoint exposes quality-gate status for a project/branch, so it is accessible to project users, project admins, and CI accounts with scan rights.","triggerScenarios":"Calling GET api/qualitygates/project_status for a project where the token's user has none of the four checked permissions — typically an anonymous request, or a CI token whose user lost all project roles and the global 'Execute Analysis' permission.","commonSituations":"CI pipelines calling project_status with a token created before the user's roles were reset; external status dashboards polling the endpoint anonymously; granting SCAN on the project but to a group the CI user isn't in.","solutions":["Grant the calling user global 'Execute Analysis' (scan) permission, the usual fix for CI tokens.","Or add the user to the project with SCAN, ADMIN, or USER permission via api/permissions/add_user.","Ensure the request is authenticated — anonymous users almost always lack all four permissions.","If using a project-wide group permission, confirm the token's user is actually a member of that group."],"exampleFix":"// before: CI token with no permissions\ncurl -u citoken: \"$SONAR/api/qualitygates/project_status?projectKey=my.project\"\n\n// after: grant global scan permission to the CI user\ncurl -u admintoken: -X POST \"$SONAR/api/permissions/add_user?permission=scan&login=ci-user\"","handlingStrategy":"try-catch","validationCode":"curl -u \"$TOKEN\": \"$SONAR/api/permissions/users?projectKey=my.project&login=$USER\" | grep -E '\"scan\"|\"admin\"|\"user\"'\ncurl -u \"$TOKEN\": \"$SONAR/api/permissions/user?login=$USER\" | grep '\"scan\"'","typeGuard":null,"tryCatchPattern":"try {\n  ProjectStatus status = wsClient.qualityGates().projectStatus(req);\n} catch (ServiceErrorException e) {\n  if (e.errors().contains(\"Insufficient privileges\")) {\n    // grant global scan or project scan/admin/user to the token's user\n  }\n}","preventionTips":["Give CI service accounts the global 'Execute Analysis' permission once, reuse across projects.","Keep group-based project permissions so role resets don't orphan CI tokens.","Never call authenticated endpoints anonymously; always pass a token.","Test permissions with a dry-run call before wiring into pipelines."],"tags":["sonarqube","webapi","authorization","ci","quality-gates"],"backgroundTag":"insufficient-permissions","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}