WORKFLOW AUDIT · FREE GITHUB ACTION · READ-ONLY

One step that checks your workflows for twelve known risks

Pwn requests, script injection, cache and artifact poisoning, secrets leaking into logs, write-all tokens, fork-reachable self-hosted runners and more. Workflow Audit runs twelve focused checkers over .github/workflows, merges their findings into one severity-ranked report, and writes it to your job summary, with optional Code Scanning alerts.

It reads files in the checkout and makes no network calls of its own. Your workflows are never uploaded.

Add it in four lines

- uses: actions/checkout@v5
  with: { persist-credentials: false }
- uses: Duncan-Haywood/oss-monorepo/ventures/workflow-audit@main
  with: { fail-on: high }

Pin to a commit SHA once you have read the code, as you should for any action. Prefer a CLI? python3 audit.py path/to/repo --format markdown (Python 3.8+, no dependencies).

Upload to Code Scanning

- uses: Duncan-Haywood/oss-monorepo/ventures/workflow-audit@main
  with: { sarif-file: audit.sarif }
- uses: github/codeql-action/upload-sarif@v3
  with: { sarif_file: audit.sarif }

What it checks

SeverityRisk
HighPwn-request checkout; script injection from untrusted github.event.*; secrets transformed past log masking; artifacts executed or caches written on untrusted triggers; self-hosted runners reachable from forks; secrets: inherit on untrusted triggers
Mediumpermissions: write-all; checkout credentials left in .git/config; unmasked env exports; unscoped artifact downloads and cache restore keys; third-party actions pinned to a mutable tag or branch instead of a commit SHA; secrets: inherit into external workflows
LowMissing permissions; jobs with no timeout-minutes; actions on end-of-life runtimes; first-party actions and Docker images not pinned

Each check is also a standalone free tool in this portfolio, with a paste-in-browser page and a write-up.

Alternatives, honestly

zizmor is a broader, more mature analyser and the right pick for deep coverage; OpenSSF Scorecard scores whole-repository posture; hosted platforms add dashboards and enforcement at a price. Workflow Audit is the small option: nothing to install, nothing to configure, nothing leaves the runner. Running it next to the others costs one step.

FAQ

What does Workflow Audit check?

Twelve documented patterns: pwn-request checkouts and script injection, secret leaks into logs, artifact and cache poisoning, self-hosted runners reachable from forks, secrets: inherit on untrusted triggers, write-all or missing permissions, checkout credentials persisted in .git/config, deprecated action runtimes, jobs with no timeout-minutes, action references not pinned to a commit SHA, and deploy jobs with no concurrency group (an older commit can finish last and go live).

How is this different from zizmor?

zizmor is a broader, more mature static analyser and is the better choice for deep coverage. Workflow Audit is a smaller, dependency-free option that runs as a one-step Action with no install, ranks findings by severity, and writes the job summary and SARIF for you. Running both is reasonable.

What if my repo already has findings and I do not want CI to fail on day one?

Run audit.py --write-baseline to record today's findings, commit the file, and pass it as the baseline input. Only new findings are reported or fail the step, and entries match on the offending line's text so line shifts do not resurrect them. A single finding can also be silenced with a # workflow-audit: ignore[rule] comment.

Does it send my workflows anywhere?

No. It reads files in the checkout on the runner and makes no network calls of its own.

Does a clean report mean my workflows are secure?

No. It matches twelve specific patterns line by line. It is not a security audit and cannot see what a called action or reusable workflow does.

What does it cost?

Nothing. It is MIT-licensed open source; sponsoring is optional.