Published on May 4, 2026 by Marina Moore, Evan Anderson, and Sherine Khoury, CNCF Technical Advisory Group
CNCF projects featured in this article
Recipe
GitHub Actions CI dependencies
Target audience (the chef)
Project maintainers and developers looking for clear, actionable steps to secure CI dependencies in their GitHub Actions workflows
Scope (ingredients)
Dependencies within GitHub Actions, GitHub Action runner images, selecting CI dependencies, and responding to vulnerabilities in CI dependencies
Out of scope (do not add)
Creating custom actions, other CI tools, other dependency types (code, test, container, etc.), transitive dependencies, SBOMs – provenance
TLDR:
🗹 Source the Best Ingredients: Assess before adopting / Trust the provider: Favor actions from reputable organizations (or GitHub itself)
🗹 Measure precisely: Restrict permissions and access to only what the action requires
🗹 Protect your tools: Pin your dependencies and runner images to specific versions
🗹 Keep it fresh: Set up automatic updates for your dependencies and images
🗹 Choose your kitchen: Weigh the trade-offs between self-hosted runners and GitHub-hosted runners
Utensils: Tools for cooking up a release
As a quick reference, here are the specific tools discussed in this article, along with their key capabilities:
A word of caution in the kitchen
Executing a third-party action is the same as copying its source code and running it within your own permission boundary. A compromised dependency can ruin everything — leaking build secrets, altering your code, or taking over your publishing infrastructure — all without any visible change to the workflow or its original inputs.
Think of it as preparing your favorite dish in a cluttered kitchen with leaky pipes, slick floors, and grimy utensils: trouble is never far away.
The SolarWinds incident remains one of the most notorious examples of supply chain attacks targeting CI dependencies. More recently, the tj-actions/changed-files GitHub Action was also compromised, along with hackerbot-claw exploiting GitHub Actions for tools like Trivy, Datadog, and others.
The Recipe: Step-by-step instructions
Evaluate before using (source your ingredients)
Prioritize actions provided directly by GitHub or those from verified organizations. In the GitHub Marketplace, Actions carrying the “Verified” badge mean GitHub has confirmed the action’s creator as a partner organization.
When selecting actions — especially from unverified sources — look for those with frequent, recent updates and an active community that regularly resolves issues. Adopters, project age, stars, contributors, and forks offer quick ways to compare actions, though these metrics can be gamed. Adopters and project longevity are the most reliable indicators. If badges are displayed, they can signal whether recent builds or tests are passing, along with results from code coverage and static analysis. Testing Actions can be challenging, so visible effort in this area is a strong indicator of sound practices.
Secrets (a note on seasoning): Exercise extra caution when an action requests elevated permissions. Keep in mind that granting access to secrets injects all secrets into the workflow, so only enable this for trusted actions when absolutely necessary. Remember that actions already have access to secrets within the build environment. Is that sufficient? Or excessive? (See Access control below).
Static Analysis (taste testing): Pass your workflow through a static analysis tool such as zizmor:
Install zizmor on your preferred platform or run it as a container image
Execute zizmor against workflows, actions, Dependabot configurations, or all of them:
Offline, targeting a specific tag: zizmor –collect=all myorg/myrepo@v1
Online, pulling remote repositories as needed and running all audits that require internet access: zizmor –gh-token $(gh auth token) myorg/myrepo
Even better, set up continuous monitoring of your repository by integrating zizmorcore/zizmor-action into your GitHub Actions pipeline
For further details, refer to the zizmor documentation.
Enforce API settings (the pantry gatekeeper): To formalize your review process, adjust your GitHub API settings to permit only “organization-only actions” or “explicitly named actions.” When configured at the organization level, these settings override all downstream permissions. This enables a designated group of trusted reviewers to vet every action, though it does add review overhead whenever a new Action is introduced into your pipelines.
Pin your dependencies and runner images (protect your tools)
Unlike mutable tags (e.g., @v1), which can be overwritten by maintainers or attackers, a digest is a unique, immutable identifier tied to a specific version of an action’s code or a container image. When you reference a mutable tag, anyone with upstream permission to modify tags could swap out your ingredients — right in the middle of your build!
Anchoring tools: You can use pinning utilities like frizbee, pin-github-action, ratchet, or pinact (among others) to convert all tag references in your workflow YAML files into digests.
Inspection check: Scorecard or zizmor will flag unpinned dependencies with the pinned dependency check, which covers pinning CI dependencies.
Automatically update your dependencies (keeping it fresh)
Like perishable goods, your actions can deteriorate over time. As with any other code, newly discovered vulnerabilities may impact the actions referenced in your workflows. You need to update your Actions regularly to take advantage of the latest security patches.
The kitchen assistant: To streamline this process, enable Dependabot or Renovate for GitHub Actions. Grouping updates in these automated tools can reduce the maintenance burden, but make sure security updates are prioritized (for this to work, you must enable the Dependency graph and Dependabot alerts in GitHub). These tools also verify that updates originate from the correct upstream repository, ensuring they come from the project’s existing maintainers.
Setting the schedule: As an example, to configure Dependabot to update your CI workflow dependencies:
Place a dependabot.yml file under the .github folder. If Dependabot is already configured for other ecosystems in your repository, you can add to the existing file.
The following configuration will deliver weekly updates as separate pull requests for each action that requires an update.
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every week
interval: "weekly"
These tools can update both pinned Actions and tags, making them a great fit for the earlier recommendations. Below is an example of the type of update Dependabot will automatically generate:
GitHub Actions run within your organization and repositories, so it’s crucial to understand what they can access. Just as you’d carefully monitor who has access to sharp tools in a kitchen, applying the principle of least privilege is a smart approach for CI as well. All Actions have access to a GITHUB_TOKEN, with permissions determined by settings at the repository, organization, and workflow levels. By default, Actions receive the broadest permissions available unless explicitly restricted. The Secure Use for GitHub Actions guide is a great starting point.
Scorecard will flag your project if it doesn’t define (restrict) workflow-level settings through the Token Permissions check.
A few key points:
Be aware of the shared environment: As a reminder, the GitHub token is accessible to most workflows, and earlier workflows can potentially compromise the environment for subsequent ones.
Secure the entry point: Keep in mind that pull_request_target executes workflows in the context of the base repository, granting it read and write access to the GitHub token by default.
Self-hosted runners vs GitHub-hosted runners (pick your setup)
GitHub lets you choose between hosted ephemeral runners (similar to renting a commercial kitchen space) or your own runner infrastructure (like using your own kitchen). If you opt for self-hosted runners, you’re also responsible for keeping the base software image up to date, as well as the Actions used in your workflows. You’ll also need to ensure the self-hosted runner environment remains secure. For a more detailed comparison, check out this resource.