Coordinated Disclosure Timeline
- 2024-10-11: Reported via GitHub’s Private Vulnerability Reporting (PVR).
- 2024-10-28: Fix released.
Summary
Hibernate ORM is vulnerable to Poisoned Pipeline Execution (PPE) allowing malicious actors to exfiltrate their Develocity access keys.
Project
Hibernate ORM
Tested Version
Latest version at the time of reporting.
Details
Secret Exfiltration (GHSL-2024-268
)
The contributor-build.yml
workflow runs on pull_request_target
events and therefore can be triggered by external users.
on:
push:
branches:
- 'main'
# WARNING: Using pull_request_target to access secrets, but we check out the PR head commit.
# See checkout action for details.
pull_request_target:
branches:
- 'main'
The workflow checkouts the tip of the Pull Request branch and therefore pollutes the workspace with untrusted files as clearly stated in the comment:
- name: Check out PR head
uses: actions/checkout@v4
if: github.event.pull_request.number
with:
# WARNING: This is potentially dangerous since we're checking out unreviewed code,
# and since we're using the pull_request_target event we can use secrets.
# Thus, we must be extra careful to never expose secrets to steps that execute this code,
# and to strictly limit our of secrets to those that only pose minor security threats.
# This means in particular we won't expose Develocity credentials to the main gradle executions,
# but instead will execute gradle a second time just to push build scans to Develocity;
# see below.
ref: "refs/pull/${{ github.event.pull_request.number }}/head"
persist-credentials: false
The workflow then runs untrusted code from .github/ci-prerequisites.sh
and ci/database-start.sh
scripts. Since these files are controlled by the PR author, they can contain any arbitrary code.
- name: Reclaim Disk Space
run: .github/ci-prerequisites.sh
- name: Start database
env:
RDBMS: ${{ matrix.rdbms }}
run: ci/database-start.sh
The same job uses the GRADLE_ENTERPRISE_ACCESS_KEY
secret and, therefore, it is available in the runner’s process memory for all the steps executed within the same job, not only those that receive the secret:
- name: Run build script
env:
RDBMS: ${{ matrix.rdbms }}
# Don't populate Develocity cache in pull requests as that's potentially dangerous
POPULATE_REMOTE_GRADLE_CACHE: "${{ github.event_name == 'push' }}"
# WARNING: exposes secrets, so must only be passed to a step that doesn't run unapproved code.
DEVELOCITY_ACCESS_KEY: "${{ github.event_name == 'push' && secrets.GRADLE_ENTERPRISE_ACCESS_KEY || '' }}"
An attacker able to run arbitrary code will be able to dump the runner’s memory and read any secrets made available to the runner. See “Leaking Secrets From GitHub Actions: Reading Files And Environment Variables, Intercepting Network/Process Communication, Dumping Memory” for more information.
The atlas.yml
workflow contains the same code, but in that case the only secret available is GRADLE_ENTERPRISE_ACCESS_KEY_PR
which according to the comment: “we use the same access key as for PRs, it has limited access, essentially it can only push build scans.”
Considering that GRADLE_ENTERPRISE_ACCESS_KEY_PR
has limited access for Pull Request, we assumed that GRADLE_ENTERPRISE_ACCESS_KEY
is not limited for external Pull Requests and therefore is more privileged.
Impact
Malicious actors can leak the GRADLE_ENTERPRISE_ACCESS_KEY
and GRADLE_ENTERPRISE_ACCESS_KEY_PR
secrets which may grant them access to Hibernate’s Develocity instance.
Credit
This issue was discovered and reported by GHSL team member @pwntester (Alvaro Muñoz).
Contact
You can contact the GHSL team at securitylab@github.com
, please include a reference to GHSL-2024-268
in any communication regarding this issue.