GitHub Actions workflow security checker

Paste a workflow file and read what it hands out: the triggers that run with your secrets, the values an outsider can write into your shell, the actions that can change under you. Nothing is uploaded, and the checks run in this tab.

Useful mostly for a file you did not write. A workflow arriving in a pull request, or a third-party action you are about to adopt, is exactly the case where installing a scanner is more work than the question is worth, and where telling a hosted service which repository you are auditing is its own small disclosure.

Findings

Paste a workflow on the left. Results appear as you type.

Why a workflow is a good target

A build pipeline holds the credentials that a running application deliberately does not: the publishing token, the cloud role, the signing key. It also executes code from more places than the application does, because every uses: line is a repository someone else controls.

That is why the two incidents that shaped this list were not application bugs. In March 2025 the tags of tj-actions/changed-files were repointed at code that printed the runner's memory into the build log, and more than 23,000 repositories leaked secrets without changing a line of their own workflows. A year later the same class recurred through a misconfigured pull_request_target, and the stolen credentials were used to backdoor a package on PyPI.

The checks here follow GitHub's own hardening guidance, including its list of the context values an outsider can write.

What this does not do

It reads one file. It does not fetch the actions you call, so it cannot tell you whether the action behind a pinned SHA is well written, only that it will not change under you. It does not know whether your repository is public, which is the condition that turns a self-hosted runner from a preference into an exposure, so that finding states the condition rather than asserting it.

It is also not a replacement for a scanner in your pipeline. zizmor is the standard tool for that and it belongs in CI, where it sees every workflow on every commit. This page is for the minute before that, when the file in front of you is someone else's and you want an answer now.

Questions

Is my workflow sent anywhere?
No. The reader and every check are plain functions running in your browser tab, with no request to any server at any point. That matters here for a reason beyond the file itself: a hosted scanner learns which repository you are auditing and when, which is information about your pipeline that you did not mean to publish. This page cannot learn it, because nothing is transmitted.
What is a pwn request?
It is the combination of a trigger that runs with your secrets and a checkout of code that a stranger wrote. pull_request_target and workflow_run both execute in the context of the base repository, with a writable token and access to secrets, which is what makes them useful for labelling or commenting on a pull request. Add a checkout of the pull request head and the job is now running a contributor's build scripts with those credentials. The fix is to keep the two apart: build untrusted code in a pull_request workflow that holds nothing, and let a second workflow consume only the artifact.
Why pin an action to a commit SHA instead of a version tag?
Because a tag is a pointer and its owner can move it. In March 2025 the maintainer account of tj-actions/changed-files was compromised and every existing tag was repointed at code that dumped the runner process memory into the build log. More than 23,000 repositories leaked secrets, and not one of them had changed a line of their own workflow. A commit SHA cannot be repointed. Keep the readable version in a trailing comment so Dependabot can still raise the bumps.
Does this replace zizmor or a scanner in CI?
No, and it is not trying to. zizmor is the de facto standard for this and it belongs in your pipeline, where it sees every workflow on every commit. This page is for the moment before that: a workflow in a pull request you are reviewing, or a third-party action you are deciding whether to adopt, when installing a tool is more friction than the question deserves. Run both, for different reasons.
What does a clean result actually mean?
That the file declares its token scopes, pins what it runs, and does not put a value an outsider controls where a shell or a JavaScript engine will read it. It says nothing about the actions you call, because their source is not in this file, and nothing about what your secrets protect. A pinned action is a known commit, not a trustworthy one: pinning removes the risk of the code changing under you, not the risk of it being wrong in the first place.

The same reasoning applied to what the pipeline builds is in the Dockerfile checker, and to what it hands out at runtime in the JWT checker. The wider list this sits inside is the security hardening playbook.