A SonarQube server holds a readable copy of every project it analyses, plus the tokens that connect it to your source control platform, so an exposed or loosely permissioned instance is a source code leak waiting to happen. The FBI warned in October 2020 that attackers were scanning the internet for SonarQube on its default port and logging in with default administrator credentials to steal proprietary code from government agencies and companies. This guide covers how identity and access work in SonarQube Server, the permissions that decide who can read source, the token types used by scanners and IDEs, DevOps platform integration secrets, audit logging and a hardening baseline. It is for application security engineers, platform teams and anyone who runs SonarQube Server (self-managed) rather than the SaaS SonarQube Cloud. Behaviour below was checked against the SonarQube Server 2026.5 documentation on 27 October 2026; editions differ, and features marked Enterprise are not in Community Build or Developer Edition.
Key takeaways
- New projects are public by default. Unless you change "Default visibility of new projects" to Private, every authenticated user, and anonymous users if forced authentication is off, can browse the project and see its source code.
- User tokens are the user. A user token carries every permission of the account that created it, so an administrator's token is full control of the instance; scanners should use project analysis tokens instead.
- Disabling the IdP account does not kill tokens. SonarQube's documentation states that deactivating a user in the identity provider does not revoke their SonarQube tokens: you must deactivate the user in SonarQube as well.
- The integration settings are crown jewels. Global DevOps platform settings store personal access tokens for GitLab, Azure DevOps and Bitbucket Data Center, and the GitHub App private key, client secret and webhook secret; encrypt them and treat the server as a tier 1 system.
- Never expose port 9000. SonarQube serves plain HTTP only. Put it behind a TLS reverse proxy, bind it to
127.0.0.1withsonar.web.host, and keep it off the internet entirely.
How identity and access work in SonarQube Server
SonarQube has four kinds of identity, and each one has a different failure mode. Most incidents come from the first two: anonymous access and default administrator accounts.
| Identity | What it is | Where it is managed | Main risk |
|---|---|---|---|
| Anonymous user | Anyone reaching the web interface without logging in | Administration > Configuration > General settings > Security > Force user authentication (on by default) | If switched off, anonymous users can browse public projects and run analyses, and endpoints such as api/users/search answer without login |
| Human user | Developers, reviewers, administrators | Built-in database, or delegated to HTTP header, LDAP, SAML (Microsoft Entra ID, Keycloak, Okta), GitHub, Bitbucket Cloud or GitLab | Local accounts that never get deprovisioned; the built-in admin account |
| Token | User, project analysis or global analysis token used by scanners, IDEs and scripts | My Account > Security, or Administration > Security > Users > Tokens | Long-lived tokens in CI variables and build logs; user tokens with admin rights |
| Integration identity | The credentials SonarQube uses to call GitHub, GitLab, Azure DevOps or Bitbucket | Administration > Configuration > DevOps platform integrations | A PAT or GitHub App key that can read every repository it is bound to |
Authentication and provisioning
- Just-in-time (default): accounts are created at first login. Groups must exist in SonarQube with the same name for memberships to sync, synced memberships override manual ones, and groups are re-fetched at each login.
- Automatic provisioning: the identity provider becomes the source of truth and also deprovisions. SCIM provisioning from Microsoft Entra ID and Okta needs Enterprise Edition; GitHub and GitLab provisioning, including project permission sync, needs Developer Edition. Only one provisioning identity provider can be enabled, and the instance then becomes "managed". See the SCIM Provisioning Guide.
- HTTP header authentication: trusts a header set by an upstream proxy. Only use it when the proxy is the only path to SonarQube; otherwise anyone who can reach the port can set the header.
- Case sensitivity: login names are case-sensitive but email checks are not, so identity provider accounts whose emails differ only by case cause rejected logins. Clean these up before migrating.
Project visibility
Projects are either public or private. Browse Project and See Source Code permissions only apply to private projects; a public project can be browsed, including its source, by anyone who can reach the instance. The default is public. For any organisation with proprietary code, set Administration > Projects > Management > "Default visibility of new projects" to Private on day one, then find and convert existing public projects.
Admin roles and privileged access
Permissions are granted to users or groups at two levels. Granting to groups is easier to review and to provision from an identity provider.
| Level | Permission | What it allows | Who should hold it |
|---|---|---|---|
| Global | Administer System | Full control: settings, users, tokens, plugins, integrations, encryption | Two or three named administrators |
| Global | Administer Quality Gates / Administer Quality Profiles | Change what "passing" means and which rules run | AppSec team only; changes here can silently switch off security rules |
| Global | Execute analysis | Run analysis on any project; also lets members see the branch status of any project | Only CI identities, not the whole user base |
| Global | Create Projects / Create Applications / Create Portfolios | Create new objects | Platform team or provisioning automation |
| Project | Browse Project / See Source Code | View the project, and view its code (private projects) | The owning team; See Source Code is the permission that matters for leaks |
| Project | Administer Issues / Administer Security Hotspots | Change issue status, including marking vulnerabilities and hotspots as safe or false positive | Senior developers and AppSec reviewers |
| Project | Administer project / Execute Analysis on project | Project settings and webhooks; push analyses | Project leads; the project's analysis token |
- sonar-users: contains every authenticated user, cannot be deleted or renamed, and by default holds the global Execute analysis permission. The documentation warns that this lets its members see the branch status of any project. Remove that grant and give Execute analysis to CI groups instead.
- sonar-administrators: contains the built-in
adminaccount created at installation. SonarSource recommends renaming it, because with group synchronisation from an identity provider a group of the same name could be used to gain administrator rights. - The built-in admin account: change its password at installation, store it in a vault for break-glass use, and do not use it day to day. Recovery is documented through direct database queries, which means database administrators are effectively SonarQube administrators too.
- Permission templates: templates match project keys by regular expression and apply at project creation. A change to a template does not update existing projects; reapply it in bulk after edits, or old projects keep old permissions.
- Who can mark a hotspot safe: Administer Security Hotspots is a security decision, not a developer convenience. Track who holds it and review status changes, as covered in the SAST Triage Guide.
Integrations, API tokens and service accounts
Token types
| Token | Scope | Who can create it | Use for |
|---|---|---|---|
| User token | Every action the user can do in the UI, through the Web API | Any user, for themselves; administrators can generate for others | IDE Connected mode (which requires a user token) and personal scripts; never CI |
| Project analysis token | Analysis of one project, plus web services needing Execute Analysis on it | Users with Execute Analysis on that project or globally | The default for CI: a leak exposes one project |
| Global analysis token | Analysis of every project | Users with global Execute Analysis | Shared build platforms that cannot hold per-project secrets; minimise |
- Expiry: users can choose an expiration date or "No expiration". In Enterprise Edition an administrator can set "Maximum allowed lifetime for token" under Administration > Configuration > General settings > Security, which removes the No expiration option. It applies to newly generated tokens only, so existing never-expiring tokens must be found and revoked.
- Rotation signals: with email configured, users get a reminder seven days before expiry. Web API responses carry a
SonarQube-Authentication-Token-Expirationheader that automation can read to rotate before failure. - Permission coupling: if a token's author loses the relevant permission, the token stops working for analysis. This is useful for offboarding, but it also means CI tokens tied to a person break when that person moves team. Create analysis tokens from a dedicated, non-interactive service user owned by the platform team.
- How scanners pass tokens: through the
sonar.tokenproperty or theSONAR_TOKENenvironment variable. Keep it in the CI platform's secret store, never insonar-project.propertiescommitted to the repository. Tokens are shown once at creation and cannot be retrieved later.
Scanner tokens live in CI environments, and CI environment variables are a known harvest target: in the Codecov breach, a tampered uploader script sent every CI job's environment variables to the attacker. See the CI/CD Pipeline Identity Security Guide.
DevOps platform integrations
To decorate pull requests and import projects, SonarQube stores credentials for your source control platform: personal access tokens for GitLab, Azure DevOps and Bitbucket Data Center, and for GitHub an App ID, client secret, private key and webhook secret. These can usually read every repository the integration is bound to.
- Prefer a GitHub App over a PAT where the platform supports it, installed only on the repositories that are analysed, with read access to code and write access to checks and pull requests only.
- Use a dedicated bot account for GitLab, Azure DevOps and Bitbucket PATs, with the narrowest scope the integration documents and an expiry date, and record its owner. See the GitLab Tokens Security Guide and the GitHub Personal Access Tokens Security Guide.
- Encrypt the settings: generate a secret key under Administration > Configuration > Encryption, store it at
~/.sonar/sonar-secret.txt(or the path insonar.secretKeyPath) readable only by the service account, and replace plaintext values with the{aes-gcm}encrypted form. This coverssonar.jdbc.passwordand the global DevOps integration settings. It does not cover PATs entered when importing or binding a single project, which SonarQube rejects in encrypted form.
Webhooks
Webhooks POST a JSON payload after each analysis with the project key, quality gate conditions and status, the server URL and the revision. SonarQube signs the body with HMAC-SHA256 using the secret stored in the webhook configuration. Always set a secret and verify the signature at the receiver, especially when a quality gate result triggers a deployment step. See the Webhook Secrets Security Guide.
Logging and detection
SonarQube writes its own server logs under the installation's logs directory (including web.log, ce.log for the compute engine and access.log for HTTP requests). Enterprise Edition adds audit logs. Ship both to your SIEM, because Housekeeping deletes audit logs monthly by default and the documentation recommends exporting them at shorter intervals.
| Source | What it records | What to alert on |
|---|---|---|
| Audit logs (Enterprise, Administration > Audit logs) | Changes to user accounts, permissions and global security settings; project, application and portfolio create/update/delete; plugin installs and updates; licence changes; project binding | Grants of Administer System; Force user authentication turned off; new plugin installed; project visibility set to public; new DevOps binding |
Reverse proxy and access.log | Every HTTP request, source address and path | Logins as admin; bursts of api/sources/raw or api/sources/show calls across many projects (bulk source download); API calls from addresses outside CI and office ranges |
| Identity provider sign-in logs | SAML or OAuth logins to SonarQube | Logins from unexpected countries; accounts that log in but are disabled elsewhere |
| CI platform logs | Which pipeline used which token | A project analysis token used from a runner that does not build that project |
| External attack surface scans | Internet-facing services | Any SonarQube login page or port 9000 reachable from the internet |
The ATT&CK techniques that describe the threat are T1078.001 Default Accounts (admin/admin), T1190 Exploit Public-Facing Application, T1213.003 Code Repositories for collection of source, and T1552.001 Credentials In Files for secrets found inside the analysed code. Remember that SonarQube's issue list itself can point an intruder straight at hard-coded credentials, so the findings are sensitive data too.
Metrics that show it is working
- Public project count: number of public projects on an instance that holds proprietary code (target 0).
- Never-expiring tokens: tokens with No expiration, and tokens older than your rotation period (target 0 after a cleanup).
- User tokens in CI: share of pipelines authenticating with a user or global token rather than a project analysis token.
- Administrator count: holders of Administer System, reviewed quarterly (target 3 or fewer).
- Orphaned accounts: active SonarQube users with no matching active identity provider account.
- Internet exposure: days any SonarQube endpoint was reachable from the internet (target 0).
Hardening baseline
Roll this out in order. Each phase can be tested on a staging instance restored from a production database backup.
- Find every instance. Search attack surface data and cloud inventories for SonarQube login pages and port 9000. Teams often run forgotten instances for one-off audits. See the Attack Surface Management Guide.
- Close the network. Set
sonar.web.host=127.0.0.1, terminate TLS at a reverse proxy with a CA-signed certificate, setX-Forwarded-ProtoandX-Forwarded-For(mandatory for HTTPS and SAML), and expose only the proxy port, ideally only to corporate networks and CI runners. Restrict the database and Elasticsearch ports to the host. See the Proxies and Forward vs Reverse Proxy Security Guide. - Lock the front door. Confirm Force user authentication is on, change the
adminpassword, rename sonar-administrators, and connect SAML or another delegated method with MFA enforced at the identity provider. - Close source visibility. Set new project visibility to Private, convert existing public projects, remove Execute analysis from sonar-users, and fix permission templates, reapplying them in bulk.
- Replace tokens. Create a service user, issue project analysis tokens per pipeline with expiry, move them into the CI secret store, then revoke old user and global tokens. Run old and new in parallel for one release cycle; rollback is re-enabling the old token in the CI variable, so revoke only after the pipelines show green with the new one.
- Protect integration secrets. Encrypt DevOps platform and database settings, narrow the GitHub App installation or PAT scope, and set a webhook secret on every webhook.
- Turn on logging. Forward proxy, server and audit logs, set the token maximum lifetime if licensed, and add the alerts above.
- Patch on a schedule. Track SonarSource release notes and stay on a supported version; plugins installed from the marketplace run inside the server, so allow only the plugins you need.
Choosing an edition and deployment model
- Small teams: Community Build has no audit log, no token lifetime cap and no SCIM. Compensate with proxy logging, a quarterly manual token review and SSO through the proxy or SAML where available. If the team cannot run a server securely, the hosted SonarQube Cloud moves network and patching responsibility to the vendor, at the cost of sending code to a third party.
- Large organisations: Enterprise Edition features (audit logs, maximum token lifetime, SCIM from Entra ID or Okta) are the controls that make SonarQube auditable at scale. Consider separate instances for highly sensitive code rather than relying on project permissions alone.
Common misconfigurations
- Internet-facing on port 9000 with admin/admin: FBI Flash MU-000136-MW (14 October 2020) described actors scanning for exactly this from April 2020 and publishing stolen source code. The pattern is the same as the Nissan source code leak, where an internet-facing Git server on default credentials exposed about 20GB of code.
- Public by default left in place: projects created by CI land as public and every employee, contractor and, with forced authentication off, every visitor can read the code.
- An administrator's user token in CI: convenient once, then copied across dozens of pipelines and build logs. Anyone with the CI variable has full control of the instance.
- Offboarding only in the identity provider: the person can no longer log in, but their tokens keep working until they are deactivated in SonarQube.
- Plaintext integration secrets:
sonar.propertieswith a database password and GitHub App key in clear text, backed up to a shared file store. - Treating findings as non-sensitive: the vulnerability and secrets findings list is a map of weaknesses. If code is leaked, assume the issue list was too, and follow the Source Code Leak Response Playbook.
Framework mapping
| Control area | NIST SP 800-53 Rev 5 | NIST CSF 2.0 | CIS Controls v8.1 | ISO/IEC 27001:2022 Annex A |
|---|---|---|---|---|
| Default accounts, admin count, permissions | AC-2, AC-6 | PR.AA-05 | 4.7, 5.4, 6.8 | A.5.15, A.8.2 |
| Tokens and integration secrets | IA-5 | PR.AA-05 | 3.11, 5.2 | A.5.17 |
| Network exposure and TLS | CM-7, SC-8 | PR.PS-01 | 4.4, 12.2 | A.8.20, A.8.24 |
| Configuration baseline | CM-6 | PR.PS-01 | 4.1 | A.8.9 |
| Audit logging | AU-2 | DE.CM-09 | 8.2 | A.8.15 |
Practitioner checklist
- Confirm no SonarQube instance is reachable from the internet, and that the server listens only on 127.0.0.1 behind a TLS proxy.
- Verify Force user authentication is on and the built-in admin password has been changed and vaulted.
- Rename sonar-administrators and keep Administer System to three or fewer named people.
- Set default project visibility to Private and convert all existing public projects.
- Remove the global Execute analysis permission from sonar-users.
- Replace user and global tokens in CI with expiring project analysis tokens owned by a service user.
- Deactivate leavers in SonarQube, not only in the identity provider, and review tokens per user quarterly.
- Encrypt database and DevOps integration secrets with the AES-256 secret key, and narrow GitHub App or PAT scope.
- Set an HMAC secret on every webhook and verify signatures at the receiver.
- Export audit and proxy logs to the SIEM before Housekeeping deletes them, with alerts for permission and visibility changes.
Standards and references
- SonarSource: SonarQube Server, Managing your tokens
- SonarSource: SonarQube Server, Managing permissions
- SonarSource: SonarQube Server, Authentication and provisioning overview
- SonarSource: SonarQube Server, Encrypting sensitive settings
- SonarSource: SonarQube Server, Securing behind a proxy
- SonarSource: SonarQube Server, Audit logs
- FBI: Cyber Actors Target Misconfigured SonarQube Instances (Flash MU-000136-MW)
- MITRE ATT&CK: T1213.003 Code Repositories
Related NHI Mgmt Group resources: Application Security Testing Buyer's Guide · SAST Triage Guide · CI/CD Pipeline Identity Security Guide · API Key Management Guide · Source Code Leak Response Playbook