Skip to content

[REVIEW] pipeline-security: workflow_run, OIDC trust policy, and cache-poisoning gaps #1113

@tick25108-cpu

Description

@tick25108-cpu

Skill Being Reviewed

Skill name: pipeline-security
Skill path: skills/devsecops/pipeline-security/

False Positive Analysis

Benign configuration that can trigger a false positive:

name: docs-preview
on:
  pull_request:

jobs:
  preview:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build:docs

Why this is a false positive:
The skill says a missing GitHub Actions permissions block is bad because it "defaults to read-write for everything." That can be true in permissive repositories, but it is not safe to infer from workflow YAML alone. GitHub lets orgs/repos configure the default GITHUB_TOKEN permission as read-only or read/write, and the effective permissions also depend on event type and fork settings. A repository with org-level default read-only permissions can have no workflow-level permissions block while still being safe for this job. The skill should report this as Not Evaluable from workflow file alone unless repository Actions settings are available, and it should recommend explicitly declaring permissions: contents: read to make the posture auditable.

Coverage Gaps

Missed variant 1: workflow_run privilege handoff with untrusted artifacts

# Unprivileged PR workflow
name: build-pr
on: pull_request
jobs:
  build:
    steps:
      - uses: actions/checkout@v4
      - run: npm test
      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/

# Privileged follow-up workflow
name: publish-after-build
on:
  workflow_run:
    workflows: [build-pr]
    types: [completed]
permissions:
  contents: write
  packages: write
jobs:
  publish:
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: dist
      - run: npm publish ./dist

Why it should be caught:
The skill focuses heavily on pull_request_target + checkout but does not explicitly check the other common pwn-request shape: an untrusted PR workflow produces artifacts that a privileged workflow_run job later downloads and publishes, deploys, signs, or packages. GitHub's security hardening guidance calls out pull_request_target and workflow_run when combined with checkout or execution of untrusted code. The skill should add a dedicated workflow_run gate: identify the upstream workflow, determine whether it is triggered by untrusted PRs/forks, and block privileged consumption of its artifacts unless signatures, digests, or trusted rebuilds are enforced.

Missed variant 2: OIDC trust-policy overbreadth

permissions:
  contents: read
  id-token: write

steps:
  - uses: aws-actions/configure-aws-credentials@v4
    with:
      role-to-assume: arn:aws:iam::123456789012:role/prod-deploy
      aws-region: us-east-1
{
  "Effect": "Allow",
  "Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" },
  "Action": "sts:AssumeRoleWithWebIdentity",
  "Condition": {
    "StringLike": {
      "token.actions.githubusercontent.com:sub": "repo:org/repo:*"
    }
  }
}

Why it should be caught:
The skill correctly recommends short-lived OIDC tokens, but it does not require checking the cloud-provider trust policy. A workflow can look good in YAML while the AWS/Azure/GCP trust relationship allows any branch, tag, environment, pull request, or reusable workflow in the repo to assume a production role. GitHub's OIDC reference exposes claims such as sub, aud, repository, environment, and job_workflow_ref that should be constrained. The skill should ask for the cloud trust policy or mark OIDC posture as incomplete.

Missed variant 3: reusable workflows and secrets: inherit

jobs:
  deploy:
    uses: external-org/shared-workflows/.github/workflows/deploy.yml@main
    secrets: inherit
    with:
      environment: production

Why it should be caught:
Reusable workflows can become part of the trusted build/deploy boundary, but the discovery patterns only list workflow config files. The skill should inspect workflow_call, uses: owner/repo/.github/workflows/*.yml@ref, secrets: inherit, and the called workflow's pinning status. It should also treat unpinned external reusable workflows as third-party services under CICD-SEC-8, not just normal uses: actions.

Missed variant 4: cache poisoning across trust boundaries

- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: npm-${{ hashFiles('package-lock.json') }}
    restore-keys: npm-

Why it should be caught:
The skill mentions shared caches under SLSA L3, but it does not provide a concrete detection rule for restore-key cache poisoning. A low-privilege PR workflow may populate a broad cache key and a later privileged build may restore it. The skill should check whether cache scope, key material, branch trust, and restore behavior prevent untrusted writers from influencing trusted builds.

Edge Cases

  • Repository settings live outside YAML. Branch protection, GitHub Rulesets, default token permissions, Actions allowlists, environment reviewers, and fork-workflow approvals are often configured through the UI/API or Terraform. Workflow-only review should mark these controls as Not Evaluable, not fail them automatically.
  • Self-hosted runners are not always the same risk. The skill treats self-hosted runners as risky, which is directionally right, but it should distinguish persistent shared runners from ephemeral single-job runners with network egress controls, no sibling repo trust, and image reset after each job.
  • Official mutable tags versus full SHA pinning. SHA pinning is the strongest control, but teams need an update workflow. The remediation should include Dependabot/Renovate support for action SHA updates; otherwise the fix may freeze actions and delay security updates.
  • Matrix-generated deployments. A job matrix can expand a single workflow into production and non-production paths. The skill should evaluate permissions and environment gates per matrix branch, not only at the job name level.

Remediation Quality

  • Fix resolves the vulnerability
  • Fix doesn't introduce new security issues
  • Fix doesn't break functionality
  • Issues found: The skill is strong for common GitHub Actions hazards, especially pull_request_target, broad token permissions, unpinned third-party actions, and missing provenance. The main risk is overconfidence: it can declare a repository below/above a security bar based only on YAML, while several decisive controls live in platform settings or cloud trust policies. It should explicitly separate Config-observable findings from Platform-setting findings and require external evidence before final SLSA/CICD-SEC conclusions.

Comparison to Other Tools

Tool Catches this? Notes
OpenSSF Scorecard Partial Flags dangerous workflow patterns, token permissions, and unpinned dependencies, but does not fully reason about cloud OIDC trust policies.
zizmor Partial Strong GitHub Actions static analysis, including workflow injection and suspicious permissions; still needs cloud-side context for OIDC.
StepSecurity Harden-Runner Partial Provides runtime egress/process visibility and policy enforcement, but it is not a complete CICD-SEC/SLSA assessment framework.
actionlint Partial Catches syntax and some expression issues, but does not assess SLSA level, privilege handoff, or cloud trust relationships.

Overall Assessment

Strengths:
The skill is useful and action-oriented. It covers the CI/CD risks practitioners actually see: pull_request_target, broad GITHUB_TOKEN permissions, weak credential hygiene, third-party Actions, missing SBOM/provenance, and insufficient logging. The output format is clear enough to turn into a review report.

Needs improvement:
The skill should expand beyond single-workflow static checks into trust-boundary analysis across event chains, reusable workflows, caches, artifacts, and cloud OIDC trust policies. It should also avoid false certainty when branch protection, environment gates, token defaults, or Actions policies are only available from repository settings.

Priority recommendations:

  1. Add a workflow_run / artifact handoff check for privileged jobs that consume untrusted PR artifacts, logs, or generated code.
  2. Add an OIDC trust policy checklist requiring sub, aud, repository, environment, and reusable-workflow claims to be constrained in the cloud provider.
  3. Add reusable-workflow discovery: workflow_call, external .github/workflows/*.yml@ref, secrets: inherit, and mutable refs.
  4. Add cache-poisoning detection for broad restore keys and caches shared between untrusted and privileged jobs.
  5. Split conclusions into Observed in YAML, Requires repository settings, and Requires cloud/IAM evidence.

References checked:

Bounty Info

  • I have read and agree to the CONTRIBUTING.md bounty terms
  • Preferred payment method: PayPal (I can provide the payout email privately on acceptance)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions