Skip to main content
ISSUE-713 High Medium CLI Third-party actions

Action comes from an unauthorized source

Control: Actions must come from authorized sources · Config key: githubActionMustComeFromAuthorizedSources

📋 What is this?

A workflow references a GitHub Action whose source is not authorized. The control checks every step-level uses: owner/repo@ref and every job-level reusable-workflow uses:, and flags any reference that is not trusted by one of:

  • a GitHub-official owner (actions/*, github/*, trusted by default)
  • the same org/user as the scanned repository (trustSameOrgActions, trusted by default)
  • the trustedGithubActions allowlist (exact owner/repo or owner/* wildcard)
  • a minimumStars floor — when set, the action's upstream repository has at least that many stars

⚠️ Impact

Every third-party action runs inside the caller workflow with its GITHUB_TOKEN and secrets, so an unvetted owner is a direct supply-chain entry point — the vector behind the tj-actions/changed-files compromise (CVE-2025-30066). The minimumStars floor additionally catches the rename/re-creation squat, where an attacker re-registers a once-trusted repository name with no history.

🔧 How to fix

Use an action from an authorized source. Keep trustGithubOfficialActions on for actions/* and github/*, add trusted owners or actions to trustedGithubActions (exact owner/repo or owner/*), and optionally set minimumStars to require a popularity threshold. Vendoring the action into a local ./.github/actions/… directory removes the external dependency entirely.

✗ Before Only `actions/checkout` is trusted; the two third-party steps and the reusable-workflow call all come from unauthorized owners.
# .github/workflows/ci.yml — ❌ Actions from unvetted owners
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # official — trusted
- uses: random-dev/handy-action@v1 # unknown owner — flagged
- uses: tj-actions/changed-files@v45 # not on the allowlist — flagged
deploy:
# Job-level reusable workflow from an unauthorized owner — flagged.
uses: acme/shared-workflows/.github/workflows/deploy.yml@main
✓ After Every `uses:` resolves to an official owner, your own org, an allowlist match, or (when enabled) a starred repo.
# .github/workflows/ci.yml — ✅ Only authorized sources
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # official
- uses: mycompany/handy-action@v1 # allowed via mycompany/*
- uses: jdx/mise-action@v2 # allowed by exact entry
# .plumber.yaml — opt in and define the trusted set
github:
controls:
githubActionMustComeFromAuthorizedSources:
enabled: true
trustGithubOfficialActions: true # trust actions/* and github/*
trustSameOrgActions: true # trust your org's own actions
minimumStars: 0 # > 0 to require a popularity floor (API)
trustedGithubActions:
- mycompany/* # whole-org wildcard
- jdx/mise-action # exact owner/repo

💡 Tips

  • Trust is satisfied by ANY of: a GitHub-official owner (actions/*, github/*, on by default), the scanned repo's own org (trustSameOrgActions, on by default), a trustedGithubActions match, or — when minimumStars > 0 — enough stars on the action repo.
  • trustSameOrgActions trusts actions whose owner matches the scanned repository's owner (case-insensitive). It abstains when the repo owner is unknown (e.g. no GitHub remote), so it never grants trust on missing data.
  • trustedGithubActions accepts an exact owner/repo (jdx/mise-action) or an owner/* whole-org wildcard (mycompany/*). Bare owners and arbitrary globs are not supported.
  • Job-level reusable-workflow calls (jobs.<id>.uses) are checked too, but only against the official-owner and allowlist rules — they carry no star metadata.
  • minimumStars reads star counts from the GitHub API and needs gh / GH_TOKEN. Without it, a reference falls back to the allowlist rather than being flagged on missing data.
  • Local actions (uses: ./.github/actions/foo) and docker:// image steps are always exempt.

⚙️ Configuration

This control is configured in .plumber.yaml under the github section:

github:
  controls:
    githubActionMustComeFromAuthorizedSources:
      enabled: true

See the CLI documentation for the full configuration reference.