ci: read the PR head ref from the environment instead of interpolating it into PowerShell - #3107
ci: read the PR head ref from the environment instead of interpolating it into PowerShell#3107kobihikri wants to merge 1 commit into
Conversation
…g it into PowerShell
There was a problem hiding this comment.
Pull request overview
This PR hardens the GitHub Actions workflow by preventing PowerShell expression expansion from untrusted PR head branch names, by passing the PR head ref via an environment variable instead of interpolating it directly into the script.
Changes:
- Adds
HEAD_REFto the step environment using${{ github.head_ref }}. - Updates the PowerShell step to read
$headReffrom$env:HEAD_REFrather than a double-quoted interpolated string.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@kobihikri Appreciate you spotting this failure, since I see passing this as an environment variable to task better than having it interpolated as actual PowerShell script (not just for hardening reasons), this PR is excitedly accepted. 👍🏻 Please also introduce the same change as discussed for the other actions as well, this is a reasonable change that needs to stay consistent between all of our GitHub actions, not just the build one. Thank you for using Cmder! ❤️ And would love to get your feedback on the P.S. Thanks for the disclaimer, we appreciate it for the AI assisted contributions to be clearly marked as such; that being said I've extensively used Codex with the recent commits to help getting CI/CD work ahead. |
Hi, and thanks for Cmder.
In
.github/workflows/build.yml, the "Summary - Repository checkout" step reads the PR's source branch name into PowerShell by interpolation:Actions substitutes
${{ ... }}into the script text before PowerShell parses it, so the branch name becomes part of the script rather than a string. PowerShell expands$(...)inside double-quoted strings, and git allows$,(and)in branch names — so a PR from a fork on a branch named something likex$(...)would run that rather than being assigned to$headRef.Scope, so I am not overstating it: the workflow triggers on
pull_request, so a fork PR gets a read-only token and no secrets. This is hardening.The change reads that one value from the environment:
I deliberately left
$refNameand$eventNameas they are:github.ref_nameon this workflow's own runs andgithub.event_nameare GitHub-controlled values with fixed shapes, not attacker-supplied free text, so they do not carry the same problem and I did not want to widen the diff beyond what is actually at issue.I noticed the same
$headRef = "${{ github.head_ref }}"line incodeql.ymlandtests.yml. I have kept this PR tobuild.ymlso it stays easy to review — happy to send the same one-line change for the other two if you would like it, or to fold them in here, whichever you prefer.Disclosure: I used AI assistance to help spot this and prepare the change, and I read the workflows myself.