GitHub Actions
GitHub Actions Security: 5 CI Risks to Fix Right Now
Start with workflow risk that can change code, touch secrets, or run untrusted pull-request input. Those are the CI/CD failures most likely to turn a small workflow mistake into repository compromise.
Key takeaways for GitHub Actions hardening
- Pin third-party actions to a full-length commit SHA because GitHub describes that as the only current way to use an action as an immutable release. [1]
- Declare `GITHUB_TOKEN` permissions explicitly; GitHub sets unspecified permissions to `none` once any permission is listed. [2]
- Treat `pull_request_target` as a sharp tool: GitHub says it runs in the base repository context and warns against building or running pull-request code with that trigger. [3]
- Set job-level `timeout-minutes`; GitHub documents a 360-minute default for jobs without an explicit timeout. [2]
- OpenSSF Scorecard labels Dangerous-Workflow risk as critical and Token-Permissions risk as high, which makes them sensible first-pass audit targets. [4]
Fix CI risks that can write, leak, or execute first
That ordering is practical because a compromised third-party action can affect later jobs, shared files, secrets, and the `GITHUB_TOKEN` that a workflow uses. GitHub’s own secure-use reference says a compromised action can be significant because it may reach repository secrets and use `GITHUB_TOKEN` write access. [1]
The five checks below are intentionally boring. They are the controls a maintainer can inspect in YAML before changing build systems, cloud deploy code, or release automation.
Full-length SHA pins make third-party actions immutable
GitHub’s secure-use reference recommends pinning actions to a full-length commit SHA and says this is currently the only way to use an action as an immutable release. [1]
Tags are convenient, but GitHub also notes that a tag can be moved or deleted if an attacker gains access to the action’s repository. [1] That does not mean every tagged action is malicious; it means a tag leaves more trust in future repository control than a reviewed commit SHA does.
- Check: every external `uses: owner/repo@...` line resolves to a full commit SHA, or the exception is intentional and documented.
- Follow-up: verify the selected SHA belongs to the action’s repository rather than a fork, matching GitHub’s guidance. [1]
Explicit token scopes stop accidental write access
GitHub lets workflows define `GITHUB_TOKEN` access with `read`, `write`, or `none` for available permissions. [2] GitHub also documents `read-all`, `write-all`, and `{}` syntaxes for broad read, broad write, or disabled permissions. [2]
The important rule is easy to miss: once a workflow specifies any permission, permissions that are not specified are set to `none`. [2] That behavior makes a top-level `permissions: contents: read` baseline useful, with job-level write scopes only where a job needs them.
OpenSSF Scorecard gives its highest Token-Permissions score when workflow YAML sets read-only permissions at the top level and declares required write permissions at the run level. [4]
- Check: top-level permissions are read-only or narrower.
- Check: release, Pages, package, issue, or pull-request write scopes appear only on jobs that need those capabilities.
`pull_request_target` should not build untrusted PR code
GitHub documents that `pull_request_target` runs in the context of the default branch of the base repository, not the merge commit used by `pull_request`. [3] The same GitHub section says the event is useful for labeling or commenting on fork pull requests, but says to avoid it when you need to build or run code from the pull request. [3]
GitHub’s warning is direct: running untrusted code on `pull_request_target` can lead to cache poisoning and unintended access to write privileges or secrets. [3] OpenSSF Scorecard’s Dangerous-Workflow check also flags `pull_request_target` or `workflow_run` combined with explicit pull-request checkout because those workflows can have write permission and target-repository secrets. [4]
Untrusted context values should not flow into shell
OpenSSF Scorecard describes script injection with untrusted context variables as a pattern where attacker-controlled strings can be interpreted as code on a runner. [4] Scorecard gives issue titles as an example of a GitHub context value that can be untrusted. [4]
The practical review is simple: search inline `run:` blocks for `${{ github.event.* }}`, branch names, PR titles, issue titles, labels, comments, and file paths. Move those values into environment variables, quote them, or handle them in a script that treats them as data rather than shell syntax.
Short timeouts reduce runaway workflow blast radius
GitHub documents `jobs.<job_id>.timeout-minutes` as the maximum minutes a job can run before GitHub cancels it, and the documented default is 360 minutes. [2] GitHub also documents a 360-minute maximum for step-level `timeout-minutes`. [2]
A six-hour default is rarely the intended budget for lint, test, dependency review, or pull-request automation. Set short job timeouts near the expected runtime, then give long-running release or integration jobs explicit exceptions.
A fast first audit can be mechanical
Start by scanning workflow files for five strings: `uses:`, `permissions:`, `pull_request_target`, `${{ github.event`, and `timeout-minutes`. Those searches map directly to the source-backed risk areas above: immutable action references, token scopes, dangerous pull-request context, script injection, and runaway jobs. [1] [2] [3] [4]
For a local pass, run gha-guard against a repository and use the results as a review queue, not as the final security verdict.
This article is informational and is not a substitute for a security review of your own workflows, repositories, or cloud accounts.
CI Tripwire has not commissioned independent expert review of this article. Read more about the organization byline at contributors and the source posture at sourcing.
Corrections can be routed through the corrections note. Sources: 4 entries, primary project and platform documentation, last reviewed 2026-06-07.
Sources
- GitHub Docs, Secure use reference.
- GitHub Docs, Workflow syntax for GitHub Actions.
- GitHub Docs, Events that trigger workflows.
- OpenSSF Scorecard, checks documentation.