Coverage area · 2 checks

CI/CD pipeline security for GitHub Actions

Your pipeline holds the keys to production: deploy credentials, registry tokens, signing keys. OpenRouting reviews workflow files for the patterns that let untrusted code or text reach those secrets.

.github/workflows/pr.yml1permissions: write-all2- run: echo "${{3 github.event.issue.title }}"4- uses: org/labeler@mainCI/CDwhat this review answersEvent text expanded into a shell?Token scoped to what the job needs?Third-party actions pinned by SHA?$ verdict REAL ISSUE$ fix pass via env, pin actions by SHA▍

Illustrative example of how a finding in this area is reviewed.

Why this area matters

Build systems are a prime supply-chain target because one compromised pipeline can ship malicious code to every user. The common workflow mistakes are well documented by GitHub's own security guidance: expanding untrusted event text into shell scripts, running fork code with secrets under pull_request_target, granting the job token write access to everything, and referencing third-party actions by a movable tag.

IaC scanners catch some of these, but the risk depends on context — which event triggers the workflow, whether a step checks out untrusted code, and what the token can do. The CI/CD agent reads the whole workflow before deciding.

What goes wrong in real applications

  • Script injection from event data

    Expanding PR titles, branch names or issue bodies directly inside run: steps lets anyone who opens a PR or issue inject shell commands into your build.

  • Secrets exposed to untrusted code

    pull_request_target and similar triggers run with repository secrets; checking out and running the fork's code there hands those secrets to the PR author.

  • Over-scoped job tokens

    permissions: write-all, or no permissions block on older defaults, lets any compromised step push code, create releases or modify settings.

  • Mutable action references

    Third-party actions pinned to a branch or tag run whatever the owner pushes next, including a compromised version.

Sample: the risky pattern and the fix

Risky.github/workflows/pr-triage.yml
on: pull_request_target
permissions: write-all
jobs:
  triage:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.sha }}
      - run: echo "Triaging: ${{ github.event.pull_request.title }}"
      - uses: some-org/label-action@main
Safer.github/workflows/pr-triage.yml
on: pull_request
permissions:
  contents: read
  pull-requests: write
jobs:
  triage:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@<full-commit-sha> # v4
      - env:
          PR_TITLE: ${{ github.event.pull_request.title }}
        run: echo "Triaging: $PR_TITLE"
      - uses: some-org/label-action@<full-commit-sha> # v2.1.0

The original runs a fork's code with full secrets and a write-all token, pastes the PR title into a shell script, and trusts whatever is on the action's main branch. The fix uses the pull_request trigger, scopes the token, passes the title through an environment variable so the shell treats it as data, and pins actions by commit SHA.

Illustrative code, simplified for clarity — not taken from a customer repository.

What OpenRouting checks in your repository

  • GitHub Actions and GitLab CI files: triggers, permissions blocks, checkout refs
  • Event fields expanded inside run: scripts
  • Third-party actions and images referenced by tag or branch instead of SHA or digest
  • Secrets echoed, written to artifacts or passed to untrusted steps
  • Build scripts that download and execute remote code

Scope and limits

  • It reviews pipeline definitions in the repository; it doesn't read your CI provider's run logs, organization settings or stored secrets.
  • Branch protection, required reviewers and environment approvals live in repository settings and aren't checked.

Coverage areas reflect OpenRouting's check library. Code, secret and infrastructure scanning run today; other areas are rolling out. Scanners surface candidates and a review agent decides whether each one is real — it doesn't promise to find every issue.

Review agents for this area

  • CI/CD pipeline — Checks pipelines for leaked secrets, untrusted code execution and over-broad tokens.
  • Supply chain — Checks dependency and build-time trust: pinning, lockfiles, registries and remote code.
  • Secrets & data exposure — Judges whether a flagged value is really a secret and whether sensitive data leaks through logs or errors.

Common questions

Is pull_request_target always a finding?

No. It is safe when the workflow doesn't check out or run the PR's code. The CI/CD agent checks the steps and marks safe uses as likely false positives with the reason.

Does it support GitLab CI?

Yes, .gitlab-ci.yml is reviewed for the same classes: untrusted variables in scripts, protected-variable exposure and unpinned images.