Untrusted issue, PR or comment text reached a shell in GitHub Actions: find vulnerable workflows, check whether it ran, rotate, fix
For when a campaign like the one Radware reported on Oct 29 (83 items across 61 repos on Sept 1, payload calling 54.205.16.142:8443) touched your repos, or you just want to close the hole. Anyone who can open an issue can try this; it needs no write access, and the item can be closed within minutes and still have run.
Find vulnerable workflows
The bug is a workflow that expands event text inside a run: block.
- Grep .github/workflows across the org for ${{ github.event.issue.title / .body, pull_request.title / .body / .head_ref, comment.body, review.body, discussion.title / .body used inside run:
- Prioritize workflows on issues, issue_comment, pull_request_target, discussion and workflow_run triggers, and any that also use secrets or have write permissions
- Run an Actions linter (zizmor, actionlint) in CI so new cases fail the build
- List AI review or triage bots that read issue and PR text, and note which tokens they hold
Check whether it ran
A payload in an issue proves an attempt; the run log proves execution.
- Search issues, PRs and comments (raw Markdown, including HTML comments) since Sept 1, 2026 for 54.205.16.142, :8443/c/, $(curl and env|base64
- In logs of the matching runs, look for the expanded command line and 'warning: command substitution: ignored null byte in input' on the injected line
- Check runner egress (self-hosted runner firewall or proxy logs) for connections to 54.205.16.142:8443
- Note the triggering account; Radware saw established accounts that were likely compromised
Rotate and review
Assume everything the job could read was sent.
- Rotate every secret available to that job, plus GITHUB_TOKEN-derived access if the job had write permissions (revoke PATs, deploy keys, cloud and registry credentials)
- Review the org audit log after the run for pushes, tag or release changes, new deploy keys, new workflows and changed branch protections
- If releases or packages were published after the run, verify them against a known-good build
Fix and harden
Make event text data, not code.
- Move event values into env: and reference "$VAR" in the script; never eval it
- Set top-level permissions: contents: read and grant more per job only where needed
- Keep secrets out of jobs triggered by issues and comments; split privileged work into a separate workflow that runs on trusted triggers
- Give AI bots that read untrusted text no write tokens or secrets, or isolate them in a job without credentials