Description
.github/workflows/format-command.yml triggers on issue_comment with no authorization check on the commenter, then checks out the PR head's fork branch and runs npx prettier --write . inside a job holding contents: write and a live GITHUB_TOKEN, before auto-committing and pushing back to the base repo.
Steps to Reproduce
- Fork the repo and open a PR from the fork containing a malicious
.prettierrc.js (Prettier configs are JS and execute on load, e.g. one that runs require('child_process').exec(...)).
- Comment
/format on your own PR.
- The workflow checks out your fork's branch and runs your config with
contents: write + GITHUB_TOKEN permissions, then commits the result back to the base repo.
Expected Behavior
Only maintainers/collaborators should be able to trigger a workflow that runs code from a PR branch with write access to the repo.
Actual Behavior
Any GitHub account, including the PR author on their own fork PR, can trigger this job. The if: condition only checks contains(github.event.comment.body, '/format'), with no check on github.event.comment.user.login or author_association.
Root Cause
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/format')
permissions:
contents: write
pull-requests: write
issues: write
steps:
- uses: actions/checkout@v4
with:
repository: ${{ fromJSON(steps.pr.outputs.result).head.repo.full_name }}
ref: ${{ fromJSON(steps.pr.outputs.result).head.ref }}
token: ${{ secrets.GITHUB_TOKEN }}
- run: npx prettier --write .
- uses: stefanzweifel/git-auto-commit-action@v5
This is the classic "pwn request" anti-pattern: untrusted fork content is checked out and executed inside a job that holds write-scoped secrets.
Suggested Fix
Gate the job on commenter authorization:
if: |
github.event.issue.pull_request != '' &&
contains(github.event.comment.body, '/format') &&
(github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'COLLABORATOR')
Alternatively, replace this with a maintained slash-command dispatcher (e.g. peter-evans/slash-command-dispatch) that handles authorization correctly.
Affected Files
.github/workflows/format-command.yml
Description
.github/workflows/format-command.ymltriggers onissue_commentwith no authorization check on the commenter, then checks out the PR head's fork branch and runsnpx prettier --write .inside a job holdingcontents: writeand a liveGITHUB_TOKEN, before auto-committing and pushing back to the base repo.Steps to Reproduce
.prettierrc.js(Prettier configs are JS and execute on load, e.g. one that runsrequire('child_process').exec(...))./formaton your own PR.contents: write+GITHUB_TOKENpermissions, then commits the result back to the base repo.Expected Behavior
Only maintainers/collaborators should be able to trigger a workflow that runs code from a PR branch with write access to the repo.
Actual Behavior
Any GitHub account, including the PR author on their own fork PR, can trigger this job. The
if:condition only checkscontains(github.event.comment.body, '/format'), with no check ongithub.event.comment.user.loginorauthor_association.Root Cause
This is the classic "pwn request" anti-pattern: untrusted fork content is checked out and executed inside a job that holds write-scoped secrets.
Suggested Fix
Gate the job on commenter authorization:
Alternatively, replace this with a maintained slash-command dispatcher (e.g.
peter-evans/slash-command-dispatch) that handles authorization correctly.Affected Files
.github/workflows/format-command.yml