Pwn-request detection
pull_request_target / workflow_run jobs that check out untrusted PR code.
npm package · MIT · Node ≥ 18
Catch insecure GitHub Actions workflows before they're merged.
Reads your .github/workflows/*.yml and action.yml files and flags the patterns behind most real-world Actions compromises: mutable action tags, over-privileged tokens, pull_request_target "pwn requests", script injection, leaked secrets and more. --fix pins your actions to commit SHAs for you.
npm i -D workflow-sentinel
$ npx workflow-sentinelworkflow-sentinel — 3 file(s) scanned .github/workflows/ci.yml 1 MEDIUM No top-level `permissions:`; job "test" runs with the default GITHUB_TOKEN scopes [missing-permissions] ↳ fix: Add `permissions: { contents: read }` at the top level and widen per job only where needed. 9 HIGH actions/checkout@v4 is pinned to "v4" (mutable tag), not a commit SHA [unpinned-action] ↳ fix: Pin it: `uses: actions/checkout@<40-char-sha> # v4` (or run `workflow-sentinel --fix`). 9 MEDIUM actions/checkout@v4 without `persist-credentials: false` in job "test" [persist-credentials] ↳ fix: Add to the step: `with: { persist-credentials: false }`...9 high, 5 medium✖ Failing (fail-on: high).
A workflow file is code that runs with your repository's tokens and secrets. One mutable action tag, one pull_request_target that checks out the PR head, or one ${{ github.event.issue.title }} in a run: step is enough for an attacker.
workflow-sentinel lints every workflow and composite action in the PR, with file and line numbers and a concrete fix, and can pin every action to a SHA automatically.
pull_request_target / workflow_run jobs that check out untrusted PR code.
Untrusted event fields pasted into run: or actions/github-script.
Flags tag- and branch-pinned actions; --fix rewrites them to commit SHAs with Dependabot-compatible comments.
write-all, missing permissions blocks and persisted checkout credentials.
Secrets in jobs that run PR code, echoed secrets and secrets: inherit.
Tainted cache keys and risky artifact upload / download patterns.
Mistyped contexts, unavailable properties, unknown keys and likely input typos.
Per-rule severities, expiring allow entries and # workflow-sentinel-ignore comments.
# Scan the current repo
npx workflow-sentinel# One file, stricter gate
npx workflow-sentinel .github/workflows/release.yml --fail-on medium# Trust first-party owners
npx workflow-sentinel --trusted-owner actions --trusted-owner github# Pin every action to a SHA
GH_TOKEN=... npx workflow-sentinel --fixname: Workflow security
on: [push, pull_request]
permissions:
contents: read
security-events: write
jobs:
workflow-sentinel:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with: { persist-credentials: false }
- uses: MrLouisWright/workflow-sentinel@v1
with:
fail-on: high
sarif: workflow-sentinel.sarif
- if: always()
uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: workflow-sentinel.sarif }
| Flag | Description |
|---|---|
[paths…] | Files or directories to scan (default: .github/workflows plus every action.yml) |
--fail-on <sev> | critical, high (default), medium, low, info or none |
--config <file> | Config file path |
--trusted-owner <o> | Allow tags for an owner (actions) or a repo (github/codeql-action). Repeatable |
--fix / --fix-dry-run | Resolve each tag or branch to its commit SHA via the GitHub API and rewrite uses: |
--json [file], --sarif <file>, --markdown <file> | Reports |
--no-fixes, --no-color | Text output tweaks |
Full reference, config file format and API in the README.
Support this project
I build free, open-source tools that help developers ship safer websites. Every coffee helps keep them maintained, documented and free for everyone.
Buy me a coffee (opens Stripe in a new tab)Secure checkout by Stripe