Skip to content

ActionPin

Actions

About

Scan GitHub Actions workflows for unpinned actions, risky permissions, secret-touching install scripts
0.1
Latest
Star (0)

ActionPin

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.

What it checks

  • unpinned-action: external actions not pinned to a full 40-character commit SHA
  • missing-permissions: workflows that rely on repository defaults instead of explicit permissions:
  • write-all-permissions: permissions: write-all
  • privileged-trigger: risky triggers such as workflow_run or pull_request_target paired with write-capable token scopes
  • prod-deploy-permissions: production-like environments plus deploy-capable GITHUB_TOKEN or OIDC scopes
  • secret-touching-install-script: npm install, pip install, curl | bash, and similar bootstraps running near secrets, cloud auth, or production environments
  • agent-privileged-workflow: automation-friendly triggers that can still touch production credentials
  • write-default-permissions: GitHub API enrichment found repository default workflow permissions set to write
  • unprotected-production-environment: GitHub API enrichment found a production-like environment with no reviewers, wait timer, or custom deployment protection

Install

npm install
node ./src/cli.mjs --help

If you publish it to npm later, the same CLI entrypoint works as:

npx actionpin .

Usage

actionpin . --fail-on high
actionpin . --format json
actionpin . --format sarif --output actionpin.sarif
actionpin . --repo owner/repo --github-token "$GITHUB_TOKEN"

Exit codes

  • 0: no findings at or above the configured --fail-on threshold
  • 1: findings met or exceeded the threshold, or CLI validation failed

Output formats

Text

Human-readable summary for local runs and CI logs.

JSON

Full structured report including summary counts, enrichment details, and finding metadata.

SARIF

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.

Config

ActionPin auto-discovers any of these files from the scan root:

  • actionpin.config.json
  • actionpin.config.yaml
  • actionpin.config.yml
  • .actionpinrc
  • .actionpinrc.json
  • .actionpinrc.yaml
  • .actionpinrc.yml

Or load one explicitly:

actionpin . --config ./examples/actionpin.config.yml

Example 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 container

GitHub API enrichment

Pass --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.

Publishability notes

The repository now includes:

  • npm-ready bin entry in package.json
  • files allowlist 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

Development

npm test
node ./src/cli.mjs ./test/fixtures/risky
node ./src/cli.mjs ./test/fixtures/risky --format sarif --output actionpin.sarif

Why this is feasible

This problem is a strong fit for static analysis because the highest-signal evidence lives in workflow YAML:

  • uses: tells us whether action refs are mutable
  • permissions: tells us token blast radius
  • on:, if:, and environment: reveal privileged trigger paths
  • run: and env: 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.

References

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.

About

Scan GitHub Actions workflows for unpinned actions, risky permissions, secret-touching install scripts
0.1
Latest

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.