ActionPin
ActionsAbout
Tags
(2)ActionPin is a publishable CLI for hardening GitHub Actions workflows after the Bitwarden CLI supply-chain scare on April 23, 2026. It looks for the workflow patterns that make CI compromise expensive: mutable third-party actions, broad token permissions, install scripts that run near secrets, and bot or agent triggers that can still reach production credentials.
unpinned-action: external actions not pinned to a full 40-character commit SHAmissing-permissions: workflows that rely on repository defaults instead of explicitpermissions:write-all-permissions:permissions: write-allprivileged-trigger: risky triggers such asworkflow_runorpull_request_targetpaired with write-capable token scopesprod-deploy-permissions: production-like environments plus deploy-capableGITHUB_TOKENor OIDC scopessecret-touching-install-script:npm install,pip install,curl | bash, and similar bootstraps running near secrets, cloud auth, or production environmentsagent-privileged-workflow: automation-friendly triggers that can still touch production credentialswrite-default-permissions: GitHub API enrichment found repository default workflow permissions set towriteunprotected-production-environment: GitHub API enrichment found a production-like environment with no reviewers, wait timer, or custom deployment protection
npm install
node ./src/cli.mjs --helpIf you publish it to npm later, the same CLI entrypoint works as:
npx actionpin .actionpin . --fail-on high
actionpin . --format json
actionpin . --format sarif --output actionpin.sarif
actionpin . --repo owner/repo --github-token "$GITHUB_TOKEN"0: no findings at or above the configured--fail-onthreshold1: findings met or exceeded the threshold, or CLI validation failed
Human-readable summary for local runs and CI logs.
Full structured report including summary counts, enrichment details, and finding metadata.
Compatible with GitHub code scanning. Use --format sarif --output actionpin.sarif and upload the file in CI.
An example workflow lives at examples/scan-workflows.yml.
ActionPin auto-discovers any of these files from the scan root:
actionpin.config.jsonactionpin.config.yamlactionpin.config.yml.actionpinrc.actionpinrc.json.actionpinrc.yaml.actionpinrc.yml
Or load one explicitly:
actionpin . --config ./examples/actionpin.config.ymlExample config: examples/actionpin.config.yml
allow:
actions:
- docker/login-action
rules:
missing-permissions: high
ignore:
- ruleId: unpinned-action
file: .github/workflows/legacy-release.yml
step: Publish containerPass --repo owner/repo and optionally --github-token to enrich the static scan with repository settings:
- repository default workflow permissions
- environment protection details for production-like environments
This is the important second phase because static YAML alone cannot tell you whether missing permissions: inherits a write default or whether a production environment has required reviewers.
The repository now includes:
- npm-ready
binentry in package.json filesallowlist for packaging- MIT LICENSE
- composite action.yml wrapper for GitHub Actions users
- stable text, JSON, and SARIF outputs
- config discovery and rule overrides
- local tests covering static rules, config handling, SARIF, and GitHub enrichment
npm test
node ./src/cli.mjs ./test/fixtures/risky
node ./src/cli.mjs ./test/fixtures/risky --format sarif --output actionpin.sarifThis problem is a strong fit for static analysis because the highest-signal evidence lives in workflow YAML:
uses:tells us whether action refs are mutablepermissions:tells us token blast radiuson:,if:, andenvironment:reveal privileged trigger pathsrun:andenv:expose setup commands that execute next to secrets or cloud auth
The GitHub API fills in the gaps that YAML alone cannot prove, especially repository defaults and environment protections.
ActionPin is not certified by GitHub. It is provided by a third-party and is governed by separate terms of service, privacy policy, and support documentation.