CI/CD Pipeline Security
SkillFiles & storageHarden GitHub Actions, GitLab CI, and similar pipelines against supply-chain attacks, secret exfiltration, and pwn-request abuse. Use when authoring or reviewing workflow files, adding a third-party action, image, or script, wiring cloud or registry credentials into CI, or triaging a suspected pipeline compromise.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the CI/CD Pipeline Security skill
What this skill tells your AI
The instructions your AI receives, as published by shieldnet-360/secure-vibe in skills/cicd-security/SKILL.md and read by ahel’s review.
Rules (for AI agents)
ALWAYS
- Pin every third-party GitHub Action by commit SHA (full 40-char), never by
a floating tag (
@v1,@main,@latest) — tags can be re-pushed. The tj-actions/changed-files March 2025 incident exfiltrated secrets from 23,000+ repositories specifically because consumers used floating tags. Same applies to GitLab CIinclude:references and reusable workflows. Renovate / Dependabot can keep the SHA pins fresh. - Declare
permissions:at the workflow or job level and default tocontents: readonly. Grant additional scopes (id-token: write,packages: write, etc.) job-by-job, never workflow-wide. - Use OIDC (
id-token: write+ cloud provider trust policy) for short-lived cloud credentials. Never store long-lived AWS / GCP / Azure keys as GitHub Secrets. - Treat
pull_request_target,workflow_run, and anypull_requestjob that usesactions/checkoutwithref: ${{ github.event.pull_request.head.ref }}as trusted-context-on-untrusted-code — the "pwn request" pattern documented by GitHub Security Lab. Either don't run them, or run with no secrets and no write tokens. A fork's GitLab merge-request pipeline is the same shape — it runs the fork's own.gitlab-ci.ymlon your runners: isolate them, expose no protected variables. - Echo every untrusted expression (
${{ github.event.* }}) through an environment variable first; never interpolate it directly intorun:body — that's the canonical GitHub Actions script-injection sink. The GitLab sink has the same shape:$CI_*/$TRIGGER_*interpolated intobash -coreval, where merge-request metadata carries the shell metacharacters. - Sign release artifacts (Sigstore / cosign) and publish SLSA provenance attestations. Verify provenance in any consumer pipeline that pulls the artifact.
- Pin
runs-onto a dated runner image (ubuntu-24.04), not a floating label (ubuntu-latest) — the label moves underneath you. On GitLab, use ephemeral Docker-executor runners withprivileged: false; a shared shell runner withprivileged: truegives a compromised job root on the host. An egress firewall on runners handling secrets (StepSecurity Harden-Runner or equivalent) is defense-in-depth on top of that, not a substitute. - Require a human reviewer on a dependency-bump PR when
supply-chain-securityraises a trust-boundary change — a maintainer or ownership change, a new or changed install hook, a registry or source transition, a provenance regression. Gate on that signal, not on the version number: a patch release that changes maintainer warrants more review than a major bump that does not. - Consult
supply-chain-securitybefore any dependency install step (npm install,pip install,docker pull) — in CI it is untrusted code execution on a runner holding your credentials. It owns install-script risk (postinstall,setup.py,build.rs) and registry pinning;container-securitynames the command that fixes the lockfile half (npm ci,--frozen-lockfile) rather than adding flags tonpm install.
NEVER
curl | bash(orwget -O- | sh) any installer script in CI. The 2021 Codecov bash-uploader compromise exfiltrated env vars to an attacker for ~10 weeks because thousands of pipelines ranbash <(curl https://codecov.io/bash). Always download, checksum, then execute.- Echo secrets to logs, even on failure. Use
::add-mask::for any computed-at-runtime secret, and double-check with the GitHub workflow-log search. - Cache mutable state (e.g.
~/.npm,~/.cargo,~/.gradle) keyed only onos. A cache hit cross-job is a cross-tenant attack surface — key on a lockfile hash and scope to the workflow ref. - Trust artifact downloads from arbitrary workflow runs without verifying the source workflow + commit SHA. Build-cache poisoning works through unscoped artifact reuse.
- Store secrets in repository variables (
vars.*) — they are plaintext to anyone with read access. Onlysecrets.*are gated by the secret scanning + scope rules. GitLab's equivalent: a CI/CD variable withoutprotected: true+masked: trueis exposed to every feature-branch pipeline.
KNOWN FALSE POSITIVES
- First-party actions in the same organization that you mirror or fork in-house may legitimately be pinned by tag if the org enforces signed tags + branch-protection on the action repo.
- Public-data pipelines that handle no secrets and produce no signed artifact (e.g. nightly link-checkers) don't need OIDC or SLSA provenance, and may use floating tags without practical impact.
pull_request_targetis legitimate for label / triage bots that only call the GitHub API with the minimal scopes needed, do not check out PR code, and don't expose secrets in env.
Context (for humans)
CI/CD is now the most lucrative single supply-chain target. A pipeline runs trusted code against trusted credentials and trusted registries — compromising it once gives access to every downstream consumer of every artifact it produces. The 2021 Codecov compromise, 2021 SolarWinds incident, 2024 Ultralytics PyPI release-pipeline poisoning, and the 2025 tj-actions/changed-files mass exfiltration all hinged on unauthenticated changes to CI-consumed scripts or actions.
Most of the defenses are mechanical: pin by SHA, minimize permissions, use OIDC, sign artifacts, verify provenance. The hard part is enforcing them across an organization. OpenSSF Scorecard automates checks for the mechanical defenses and integrates with branch protection.
This skill emphasizes the design-pattern weaknesses (pwn requests, script injection, curl-pipe-bash, floating tags, untrusted artifact download) because they are the patterns AI-generated workflow YAML reinvents most often.
References
references/verifying-findings.md— confirm or refute a finding, then lock itchecklists/gitlab_ci_hardening.yaml- OpenSSF Scorecard.
- SLSA v1.0 Build Track.
- GitHub Security Lab — Preventing pwn requests.
- StepSecurity — tj-actions/changed-files attack analysis.
- CWE-1395.
Signals
- GitHub stars
- 22
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
cicd-security- Source
- github.com/shieldnet-360/secure-vibe