{"record":{"id":"99e1cb5c15c05076","repo":"SonarSource/sonarqube","slug":"insufficient-privileges-99e1cb","errorCode":null,"errorMessage":"Insufficient privileges","messagePattern":"Insufficient privileges","errorType":"http","errorClass":"ForbiddenException","httpStatus":403,"severity":"error","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/SafeModeHealthAction.java","lineNumber":46,"sourceCode":"\npublic class SafeModeHealthAction implements SystemWsAction {\n  private final HealthActionSupport support;\n  private final SystemPasscode systemPasscode;\n\n  public SafeModeHealthAction(HealthActionSupport support, SystemPasscode systemPasscode) {\n    this.support = support;\n    this.systemPasscode = systemPasscode;\n  }\n\n  @Override\n  public void define(WebService.NewController controller) {\n    support.define(controller, this);\n  }\n\n  @Override\n  public void handle(Request request, Response response) throws Exception {\n    if (!systemPasscode.isValid(request)) {\n      throw new ForbiddenException(\"Insufficient privileges\");\n    }\n\n    WsUtils.writeProtobuf(support.checkNodeHealth(), request, response);\n  }\n}\n","sourceCodeStart":28,"sourceCodeEnd":52,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/SafeModeHealthAction.java#L28-L52","documentation":"SafeModeHealthAction serves the safe-mode health Web API (api/safe_mode/health) and is protected by the system pass code rather than a user session. If the request does not carry the correct passcode (header or parameter configured as sonar.web.systemPasscode), the action throws ForbiddenException 'Insufficient privileges' without evaluating node health.","triggerScenarios":"Calling api/safe_mode/health without the sonar.web.systemPasscode value, or with a wrong/expired passcode, e.g. during a SonarQube startup where the health check runs before the passcode was configured.","commonSituations":"Load balancers or Kubernetes probes scraping the safe-mode health endpoint with credentials not set (property missing in sonar.properties) or rotated in one place but not the other; monitoring agents after a passcode change.","solutions":["Set/verify sonar.web.systemPasscode in sonar.properties and send its value via the X-Sonar-Passcode header (or passcode parameter) on the health request.","Re-check the client side secret: confirm the monitoring tool's stored passcode matches the current server value and restart/reload it after rotation.","If passcode auth is not desired for probes, restrict the endpoint at the network level and configure the passcode for the probing system specifically."],"exampleFix":"// before\ncurl http://sonarqube:9000/api/safe_mode/health\n// after\ncurl -H \"X-Sonar-Passcode: $SONAR_SYSTEM_PASSCODE\" http://sonarqube:9000/api/safe_mode/health","handlingStrategy":"validation","validationCode":"if (!process.env.SONAR_SYSTEM_PASSCODE) {\n  throw new Error('SONAR_SYSTEM_PASSCODE must be set to call safe-mode WS');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await http.get('/api/safe_mode/health', { headers: { 'X-Sonar-Passcode': passcode } });\n} catch (e) {\n  if (e.status === 403) {\n    log('passcode invalid or missing; reload from secret');\n  } else { throw e; }\n}","preventionTips":["Always send the X-Sonar-Passcode header with the sonar.web.systemPasscode value on safe-mode endpoints.","Keep the passcode in a shared secret synced between server config and monitoring clients.","Test probes after any passcode rotation or server redeploy."],"tags":["sonarqube","webapi","passcode","authorization"],"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"}