Skip to content

bug(ci): isolate Qodana from pull-request code

High
LMLiam published GHSA-c482-mr43-4rq3 Aug 10, 2026

Software

No package listed

Affected versions

>= 0.15.2

Patched versions

None

Description

Summary

The qodana job checks out the pull-request head and runs Qodana against pull-request-controlled files. The job grants several write permissions and passes the QODANA_TOKEN secret expression to the Qodana action.

A same-repository pull request can change build files, qodana.yaml, workflow-related inputs, and the scripts used by this job. The job then runs those pull-request-controlled inputs in a workflow that has write-capable GitHub credentials.

The current repository does not have a repository secret named QODANA_TOKEN. The workflow still defines a secret-bearing execution boundary because the expression is present and would expose a configured token to the PR-head Qodana execution. The confirmed current exposure is the excessive write permission on PR-controlled analysis. The secret exposure is conditional on a token being configured at repository or another applicable scope.

Evidence

The current default branch contains this execution path:

  1. .github/workflows/ci.yml:669-686 defines the Qodana job for pull-request analysis.
  2. .github/workflows/ci.yml:687-691 grants checks: write, pull-requests: write, and security-events: write, in addition to contents: read.
  3. .github/workflows/ci.yml:693-699 checks out ${{ github.event.pull_request.head.sha || github.sha }}.
  4. .github/workflows/ci.yml:701-711 runs JetBrains/qodana-action with upload-result: true and QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}.
  5. .github/workflows/ci.yml:713-714 runs the repository-local SARIF normalisation script after the scan. That script is also selected from the checked-out revision.
  6. .github/workflows/ci.yml:717-720 uploads the SARIF result with the job's security-events: write permission.

The Qodana job first appears in released workflow configuration at 0.15.2. The affected range is >= 0.15.2 until the workflow is remediated.

JetBrains documents that QODANA_TOKEN identifies a Qodana pipeline and is required for paid Qodana linters. JetBrains also documents that the Qodana action uses the GitHub token by default for annotations and pull-request comments. The current workflow grants those write permissions explicitly.

Impact

A contributor with same-repository pull-request write access can change the files that the Qodana job scans and the local script that normalises its result. The changed inputs run before a code-scanning upload while the job has write-capable GitHub credentials.

If QODANA_TOKEN is configured, the pull-request execution can also receive that secret through the workflow environment. A fork pull request normally receives restricted access, but that does not protect the same-repository case.

The current absence of the repository secret reduces the present impact. It does not make the workflow safe to use with a future Qodana token.

Immediate containment

Remove checks: write, pull-requests: write, and any other permission that Qodana does not strictly require from PR-head analysis. Remove the QODANA_TOKEN reference from the untrusted pull-request job until the trust boundary is redesigned.

Do not add the token to the repository while this job checks out pull-request code.

Required remediation

Choose one of these designs:

  1. Run a secretless Qodana scan on pull requests. Keep the token and result publication in a trusted workflow that runs default-branch code.
  2. Run a secret-bearing scan only in a protected environment that requires maintainer approval. Do not permit automatic execution for untrusted pull-request heads.

For either design:

  • Never expose QODANA_TOKEN to code or configuration from a pull-request head.
  • Do not check out pull-request code in the trusted uploader.
  • Pass only the minimum GitHub token permissions to each job.
  • Review Qodana's required permissions for annotations, pull-request comments, and SARIF upload separately.
  • Treat the local SARIF normalisation script as untrusted when it comes from the pull-request revision.
  • Bind uploaded results to the exact repository, workflow run, pull request, head SHA, and attempt.
  • Reject stale, malformed, unexpected, or duplicate result artifacts.

Acceptance criteria

  • A same-repository pull request cannot access QODANA_TOKEN.
  • PR-head Qodana analysis runs without write-capable GitHub permissions, or it runs only after explicit protected-environment approval.
  • The trusted uploader executes only default-branch implementation.
  • Code-scanning results remain available for valid pull requests.
  • Qodana annotations and pull-request comments continue to work through the smallest verified permission set.
  • Tests or deterministic checks cover a modified Qodana configuration, modified build files, modified local normalisation script, same-repository pull request, fork pull request, rerun, stale head, and missing result cases.

References

No code, release, or workflow change is included in this report.

Severity

High

CVE ID

No known CVE

Weaknesses

Improper Privilege Management

The product does not properly assign, modify, track, or check privileges for an actor, creating an unintended sphere of control for that actor. Learn more on MITRE.