Skip to content

Secure Supply Chain Consumption Framework

Microsoft / OpenSSF Secure Supply Chain Consumption Framework. Ingest, inventory, scan, rebuild, fix, the consumer-side controls for taking a third-party dependency safely.

At a glance

  • Controls in this standard: 11
  • Controls evidenced by at least one check: 11 / 11
  • Distinct checks evidencing this standard: 134
  • Of those, autofixable with --fix: 33

How to read severity

Every check below ships at a fixed severity level. The scale is the same across providers and standards so a CRITICAL finding in one place means the same thing as a CRITICAL finding anywhere else.

Level What it means Examples
CRITICAL Active exploit primitive in the workflow as written. Treat as P0: a default scan path lands an attacker on a secret, an RCE, or production write access without further effort. Hardcoded credential literal, branch ref pointing at a known-compromised action, signed-into-an-unverified registry.
HIGH Production-impact gap that requires modest attacker effort or a second condition to weaponize. Remediate this sprint; the secondary condition is usually already present in real pipelines. Action pinned to a floating tag, sensitive permissions on a low-popularity action, mutable container tag in prod.
MEDIUM Significant defense-in-depth gap. Not directly exploitable on its own but disables a control whose absence widens the blast radius of a separate compromise. Backlog with a deadline. Missing branch protection, container without resource limits, freshly-published dependency consumed before the cooldown window.
LOW Hygiene / hardening issue. Not a vulnerability on its own but raises baseline posture and reduces audit friction. Missing CI logging retention, SBOM without supplier attribution, ECR repo without scan-on-push.
INFO Degraded-mode signal. The scanner couldn't reach an API or parse a config and surfaces the gap so the operator knows coverage was incomplete. No finding against the workload itself. CB-000 CodeBuild API access failed, IAM-000 IAM enumeration failed.

Coverage by control

Click a control ID to jump to the per-control section with the full check list. The severity mix column shows the spread of evidencing checks by severity (Critical / High / Medium / Low / Info).

Control Title Checks Severity mix
ING-1 L1: Use package managers trusted by your organization 24 15H · 8M · 1L
ING-3 L1: Have the capability to deny-list specific vulnerable / malicious OSS 1 1H
SCA-1 L1: Scan OSS for known vulnerabilities 12 1H · 11M
SCA-3 L2: Scan OSS for malware 7 7C
UPD-1 L1: Update vulnerable OSS manually (pin + track versions) 38 23H · 10M · 5L
UPD-2 L3: Enable automated OSS updates (Dependabot / Renovate) 6 6M
ENF-1 L2: Enforce security policy of OSS usage (block on violation) 13 3H · 10M
ENF-2 L2: Break the build when a violation is detected 4 1H · 3M
REB-2 L4: Digitally sign rebuilt / produced OSS artifacts 16 2H · 14M
REB-3 L4: Generate SBOMs for artifacts produced 11 1H · 9M · 1L
REB-4 L4: Digitally sign SBOMs produced (attested provenance) 9 9M

Filter at runtime

Restrict a scan to checks that evidence this standard with --standard s2c2f:

# All providers, only checks tied to this standard
pipeline_check --standard s2c2f

# Compose with --pipeline to scope by provider
pipeline_check --pipeline github --standard s2c2f

# Compose with another standard to widen the lens
pipeline_check --pipeline aws --standard s2c2f --standard owasp_cicd_top_10

Controls in scope

ING-1: L1: Use package managers trusted by your organization

Evidenced by 24 checks across 12 providers (AWS, Argo Workflows, Azure DevOps, Bitbucket, Buildkite, CircleCI, Dockerfile, GitHub Actions, GitLab CI, Helm, Jenkins, Tekton).

Check Title Severity Provider Fix
ADO-018 Package install from insecure source HIGH Azure DevOps 🔧 fix
ADO-028 Package install bypasses registry integrity (git / path / tarball source) MEDIUM Azure DevOps
ARGO-008 Argo script source pipes remote install or disables TLS HIGH Argo Workflows 🔧 fix
BB-014 Package install from insecure source HIGH Bitbucket 🔧 fix
BB-027 Package install bypasses registry integrity (git / path / tarball source) MEDIUM Bitbucket
BK-004 Remote script piped into shell interpreter HIGH Buildkite 🔧 fix
BK-008 TLS verification disabled in step command MEDIUM Buildkite 🔧 fix
CA-002 CodeArtifact repository has a public external connection HIGH AWS
CC-018 Package install from insecure source HIGH CircleCI 🔧 fix
CC-028 Package install bypasses registry integrity (git / path / tarball source) MEDIUM CircleCI
DF-001 FROM image not pinned to sha256 digest HIGH Dockerfile 🔧 fix
DF-003 ADD pulls remote URL without integrity verification HIGH Dockerfile
DF-004 RUN executes a remote script via curl-pipe / wget-pipe HIGH Dockerfile
ECR-006 ECR pull-through cache rule uses an untrusted upstream HIGH AWS
GHA-018 Package install from insecure source HIGH GitHub Actions 🔧 fix
GHA-029 Package install bypasses registry integrity (git / path / tarball source) MEDIUM GitHub Actions
GL-018 Package install from insecure source HIGH GitLab CI 🔧 fix
GL-027 Package install bypasses registry integrity (git / path / tarball source) MEDIUM GitLab CI
HELM-001 Chart.yaml declares legacy apiVersion: v1 MEDIUM Helm 🔧 fix
HELM-003 Chart dependency declared on a non-HTTPS repository HIGH Helm 🔧 fix
HELM-009 Chart home / sources URL uses a non-HTTPS scheme LOW Helm
JF-018 Package install from insecure source HIGH Jenkins 🔧 fix
JF-031 Package install bypasses registry integrity (git / path / tarball source) MEDIUM Jenkins
TKN-008 Tekton step script pipes remote install or disables TLS HIGH Tekton 🔧 fix

ING-3: L1: Have the capability to deny-list specific vulnerable / malicious OSS

Evidenced by 1 check across AWS.

Check Title Severity Provider Fix
CA-002 CodeArtifact repository has a public external connection HIGH AWS

SCA-1: L1: Scan OSS for known vulnerabilities

Evidenced by 12 checks across 11 providers (AWS, Argo Workflows, Azure DevOps, Bitbucket, Buildkite, CircleCI, Cloud Build, GitHub Actions, GitLab CI, Jenkins, Tekton).

Check Title Severity Provider Fix
ADO-020 No vulnerability scanning step MEDIUM Azure DevOps
ARGO-012 No vulnerability scanning step MEDIUM Argo Workflows
BB-015 No vulnerability scanning step MEDIUM Bitbucket
BK-012 No vulnerability scanning step MEDIUM Buildkite
CC-020 No vulnerability scanning step MEDIUM CircleCI
ECR-001 Image scanning on push not enabled HIGH AWS
ECR-007 Inspector v2 enhanced scanning disabled for ECR MEDIUM AWS
GCB-008 No vulnerability scanning step in Cloud Build pipeline MEDIUM Cloud Build
GHA-020 No vulnerability scanning step MEDIUM GitHub Actions
GL-019 No vulnerability scanning step MEDIUM GitLab CI
JF-020 No vulnerability scanning step MEDIUM Jenkins
TKN-012 No vulnerability scanning step MEDIUM Tekton

SCA-3: L2: Scan OSS for malware

Evidenced by 7 checks across 7 providers (AWS, Azure DevOps, Bitbucket, CircleCI, GitHub Actions, GitLab CI, Jenkins).

Check Title Severity Provider Fix
ADO-026 Pipeline contains indicators of malicious activity CRITICAL Azure DevOps
BB-025 Pipeline contains indicators of malicious activity CRITICAL Bitbucket
CB-011 CodeBuild buildspec contains indicators of malicious activity CRITICAL AWS
CC-026 Config contains indicators of malicious activity CRITICAL CircleCI
GHA-027 Workflow contains indicators of malicious activity CRITICAL GitHub Actions
GL-025 Pipeline contains indicators of malicious activity CRITICAL GitLab CI
JF-029 Jenkinsfile contains indicators of malicious activity CRITICAL Jenkins

UPD-1: L1: Update vulnerable OSS manually (pin + track versions)

Evidenced by 38 checks across 13 providers (AWS, Argo Workflows, Azure DevOps, Bitbucket, Buildkite, CircleCI, Cloud Build, Dockerfile, GitHub Actions, GitLab CI, Helm, Jenkins, Tekton).

Check Title Severity Provider Fix
ADO-001 Task reference not pinned to specific version HIGH Azure DevOps 🔧 fix
ADO-005 Container image not pinned to specific version HIGH Azure DevOps
ADO-009 Container image pinned by tag rather than sha256 digest LOW Azure DevOps
ADO-021 Package install without lockfile enforcement MEDIUM Azure DevOps 🔧 fix
ADO-025 Cross-repo template not pinned to commit SHA HIGH Azure DevOps
ARGO-001 Argo template container image not pinned to a digest HIGH Argo Workflows
BB-001 pipe: action not pinned to exact version HIGH Bitbucket 🔧 fix
BB-009 pipe: pinned by version rather than sha256 digest LOW Bitbucket
BB-021 Package install without lockfile enforcement MEDIUM Bitbucket 🔧 fix
BK-001 Buildkite plugin not pinned to an exact version HIGH Buildkite
CB-005 Outdated managed build image MEDIUM AWS
CB-009 CodeBuild image not pinned by digest MEDIUM AWS
CC-001 Orb not pinned to exact semver HIGH CircleCI 🔧 fix
CC-003 Docker image not pinned by digest HIGH CircleCI
CC-021 Package install without lockfile enforcement MEDIUM CircleCI 🔧 fix
CC-029 Machine executor image not pinned HIGH CircleCI
DF-001 FROM image not pinned to sha256 digest HIGH Dockerfile 🔧 fix
DF-003 ADD pulls remote URL without integrity verification HIGH Dockerfile
DF-010 apt-get dist-upgrade / upgrade pulls unknown package versions LOW Dockerfile
DF-011 Package manager install without cache cleanup in same layer LOW Dockerfile
ECR-002 Image tags are mutable HIGH AWS
GCB-001 Cloud Build step image not pinned by digest HIGH Cloud Build 🔧 fix
GHA-001 Action not pinned to commit SHA HIGH GitHub Actions 🔧 fix
GHA-021 Package install without lockfile enforcement MEDIUM GitHub Actions 🔧 fix
GHA-025 Reusable workflow not pinned to commit SHA HIGH GitHub Actions
GL-001 Image not pinned to specific version or digest HIGH GitLab CI 🔧 fix
GL-005 include: pulls remote / project without pinned ref HIGH GitLab CI
GL-009 Image pinned to version tag rather than sha256 digest LOW GitLab CI
GL-021 Package install without lockfile enforcement MEDIUM GitLab CI 🔧 fix
GL-028 services: image not pinned HIGH GitLab CI
GL-030 trigger: include: pulls child pipeline without pinned ref HIGH GitLab CI
HELM-002 Chart.lock missing per-dependency digests HIGH Helm 🔧 fix
HELM-004 Chart dependency version is a range, not an exact pin MEDIUM Helm
HELM-008 Chart.lock generated more than 90 days ago MEDIUM Helm
JF-001 Shared library not pinned to a tag or commit HIGH Jenkins
JF-009 Agent docker image not pinned to sha256 digest HIGH Jenkins
JF-021 Package install without lockfile enforcement MEDIUM Jenkins 🔧 fix
TKN-001 Tekton step image not pinned to a digest HIGH Tekton

UPD-2: L3: Enable automated OSS updates (Dependabot / Renovate)

Evidenced by 6 checks across 6 providers (Azure DevOps, Bitbucket, CircleCI, GitHub Actions, GitLab CI, Jenkins).

Check Title Severity Provider Fix
ADO-022 Dependency update command bypasses lockfile pins MEDIUM Azure DevOps 🔧 fix
BB-022 Dependency update command bypasses lockfile pins MEDIUM Bitbucket 🔧 fix
CC-022 Dependency update command bypasses lockfile pins MEDIUM CircleCI 🔧 fix
GHA-022 Dependency update command bypasses lockfile pins MEDIUM GitHub Actions 🔧 fix
GL-022 Dependency update command bypasses lockfile pins MEDIUM GitLab CI 🔧 fix
JF-022 Dependency update command bypasses lockfile pins MEDIUM Jenkins 🔧 fix

ENF-1: L2: Enforce security policy of OSS usage (block on violation)

Evidenced by 13 checks across 8 providers (AWS, Azure DevOps, Bitbucket, Buildkite, CircleCI, GitHub Actions, GitLab CI, Jenkins).

Check Title Severity Provider Fix
ADO-004 Deployment job missing environment binding MEDIUM Azure DevOps
BB-004 Deploy step missing deployment: environment gate MEDIUM Bitbucket
BK-007 Deploy step not gated by a manual block / input MEDIUM Buildkite
BK-013 Deploy step has no branches: filter MEDIUM Buildkite
CB-008 CodeBuild buildspec is inline (not sourced from a protected repo) HIGH AWS
CC-009 Deploy job missing manual approval gate MEDIUM CircleCI
CD-002 AllAtOnce deployment config, no canary or rolling strategy HIGH AWS
CP-001 No approval action before deploy stages HIGH AWS
CP-005 Production Deploy stage has no preceding ManualApproval MEDIUM AWS
GHA-014 Deploy job missing environment binding MEDIUM GitHub Actions 🔧 fix
GL-004 Deploy job lacks manual approval or environment gate MEDIUM GitLab CI
JF-005 Deploy stage missing manual input approval MEDIUM Jenkins
JF-024 input approval step missing submitter restriction MEDIUM Jenkins

ENF-2: L2: Break the build when a violation is detected

Evidenced by 4 checks across 2 providers (AWS, GitLab CI).

Check Title Severity Provider Fix
CP-001 No approval action before deploy stages HIGH AWS
CP-005 Production Deploy stage has no preceding ManualApproval MEDIUM AWS
GL-004 Deploy job lacks manual approval or environment gate MEDIUM GitLab CI
GL-029 Manual deploy job defaults to allow_failure: true MEDIUM GitLab CI

REB-2: L4: Digitally sign rebuilt / produced OSS artifacts

Evidenced by 16 checks across 11 providers (AWS, Argo Workflows, Azure DevOps, Bitbucket, Buildkite, CircleCI, Cloud Build, GitHub Actions, GitLab CI, Jenkins, Tekton).

Check Title Severity Provider Fix
ADO-006 Artifacts not signed MEDIUM Azure DevOps
ARGO-009 Artifacts not signed (no cosign/sigstore step) MEDIUM Argo Workflows
BB-006 Artifacts not signed MEDIUM Bitbucket
BK-009 Artifacts not signed (no cosign/sigstore step) MEDIUM Buildkite
CA-001 CodeArtifact domain not encrypted with customer KMS CMK MEDIUM AWS
CC-006 Artifacts not signed (no cosign/sigstore step) MEDIUM CircleCI
CP-002 Artifact store not encrypted with customer-managed KMS key MEDIUM AWS
ECR-005 Repository encrypted with AES256 rather than KMS CMK MEDIUM AWS
GCB-009 Artifacts not signed (no cosign / sigstore step) MEDIUM Cloud Build
GHA-006 Artifacts not signed (no cosign/sigstore step) MEDIUM GitHub Actions
GL-006 Artifacts not signed MEDIUM GitLab CI
JF-006 Artifacts not signed MEDIUM Jenkins
LMB-001 Lambda function has no code-signing config HIGH AWS
SIGN-001 No AWS Signer profile defined for Lambda deploys MEDIUM AWS
SIGN-002 AWS Signer profile is revoked or inactive HIGH AWS
TKN-009 Artifacts not signed (no cosign/sigstore step) MEDIUM Tekton

REB-3: L4: Generate SBOMs for artifacts produced

Evidenced by 11 checks across 11 providers (Argo Workflows, Azure DevOps, Bitbucket, Buildkite, CircleCI, Dockerfile, GitHub Actions, GitLab CI, Helm, Jenkins, Tekton).

Check Title Severity Provider Fix
ADO-007 SBOM not produced MEDIUM Azure DevOps
ARGO-010 No SBOM generated for build artifacts MEDIUM Argo Workflows
BB-007 SBOM not produced MEDIUM Bitbucket
BK-010 No SBOM generated for build artifacts MEDIUM Buildkite
CC-007 SBOM not produced (no CycloneDX/syft/Trivy-SBOM step) MEDIUM CircleCI
DF-016 Image lacks OCI provenance labels LOW Dockerfile
GHA-007 SBOM not produced (no CycloneDX/syft/Trivy-SBOM step) MEDIUM GitHub Actions
GL-007 SBOM not produced MEDIUM GitLab CI
HELM-002 Chart.lock missing per-dependency digests HIGH Helm 🔧 fix
JF-007 SBOM not produced MEDIUM Jenkins
TKN-010 No SBOM generated for build artifacts MEDIUM Tekton

REB-4: L4: Digitally sign SBOMs produced (attested provenance)

Evidenced by 9 checks across 9 providers (Argo Workflows, Azure DevOps, Bitbucket, Buildkite, CircleCI, GitHub Actions, GitLab CI, Jenkins, Tekton).

Check Title Severity Provider Fix
ADO-024 No SLSA provenance attestation produced MEDIUM Azure DevOps
ARGO-011 No SLSA provenance attestation produced MEDIUM Argo Workflows
BB-024 No SLSA provenance attestation produced MEDIUM Bitbucket
BK-011 No SLSA provenance attestation produced MEDIUM Buildkite
CC-024 No SLSA provenance attestation produced MEDIUM CircleCI
GHA-024 No SLSA provenance attestation produced MEDIUM GitHub Actions
GL-024 No SLSA provenance attestation produced MEDIUM GitLab CI
JF-028 No SLSA provenance attestation produced MEDIUM Jenkins
TKN-011 No SLSA provenance attestation produced MEDIUM Tekton

Check details

Every check that evidences this standard, rendered once with its detection mechanism, recommendation, and any known false-positive modes or real-world incident references. The per-control tables above link to the matching block here.

ADO-001: Task reference not pinned to specific version HIGH 🔧 fix

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Floating-major task references (@1, @2) can roll forward silently when the task publisher ships a breaking or malicious update. Pass when every task: reference carries a two- or three-segment semver.

Recommendation. Reference tasks by a full semver (DownloadSecureFile@1.2.3) or extension-published-version. Track task updates explicitly via Azure DevOps extension settings rather than letting @1 drift.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: ADO-001 in the Azure DevOps provider.

ADO-004: Deployment job missing environment binding MEDIUM

Evidences: ENF-1 L2: Enforce security policy of OSS usage (block on violation).

How this is detected. Without an environment: binding, ADO cannot enforce approvals, checks, or deployment history against a named resource. Every deployment: job should bind one.

Recommendation. Add environment: <name> to every deployment: job. Configure approvals, required branches, and business-hours checks on the matching Environment in the ADO UI.

Source: ADO-004 in the Azure DevOps provider.

ADO-005: Container image not pinned to specific version HIGH

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Container images can be declared at resources.containers[].image or job.container (string or {image:}). Floating / untagged refs let the publisher swap the image contents.

Recommendation. Reference images by @sha256:<digest> or at minimum a full immutable version tag. Avoid :latest and untagged refs.

Source: ADO-005 in the Azure DevOps provider.

ADO-006: Artifacts not signed MEDIUM

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. Passes when cosign / sigstore / slsa-* / notation-sign appears anywhere in the pipeline text.

Recommendation. Add a task that runs cosign sign or notation sign, Azure Pipelines' workload identity federation enables keyless signing. Publish the signature to the artifact feed and verify it at deploy time.

Source: ADO-006 in the Azure DevOps provider.

ADO-007: SBOM not produced MEDIUM

Evidences: REB-3 L4: Generate SBOMs for artifacts produced.

How this is detected. Without an SBOM, downstream consumers can't audit the dependency set shipped in the artifact.

Recommendation. Add an SBOM step, microsoft/sbom-tool, syft . -o cyclonedx-json, or anchore/sbom-action. Publish the SBOM as a pipeline artifact so downstream consumers can ingest it.

Source: ADO-007 in the Azure DevOps provider.

ADO-009: Container image pinned by tag rather than sha256 digest LOW

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. ADO-005 fails floating tags at HIGH; ADO-009 is the stricter tier. Even immutable-looking version tags can be repointed by registry operators.

Recommendation. Resolve each image to its current digest and replace the tag with @sha256:<digest>. Schedule regular digest bumps via Renovate or a scheduled pipeline.

Source: ADO-009 in the Azure DevOps provider.

ADO-018: Package install from insecure source HIGH 🔧 fix

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Detects package-manager invocations that use plain HTTP registries (--index-url http://, --registry=http://) or disable TLS verification (--trusted-host, --no-verify) in a pipeline. These patterns allow man-in-the-middle injection of malicious packages.

Recommendation. Use HTTPS registry URLs. Remove --trusted-host and --no-verify flags. Pin to a private registry with TLS.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: ADO-018 in the Azure DevOps provider.

ADO-020: No vulnerability scanning step MEDIUM

Evidences: SCA-1 L1: Scan OSS for known vulnerabilities.

How this is detected. Without a vulnerability scanning step, known-vulnerable dependencies ship to production undetected. The check recognises trivy, grype, snyk, npm audit, yarn audit, safety check, pip-audit, osv-scanner, and govulncheck.

Recommendation. Add a vulnerability scanning step, trivy, grype, snyk test, npm audit, pip-audit, or osv-scanner. Publish results so vulnerabilities surface before deployment.

Source: ADO-020 in the Azure DevOps provider.

ADO-021: Package install without lockfile enforcement MEDIUM 🔧 fix

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Detects package-manager install commands that do not enforce a lockfile or hash verification. Without lockfile enforcement the resolver pulls whatever version is currently latest, exactly the window a supply-chain attacker exploits.

Recommendation. Use lockfile-enforcing install commands: npm ci instead of npm install, pip install --require-hashes -r requirements.txt, yarn install --frozen-lockfile, bundle install --frozen, and go install tool@v1.2.3.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: ADO-021 in the Azure DevOps provider.

ADO-022: Dependency update command bypasses lockfile pins MEDIUM 🔧 fix

Evidences: UPD-2 L3: Enable automated OSS updates (Dependabot / Renovate).

How this is detected. Detects pip install --upgrade, npm update, yarn upgrade, bundle update, cargo update, go get -u, and composer update. These commands bypass lockfile pins and pull whatever version is currently latest. Tooling upgrades (pip install --upgrade pip) are exempted.

Recommendation. Remove dependency-update commands from CI. Use lockfile-pinned install commands (npm ci, pip install -r requirements.txt) and update dependencies via a dedicated PR pipeline (e.g. Dependabot, Renovate).

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Known false positives.

  • Common build-tool bootstrapping idioms (pip install --upgrade pip, pip install --upgrade setuptools wheel virtualenv) and security-tool installs (pip install --upgrade pip-audit / cyclonedx-bom / semgrep) are exempted by the DEP_UPDATE_RE tooling allowlist. Other tooling-upgrade idioms not yet on the list can still trip the rule. Defaults to MEDIUM confidence so CI gates can require --min-confidence HIGH to ignore.

Source: ADO-022 in the Azure DevOps provider.

ADO-024: No SLSA provenance attestation produced MEDIUM

Evidences: REB-4 L4: Digitally sign SBOMs produced (attested provenance).

How this is detected. On Azure Pipelines the common pattern is a Bash@3 task invoking cosign attest --yes --predicate=provenance.json $(image). The native Microsoft SBOM tool emits _manifest/spdx_2.2/manifest.spdx.json for SBOM but does not produce provenance on its own.

Recommendation. Add a task that runs cosign attest against a provenance.intoto.jsonl statement, or Microsoft's sbom-tool in attestation mode. ADO-006 covers signing; this rule covers the in-toto statement SLSA Build L3 additionally requires.

Source: ADO-024 in the Azure DevOps provider.

ADO-025: Cross-repo template not pinned to commit SHA HIGH

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Azure Pipelines resolves template: build.yml@tools against the tools repo resource's ref: field. When that ref is refs/heads/main (or missing, which defaults to the pipeline's default branch), a push to the callee repo changes what your pipeline runs on the next invocation.

Recommendation. On every resources.repositories entry referenced from a template: ...@repo-alias directive, set ref: refs/tags/<sha> or the bare 40-char commit SHA, never a branch or floating tag. A moved branch/tag swaps the template body without changing your pipeline file.

Source: ADO-025 in the Azure DevOps provider.

ADO-026: Pipeline contains indicators of malicious activity CRITICAL

Evidences: SCA-3 L2: Scan OSS for malware.

How this is detected. ADO pipelines can run arbitrary shell via bash / script / powershell tasks. This rule scans every string value for known-bad patterns (reverse shells, base64-decoded execution, miner binaries, exfil channels). Orthogonal to ADO-016/ADO-017/ADO-023.

Recommendation. Treat as a potential compromise. Identify the PR/branch that added the matching task(s), rotate any Service Connections the pipeline can reach, and audit Pipeline run logs for outbound traffic to the matched hosts.

Known false positives.

  • Security-training repositories, CTF challenges, and red-team exercise pipelines legitimately contain reverse-shell strings or exfil domains as literals. Matches inside YAML keys / HCL attributes whose names contain example, fixture, sample, demo, or test are auto-suppressed; bare lines in a production pipeline still fire.
  • Defaults to LOW confidence. Filter with --min-confidence MEDIUM to ignore all matches; the rule still surfaces the hit for teams that want to spot-check.

Source: ADO-026 in the Azure DevOps provider.

ADO-028: Package install bypasses registry integrity (git / path / tarball source) MEDIUM

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Complements ADO-021 (missing lockfile flag). Git URL installs without a commit pin, local-path installs, and direct tarball URLs bypass the registry integrity controls the lockfile relies on.

Recommendation. Pin git dependencies to a commit SHA. Publish private packages to an internal registry (Azure Artifacts) instead of installing from a filesystem path or tarball URL.

Source: ADO-028 in the Azure DevOps provider.

ARGO-001: Argo template container image not pinned to a digest HIGH

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Walks spec.templates[].container, spec.templates[].script, and spec.templates[].containerSet.containers[]. The image must contain @sha256: followed by a 64-char hex digest.

Recommendation. Pin every container / script template image to a content-addressable digest (alpine@sha256:<digest>). Tag-only references (alpine:3.18) and rolling tags (alpine:latest) let a compromised registry update redirect the workflow's containers at the next pull, with no audit trail in the WorkflowTemplate.

Source: ARGO-001 in the Argo Workflows provider.

ARGO-008: Argo script source pipes remote install or disables TLS HIGH 🔧 fix

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Walks script.source and joined container.args text with the cross-provider CURL_PIPE_RE and TLS_BYPASS_RE regexes.

Recommendation. Replace curl ... | sh with a download-then-verify-then-execute pattern. Drop TLS-bypass flags (curl -k, git config http.sslverify false); install the missing CA into the template image instead. Both forms let an attacker controlling DNS / a transparent proxy substitute the script the workflow runs.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: ARGO-008 in the Argo Workflows provider.

ARGO-009: Artifacts not signed (no cosign/sigstore step) MEDIUM

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. Detection mirrors GHA-006 / TKN-009 / BK-009, the shared signing-token catalog (cosign, sigstore, slsa-github-generator, slsa-framework, notation-sign) is searched across every string in each Argo document. Fires only on artifact-producing Workflows / WorkflowTemplates (those that invoke docker build / docker push / kaniko / helm upgrade / aws s3 sync / etc.) so lint-only Workflows don't trip it.

Recommendation. Add a cosign step to the Workflow. The most common shape is a final sign template that runs cosign sign --yes <repo>@sha256:<digest> after the build. Sign by digest, not tag, so a re-pushed tag can't bypass the signature.

Source: ARGO-009 in the Argo Workflows provider.

ARGO-010: No SBOM generated for build artifacts MEDIUM

Evidences: REB-3 L4: Generate SBOMs for artifacts produced.

How this is detected. An SBOM (CycloneDX or SPDX) records every component baked into the build. Without one, post-incident triage can't answer did this CVE ship? for a given artifact. Detection uses the shared SBOM-token catalog: syft, cyclonedx, cdxgen, spdx-tools, microsoft/sbom-tool. Fires only on artifact-producing Workflows.

Recommendation. Add an SBOM-generation template. syft <artifact> -o cyclonedx-json > /tmp/sbom.json runs in any standard container; cyclonedx-cli and cdxgen are alternative producers. Persist the SBOM as an output artifact so downstream templates and consumers can read it.

Source: ARGO-010 in the Argo Workflows provider.

ARGO-011: No SLSA provenance attestation produced MEDIUM

Evidences: REB-4 L4: Digitally sign SBOMs produced (attested provenance).

How this is detected. Provenance generation is distinct from signing. A signed artifact proves who published it; a provenance attestation proves where / how it was built. Detection uses the shared provenance-token catalog (slsa-framework, cosign attest, in-toto, witness run, attest-build-provenance).

Recommendation. Add a cosign attest --predicate slsa.json --type slsaprovenance <ref> step after the build template, or use witness run to record the build environment. Publish the attestation alongside the artifact so consumers can verify how it was built, not just who signed it.

Source: ARGO-011 in the Argo Workflows provider.

ARGO-012: No vulnerability scanning step MEDIUM

Evidences: SCA-1 L1: Scan OSS for known vulnerabilities.

How this is detected. Vulnerability scanning sits at a different layer from signing and SBOM. It answers does this artifact ship a known CVE? rather than can we verify what it is?. Detection uses the shared vuln-scan-token catalog: trivy, grype, snyk, npm-audit, pip-audit, osv-scanner, govulncheck, anchore, codeql-action, semgrep, bandit, checkov, tfsec. Walks every Argo document and passes if any document includes a scanner reference.

Recommendation. Add a vulnerability scanner template. trivy fs /workdir for source / filesystem; trivy image <ref> for container images. grype, snyk, npm audit, pip-audit are alternatives. Fail the template on findings above a chosen severity so a regression blocks the merge instead of shipping.

Source: ARGO-012 in the Argo Workflows provider.

BB-001: pipe: action not pinned to exact version HIGH 🔧 fix

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Bitbucket pipes are docker-image references. Major-only (:1) or missing tags let Atlassian/the publisher swap the image contents. Full semver or sha256 digest is required.

Recommendation. Pin every pipe: to a full semver tag (e.g. atlassian/aws-s3-deploy:1.4.0) or to an immutable SHA. Floating majors like :1 can roll to new code silently.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: BB-001 in the Bitbucket provider.

BB-004: Deploy step missing deployment: environment gate MEDIUM

Evidences: ENF-1 L2: Enforce security policy of OSS usage (block on violation).

How this is detected. A step whose name or invoked pipe matches deploy / release / publish / promote should declare a deployment: field so Bitbucket enforces deployment-scoped variables, approvals, and history.

Recommendation. Add deployment: production (or staging / test) to the step. Configure the matching environment in the repo's Deployments settings with required reviewers and secured variables.

Source: BB-004 in the Bitbucket provider.

BB-006: Artifacts not signed MEDIUM

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. Unsigned artifacts can't be verified downstream. Passes when cosign / sigstore / slsa-* / notation-sign appears in the pipeline body.

Recommendation. Add a step that runs cosign sign against the built image or archive, using Bitbucket OIDC for keyless signing where possible. Publish the signature next to the artifact and verify it at deploy time.

Source: BB-006 in the Bitbucket provider.

BB-007: SBOM not produced MEDIUM

Evidences: REB-3 L4: Generate SBOMs for artifacts produced.

How this is detected. Without an SBOM, downstream consumers can't audit the dependency set shipped in the artifact. Passes when CycloneDX / syft / anchore / sbom-tool / Trivy-SBOM appears.

Recommendation. Add an SBOM step, syft . -o cyclonedx-json, Trivy with --format cyclonedx, or Microsoft's sbom-tool. Attach the SBOM as a build artifact.

Source: BB-007 in the Bitbucket provider.

BB-009: pipe: pinned by version rather than sha256 digest LOW

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. BB-001 fails floating tags at HIGH; BB-009 is the stricter tier. Even immutable-looking semver tags can be repointed by the registry; sha256 digests are tamper-evident.

Recommendation. Resolve each pipe to its digest (docker buildx imagetools inspect bitbucketpipelines/<name>:<ver>) and reference it via @sha256:<digest>.

Source: BB-009 in the Bitbucket provider.

BB-014: Package install from insecure source HIGH 🔧 fix

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Detects package-manager invocations that use plain HTTP registries (--index-url http://, --registry=http://) or disable TLS verification (--trusted-host, --no-verify) in a pipeline. These patterns allow man-in-the-middle injection of malicious packages.

Recommendation. Use HTTPS registry URLs. Remove --trusted-host and --no-verify flags. Pin to a private registry with TLS.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: BB-014 in the Bitbucket provider.

BB-015: No vulnerability scanning step MEDIUM

Evidences: SCA-1 L1: Scan OSS for known vulnerabilities.

How this is detected. Without a vulnerability scanning step, known-vulnerable dependencies ship to production undetected. The check recognises trivy, grype, snyk, npm audit, yarn audit, safety check, pip-audit, osv-scanner, and govulncheck.

Recommendation. Add a vulnerability scanning step, trivy, grype, snyk test, npm audit, pip-audit, or osv-scanner. Publish results so vulnerabilities surface before deployment.

Source: BB-015 in the Bitbucket provider.

BB-021: Package install without lockfile enforcement MEDIUM 🔧 fix

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Detects package-manager install commands that do not enforce a lockfile or hash verification. Without lockfile enforcement the resolver pulls whatever version is currently latest, exactly the window a supply-chain attacker exploits.

Recommendation. Use lockfile-enforcing install commands: npm ci instead of npm install, pip install --require-hashes -r requirements.txt, yarn install --frozen-lockfile, bundle install --frozen, and go install tool@v1.2.3.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: BB-021 in the Bitbucket provider.

BB-022: Dependency update command bypasses lockfile pins MEDIUM 🔧 fix

Evidences: UPD-2 L3: Enable automated OSS updates (Dependabot / Renovate).

How this is detected. Detects pip install --upgrade, npm update, yarn upgrade, bundle update, cargo update, go get -u, and composer update. These commands bypass lockfile pins and pull whatever version is currently latest. Tooling upgrades (pip install --upgrade pip) are exempted.

Recommendation. Remove dependency-update commands from CI. Use lockfile-pinned install commands (npm ci, pip install -r requirements.txt) and update dependencies via a dedicated PR pipeline (e.g. Dependabot, Renovate).

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Known false positives.

  • Common build-tool bootstrapping idioms (pip install --upgrade pip, pip install --upgrade setuptools wheel virtualenv) and security-tool installs (pip install --upgrade pip-audit / cyclonedx-bom / semgrep) are exempted by the DEP_UPDATE_RE tooling allowlist. Other tooling-upgrade idioms not yet on the list can still trip the rule. Defaults to MEDIUM confidence so CI gates can require --min-confidence HIGH to ignore.

Source: BB-022 in the Bitbucket provider.

BB-024: No SLSA provenance attestation produced MEDIUM

Evidences: REB-4 L4: Digitally sign SBOMs produced (attested provenance).

How this is detected. Bitbucket has no native SLSA builder; self-hosted attestation via cosign attest or witness run is the usual path. Pipes like atlassian/cosign-attest (if published) would also match.

Recommendation. Add a step that runs cosign attest against a provenance.intoto.jsonl statement, or integrate the TestifySec witness run attestor. Artifact signing alone (BB-006) doesn't satisfy SLSA Build L3.

Source: BB-024 in the Bitbucket provider.

BB-025: Pipeline contains indicators of malicious activity CRITICAL

Evidences: SCA-3 L2: Scan OSS for malware.

How this is detected. Specific indicators only (reverse shells, base64-decoded execution, miner binaries, Discord/Telegram webhooks, credential-dump pipes, audit-erasure commands). Does not replace BB-014 (TLS bypass) or BB-013 (Docker insecure), those are hygiene; this is evidence.

Recommendation. Treat as a potential compromise. Identify the PR that added the matching step(s), rotate any credentials referenced from the pipeline's variable groups, and audit recent builds.

Known false positives.

  • Security-training repositories, CTF challenges, and red-team exercise pipelines legitimately contain reverse-shell strings or exfil domains as literals. Matches inside YAML keys / HCL attributes whose names contain example, fixture, sample, demo, or test are auto-suppressed; bare lines in a production pipeline still fire.
  • Defaults to LOW confidence. Filter with --min-confidence MEDIUM to ignore all matches; the rule still surfaces the hit for teams that want to spot-check.

Source: BB-025 in the Bitbucket provider.

BB-027: Package install bypasses registry integrity (git / path / tarball source) MEDIUM

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Complements BB-021 (missing lockfile flag). Git URL installs without a commit pin, local-path installs, and direct tarball URLs bypass the registry integrity controls the lockfile relies on.

Recommendation. Pin git dependencies to a commit SHA. Publish private packages to an internal registry instead of installing from a filesystem path or tarball URL.

Source: BB-027 in the Bitbucket provider.

BK-001: Buildkite plugin not pinned to an exact version HIGH

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Buildkite resolves plugin refs at agent boot. foo#v1.2.3 locks the version; foo#main / foo does not. Detection fires on bare names, branch keywords, and partial-semver pins (v4, v4.13).

Recommendation. Pin every plugin reference to an exact tag (docker-compose#v4.13.0) or a 40-char commit SHA. Bare references (docker-compose), branch refs (#main / #master), and major-only floats (#v4) resolve to whatever is current at agent start time, which lets a compromised plugin release execute inside the pipeline.

Source: BK-001 in the Buildkite provider.

BK-004: Remote script piped into shell interpreter HIGH 🔧 fix

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. The detection fires on curl|bash, curl|sh, wget|bash, iex (iwr ...), and the corresponding Invoke-WebRequest|Invoke-Expression PowerShell forms. Use curl -fsSLO <url>; sha256sum -c install.sh.sha256; bash install.sh instead.

Recommendation. Download the installer to disk, verify a checksum or signature, then execute it. curl ... | sh lets the remote host change what runs in your pipeline at any time, and any TLS / DNS error during download silently feeds a partial script to the shell.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: BK-004 in the Buildkite provider.

BK-007: Deploy step not gated by a manual block / input MEDIUM

Evidences: ENF-1 L2: Enforce security policy of OSS usage (block on violation).

How this is detected. A step is treated as a deploy when its label, key, or any command line contains a deploy keyword (deploy, ship, release, promote, apply, rollout, terraform apply, kubectl apply, helm upgrade, aws ecs update-service). The check passes when at least one preceding step in the same pipeline file is a block: or input: flow-control step.

Recommendation. Insert a - block: "Deploy?" (or - input: step) in front of every deploy step. Buildkite waits for a human to click Unblock before the gated steps run, which prevents an unreviewed merge from auto-deploying to production. Combine with branches: main so the gate only appears on release branches.

Known false positives.

  • Pipelines where the deploy gate lives in a triggered pipeline rather than the local file, the local pipeline looks ungated even though the actual deploy is gated downstream. Add a no-op block: to silence.

Source: BK-007 in the Buildkite provider.

BK-008: TLS verification disabled in step command MEDIUM 🔧 fix

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Detection fires on the canonical bypass flags across curl, wget, git, npm, pip, gcloud, and openssl. The check is deliberately conservative, partial-word matches (--insecure-protocols) are excluded.

Recommendation. Drop curl -k / --insecure, wget --no-check-certificate, git -c http.sslVerify=false, and pip install --trusted-host. If a CA isn't trusted, install it into the agent's trust store (update-ca-certificates) rather than disabling validation pipeline-wide. A compromised intermediate that strips TLS gets a free hand with every fetch the step performs.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: BK-008 in the Buildkite provider.

BK-009: Artifacts not signed (no cosign/sigstore step) MEDIUM

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. Unsigned artifacts can't be verified downstream, a tampered build is indistinguishable from a legitimate one. The check recognises cosign, sigstore, slsa-github-generator, slsa-framework, and notation-sign as signing tools, matching the shared signing-token catalog used by the other CI packs.

Recommendation. Add a signing step, install cosign once (brew install cosign in the agent image, or a cosign-install plugin) and call cosign sign --yes <ref> after the build. For container images pushed to ECR / GCR / GHCR, the same call signs by digest. Publish the signature alongside the artifact and verify it at consumption time.

Source: BK-009 in the Buildkite provider.

BK-010: No SBOM generated for build artifacts MEDIUM

Evidences: REB-3 L4: Generate SBOMs for artifacts produced.

How this is detected. An SBOM (CycloneDX or SPDX) records every component baked into the build. Without one, post-incident triage can't answer did this CVE ship? for a given artifact. Detection uses the shared SBOM-token catalog, syft, cyclonedx, cdxgen, spdx-tools, microsoft/sbom-tool.

Recommendation. Add an SBOM-generation step. syft <artifact> -o cyclonedx-json > sbom.json runs in any standard agent image; cyclonedx-cli and cdxgen are alternative producers. Upload the SBOM via buildkite-agent artifact upload so downstream consumers (and incident-response tooling) can match deployed artifacts to the components they were built from.

Source: BK-010 in the Buildkite provider.

BK-011: No SLSA provenance attestation produced MEDIUM

Evidences: REB-4 L4: Digitally sign SBOMs produced (attested provenance).

How this is detected. Provenance generation is distinct from signing. A signed artifact proves who published it; a provenance attestation proves where / how it was built. Without it, a leaked signing key forges identity but a leaked build environment also forges provenance. You need both for the SLSA L3 non-falsifiability guarantee. Detection uses the shared provenance-token catalog (slsa-framework, cosign attest, in-toto, attest-build-provenance).

Recommendation. Run cosign attest --predicate slsa.json (or the SLSA-framework generator from a build-time step) after the build completes. The predicate records the build inputs and the agent that produced the artifact. Publish the attestation alongside the artifact so consumers can verify how it was built, not just who signed it.

Source: BK-011 in the Buildkite provider.

BK-012: No vulnerability scanning step MEDIUM

Evidences: SCA-1 L1: Scan OSS for known vulnerabilities.

How this is detected. Vulnerability scanning sits at a different layer from signing and SBOM. It answers does this artifact ship a known CVE? rather than can we verify what it is?. Detection uses the shared vuln-scan-token catalog: trivy, grype, snyk, npm-audit, pip-audit, anchore, dependency-check, checkov, semgrep.

Recommendation. Add a vulnerability scanner, trivy fs . for source / filesystem, trivy image <ref> for container images, grype and snyk for either. Add npm audit / pip-audit for language-specific dep audits. Fail the step on findings above a chosen severity so a regression blocks the merge instead of shipping.

Source: BK-012 in the Buildkite provider.

BK-013: Deploy step has no branches: filter MEDIUM

Evidences: ENF-1 L2: Enforce security policy of OSS usage (block on violation).

How this is detected. A step is treated as a deploy when its label, key, or any command line contains a deploy keyword (deploy, ship-it, release, promote, rollout, helm upgrade, kubectl apply, terraform apply, aws ecs update-service, aws lambda update-function-code, gcloud run deploy). The check passes when the step declares branches: with at least one literal branch name (a wildcard like "*" is treated as an explicit opt-out, not a passing filter, and still trips). The pipeline-level default also counts, top-level steps: with branches: propagates.

Recommendation. Add branches: "main release/*" (or your release branch glob) to every deploy step. Buildkite skips the step on any other branch, which prevents a feature-branch PR from accidentally promoting code to production. Combine with BK-007's manual block: so a release branch plus a human approval is the path to deploy.

Known false positives.

  • Trunk-based teams that branch-protect main and treat every merge as a deploy candidate may not use branches:. Add branches: main to make the policy explicit, or ignore BK-013 in .pipeline-check-ignore.yml with a scope of main-only repos.

Source: BK-013 in the Buildkite provider.

CA-001: CodeArtifact domain not encrypted with customer KMS CMK MEDIUM

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. AWS-owned encryption (the default alias/aws/codeartifact key) keeps the key policy under AWS's control, not yours. That's fine for confidentiality but means cross-account auditability of every Decrypt event lives with AWS, and you can't revoke or scope key access without recreating the domain. A customer-managed CMK puts both controls back in your hands.

Recommendation. Recreate the CodeArtifact domain with an encryption-key argument pointing at a customer-managed CMK. Domain encryption is set at creation and cannot be changed after.

Source: CA-001 in the AWS provider.

CA-002: CodeArtifact repository has a public external connection HIGH

Evidences: ING-1 L1: Use package managers trusted by your organization, ING-3 L1: Have the capability to deny-list specific vulnerable / malicious OSS.

How this is detected. An external connection to public:npmjs / public:pypi / public:nuget / public:maven-central fetches packages from the public registry on first resolution. A typo-squat (request vs requests) or a compromised upstream lands in the cache the first time anyone names it; every subsequent build pulls the cached substitute. The pull-through cache with an allow-list is the same risk shape solved by an explicit allowlist.

Recommendation. Route public package consumption through a pull-through cache repository governed by an allow-list of package names, and point build-time repos at that cache rather than directly at public:npmjs/public:pypi. Unscoped public upstreams expose builds to dependency-confusion and typosquatting attacks.

Source: CA-002 in the AWS provider.

CB-005: Outdated managed build image MEDIUM

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Only AWS-managed aws/codebuild/standard:N.0 images are version-checked. Custom or third-party images pass here, CB-009 handles the separate concern of tag vs digest pinning for custom images.

Recommendation. Update the CodeBuild environment image to aws/codebuild/standard:7.0 or later to ensure the build environment receives the latest security patches.

Known false positives.

  • One version behind the current aws/codebuild/standard is a hygiene warning, not a production issue, and defaults to MEDIUM confidence. The rule emits HIGH only when the project is two or more versions behind. Custom or third-party images are not version-checked here; CB-009 handles tag-vs-digest pinning for those.

Source: CB-005 in the AWS provider.

CB-008: CodeBuild buildspec is inline (not sourced from a protected repo) HIGH

Evidences: ENF-1 L2: Enforce security policy of OSS usage (block on violation).

How this is detected. An inline buildspec (source.buildspec set to YAML text, or a S3 URL) bypasses the protections that cover your source code. A user with codebuild:UpdateProject can rewrite the build commands without touching the repository, no PR review, no branch protection, no audit of what changed. Store buildspec.yml in the repo instead.

Recommendation. Remove the inline buildspec and store buildspec.yml in the source repository under branch protection. Anyone with codebuild:UpdateProject can silently rewrite an inline buildspec; repository-sourced buildspecs inherit the repo's review and protection controls.

Source: CB-008 in the AWS provider.

CB-009: CodeBuild image not pinned by digest MEDIUM

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. CodeBuild pulls the environment image on every build. A tag pointer can be moved by whoever controls the registry; a digest cannot. AWS-managed aws/codebuild/... images are exempt. Those are covered by CB-005 and are not part of the tag-mutation threat model.

Recommendation. Pin custom CodeBuild images by @sha256:<digest>. Tag-based references (:latest, :1.2.3) can be silently overwritten to point at a malicious layer that is pulled on the next build.

Source: CB-009 in the AWS provider.

CB-011: CodeBuild buildspec contains indicators of malicious activity CRITICAL

Evidences: SCA-3 L2: Scan OSS for malware.

How this is detected. Scans the source.buildspec text on every CodeBuild project for concrete attack indicators: reverse shells, base64-decoded execution, miner binaries/pools, Discord/Telegram webhooks, credential-dump pipes, audit-erasure commands. CB-011 is CRITICAL by design, a true positive is evidence of compromise, not a hygiene improvement. Repo-sourced buildspecs (not inlined) return NOT APPLICABLE because the text isn't visible to the scanner; CB-008 already flags the inline form as a governance gap.

Recommendation. Treat as a potential compromise. Identify which principal or pipeline ran the CodeBuild project recently, rotate its service role's credentials, audit CloudTrail for outbound activity to the matched hosts, and, if an inline buildspec is in use (CB-008), enforce repo-sourced buildspecs under branch protection so the next malicious edit requires a PR.

Known false positives.

  • Security-training repositories, CTF challenges, and red-team exercise pipelines legitimately contain reverse-shell strings or exfil domains as literals. Matches inside YAML keys / HCL attributes whose names contain example, fixture, sample, demo, or test are auto-suppressed; bare lines in a production pipeline still fire.
  • Defaults to LOW confidence. Filter with --min-confidence MEDIUM to ignore all matches; the rule still surfaces the hit for teams that want to spot-check.

Source: CB-011 in the AWS provider.

CC-001: Orb not pinned to exact semver HIGH 🔧 fix

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Orb references in the orbs: block must include an @x.y.z suffix to lock a specific version. References without @, with @volatile, or with only a major (@1) or major.minor (@5.1) version float and can silently pull in malicious updates.

Recommendation. Pin every orb to an exact semver version (circleci/node@5.1.0). Floating references like @volatile, @1, or bare names without @ resolve to whatever is latest at build time, allowing a compromised orb update to execute in the pipeline.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: CC-001 in the CircleCI provider.

CC-003: Docker image not pinned by digest HIGH

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Docker images referenced in docker: blocks under jobs or executors must include an @sha256:... digest suffix. Tag-only references (:latest, :18) are mutable and can be replaced at any time by whoever controls the upstream registry.

Recommendation. Pin every Docker image to its sha256 digest: cimg/node:18@sha256:abc123.... Tags like :latest or :18 are mutable, a registry compromise or upstream push silently replaces the image content.

Source: CC-003 in the CircleCI provider.

CC-006: Artifacts not signed (no cosign/sigstore step) MEDIUM

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. Unsigned artifacts cannot be verified downstream, so a tampered build is indistinguishable from a legitimate one. The check recognises cosign, sigstore, slsa-framework, and notation-sign as signing tools.

Recommendation. Add a signing step to the pipeline, e.g. install cosign and run cosign sign, or use the sigstore CLI. Publish the signature alongside the artifact and verify it at consumption time.

Source: CC-006 in the CircleCI provider.

CC-007: SBOM not produced (no CycloneDX/syft/Trivy-SBOM step) MEDIUM

Evidences: REB-3 L4: Generate SBOMs for artifacts produced.

How this is detected. Without an SBOM, downstream consumers cannot audit the exact set of dependencies shipped in the artifact, delaying vulnerability response when a transitive dep is disclosed. The check recognises CycloneDX, syft, Anchore SBOM action, spdx-sbom-generator, Microsoft sbom-tool, and Trivy in SBOM mode.

Recommendation. Add an SBOM generation step, syft . -o cyclonedx-json, Trivy with --format cyclonedx, or Microsoft's sbom-tool. Attach the SBOM to the build artifacts so consumers can ingest it into their vulnerability management pipeline.

Source: CC-007 in the CircleCI provider.

CC-009: Deploy job missing manual approval gate MEDIUM

Evidences: ENF-1 L2: Enforce security policy of OSS usage (block on violation).

How this is detected. In CircleCI, manual approval is implemented by adding a job with type: approval to the workflow and making the deploy job require it. Without this gate, any push to the triggering branch deploys immediately with no human review.

Recommendation. Add a type: approval job that precedes the deploy job in the workflow, and list it in the deploy job's requires:. This ensures a human must click Approve in the CircleCI UI before production changes roll out.

Source: CC-009 in the CircleCI provider.

CC-018: Package install from insecure source HIGH 🔧 fix

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Detects package-manager invocations that use plain HTTP registries (--index-url http://, --registry=http://) or disable TLS verification (--trusted-host, --no-verify) in a CircleCI config. These patterns allow man-in-the-middle injection of malicious packages.

Recommendation. Use HTTPS registry URLs. Remove --trusted-host and --no-verify flags. Pin to a private registry with TLS.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: CC-018 in the CircleCI provider.

CC-020: No vulnerability scanning step MEDIUM

Evidences: SCA-1 L1: Scan OSS for known vulnerabilities.

How this is detected. Without a vulnerability scanning step, known-vulnerable dependencies ship to production undetected. The check recognises trivy, grype, snyk, npm audit, yarn audit, safety check, pip-audit, osv-scanner, and govulncheck.

Recommendation. Add a vulnerability scanning step, trivy, grype, snyk test, npm audit, pip-audit, or osv-scanner. Publish results so vulnerabilities surface before deployment.

Source: CC-020 in the CircleCI provider.

CC-021: Package install without lockfile enforcement MEDIUM 🔧 fix

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Detects package-manager install commands that do not enforce a lockfile or hash verification. Without lockfile enforcement the resolver pulls whatever version is currently latest, exactly the window a supply-chain attacker exploits.

Recommendation. Use lockfile-enforcing install commands: npm ci instead of npm install, pip install --require-hashes -r requirements.txt, yarn install --frozen-lockfile, bundle install --frozen, and go install tool@v1.2.3.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: CC-021 in the CircleCI provider.

CC-022: Dependency update command bypasses lockfile pins MEDIUM 🔧 fix

Evidences: UPD-2 L3: Enable automated OSS updates (Dependabot / Renovate).

How this is detected. Detects pip install --upgrade, npm update, yarn upgrade, bundle update, cargo update, go get -u, and composer update. These commands bypass lockfile pins and pull whatever version is currently latest. Tooling upgrades (pip install --upgrade pip) are exempted.

Recommendation. Remove dependency-update commands from CI. Use lockfile-pinned install commands (npm ci, pip install -r requirements.txt) and update dependencies via a dedicated PR workflow (e.g. Dependabot, Renovate).

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Known false positives.

  • Common build-tool bootstrapping idioms (pip install --upgrade pip, pip install --upgrade setuptools wheel virtualenv) and security-tool installs (pip install --upgrade pip-audit / cyclonedx-bom / semgrep) are exempted by the DEP_UPDATE_RE tooling allowlist. Other tooling-upgrade idioms not yet on the list can still trip the rule. Defaults to MEDIUM confidence so CI gates can require --min-confidence HIGH to ignore.

Source: CC-022 in the CircleCI provider.

CC-024: No SLSA provenance attestation produced MEDIUM

Evidences: REB-4 L4: Digitally sign SBOMs produced (attested provenance).

How this is detected. Signing (cosign sign) binds identity to bytes; attestation (cosign attest) binds a structured claim about how the artifact was built. SLSA verifiers check the latter so consumers can enforce builder/source/parameter policies.

Recommendation. Add a run: cosign attest command against a provenance.intoto.jsonl statement, or use the circleci/attestation orb. CC-006 covers signing; this rule covers the build-provenance step SLSA Build L3 requires.

Source: CC-024 in the CircleCI provider.

CC-026: Config contains indicators of malicious activity CRITICAL

Evidences: SCA-3 L2: Scan OSS for malware.

How this is detected. Fires on concrete indicators only (reverse shells, base64-decoded execution, miner binaries, Discord/Telegram webhooks, webhook.site callbacks, credential-dump pipes, history-erasure).

Recommendation. Treat as a potential compromise. Identify the PR that added the matching step(s), rotate any contexts/env vars the pipeline can reach, and audit recent CircleCI runs for outbound traffic to the matched hosts.

Known false positives.

  • Security-training repositories, CTF challenges, and red-team exercise pipelines legitimately contain reverse-shell strings or exfil domains as literals. Matches inside YAML keys / HCL attributes whose names contain example, fixture, sample, demo, or test are auto-suppressed; bare lines in a production pipeline still fire.
  • Defaults to LOW confidence. Filter with --min-confidence MEDIUM to ignore all matches; the rule still surfaces the hit for teams that want to spot-check.

Source: CC-026 in the CircleCI provider.

CC-028: Package install bypasses registry integrity (git / path / tarball source) MEDIUM

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Complements CC-021 (missing lockfile flag). Git URL installs without a commit pin, local-path installs, and direct tarball URLs bypass the registry integrity controls the lockfile relies on.

Recommendation. Pin git dependencies to a commit SHA. Publish private packages to an internal registry instead of installing from a filesystem path or tarball URL.

Source: CC-028 in the CircleCI provider.

CC-029: Machine executor image not pinned HIGH

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. CC-003 covers Docker images declared under docker: blocks. It does not reach the machine executor, where the image is on machine.image. A rolling tag (current, edge, default) pulls a fresh image whenever CircleCI publishes one, reintroducing the same supply-chain risk Docker-image pinning is designed to eliminate.

Recommendation. Pin every machine.image to a dated release tag, ubuntu-2204:2024.05.1 rather than :current, :edge, :default, or a bare image name. CircleCI rotates the current / edge aliases on its own cadence, so builds re-run on an image the author never reviewed.

Source: CC-029 in the CircleCI provider.

CD-002: AllAtOnce deployment config, no canary or rolling strategy HIGH

Evidences: ENF-1 L2: Enforce security policy of OSS usage (block on violation).

How this is detected. AllAtOnce shifts 100% of traffic to the new revision in one step. There's no gradient to halt on if a CloudWatch alarm trips mid-rollout, the bad revision is already serving every request. Canary / linear configs introduce the shift-then-watch shape that lets monitors catch a regression before it's universal.

Recommendation. Switch to a canary or linear deployment configuration (e.g. CodeDeployDefault.LambdaCanary10Percent5Minutes or a custom rolling config) so that defects are caught before they affect all instances or traffic.

Source: CD-002 in the AWS provider.

CP-001: No approval action before deploy stages HIGH

Evidences: ENF-1 L2: Enforce security policy of OSS usage (block on violation), ENF-2 L2: Break the build when a violation is detected.

How this is detected. A pipeline that goes Source -> Build -> Deploy with no Approval action means every commit on the source branch ships, with no human ack between code-merged and code-running-in-prod. The Manual approval action is the intentional pause point, combine with CP-005 for production-tagged stages specifically.

Recommendation. Add a Manual approval action to a stage that precedes every Deploy stage that targets a production or sensitive environment.

Source: CP-001 in the AWS provider.

CP-002: Artifact store not encrypted with customer-managed KMS key MEDIUM

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. The pipeline's S3 artifact store holds intermediate build outputs handed between stages. Default SSE-S3 (AES256) encrypts at rest but uses an AWS-owned key whose policy you can't scope. A customer-managed CMK gives the same key-policy + CloudTrail Decrypt-event audit story you'd apply to Lambda code, Secrets Manager, or any other build output.

Recommendation. Configure a customer-managed AWS KMS key as the encryptionKey for each artifact store. This enables key rotation, fine-grained access policies, and CloudTrail auditing of decrypt operations.

Source: CP-002 in the AWS provider.

CP-005: Production Deploy stage has no preceding ManualApproval MEDIUM

Evidences: ENF-1 L2: Enforce security policy of OSS usage (block on violation), ENF-2 L2: Break the build when a violation is detected.

How this is detected. The complement to CP-001: this rule fires only on stages whose name contains prod / production / live. Even teams that intentionally skip approvals for dev / staging deploys usually want a human in the loop for a production-tagged target.

Recommendation. Add a Manual approval action immediately before any stage whose name contains prod / production. CP-001 covers the generic case; this rule specifically looks at production-tagged stages where the blast radius of an unreviewed deploy is largest.

Source: CP-005 in the AWS provider.

DF-001: FROM image not pinned to sha256 digest HIGH 🔧 fix

Evidences: ING-1 L1: Use package managers trusted by your organization, UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Reuses _primitives/image_pinning.classify so the floating-tag semantics match GL-001 / JF-009 / ADO-009 / CC-003. PINNED_TAG (e.g. python:3.12.1-slim) is treated as unpinned here too, only an explicit @sha256: survives, since the tag is mutable on the registry side.

Recommendation. Resolve every base image to its current digest (docker buildx imagetools inspect <ref> prints it) and pin via FROM repo@sha256:<digest>. Automate refreshes with Renovate or Dependabot. A floating tag (:latest, :3, no tag) silently swaps the build base under every rebuild.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Seen in the wild.

  • Docker Hub typosquatting / namespace-takeover incidents (2017 onward): docker-library Sysdig and Aqua research documented thousands of malicious images uploaded under near-miss names (alpine vs alphine, etc.) and occasional namespace recoveries shipping crypto-miners downstream. Digest-pinned consumers are immune; tag-pinned consumers pull whatever sits under the name today.
  • Codecov codecov/codecov-action tag-mutation incident (post-Codecov-Bash-uploader compromise): the upstream rotated the action's @v3 tag during the fallout, and consumers pinning to the tag silently re-ran a different build than before. Digest pinning would have surfaced the change as a checksum mismatch instead of a silent swap.

Source: DF-001 in the Dockerfile provider.

DF-003: ADD pulls remote URL without integrity verification HIGH

Evidences: ING-1 L1: Use package managers trusted by your organization, UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. ADD with a URL is the historical Dockerfile footgun: it fetches at build time over HTTP(S) with no checksum and no signature, and the registry tag does not pin the source. A tampered server or DNS hijack silently swaps the content. COPY is for local files; RUN curl + verify is for remote ones.

Recommendation. Replace ADD https://... with a multi-step RUN: download the file with curl -fsSLo, verify a known-good checksum (sha256sum -c) or signature (cosign verify-blob), then extract / install. Better still: download the artifact in a builder stage and COPY it across. That way the verifier runs once at build time, not per-pull.

Source: DF-003 in the Dockerfile provider.

DF-004: RUN executes a remote script via curl-pipe / wget-pipe HIGH

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Reuses _primitives/remote_script_exec.scan so the vocabulary matches the equivalent CI-side rules (GHA-016, GL-016, BB-012, ADO-016, CC-016, JF-016).

Recommendation. Download to a file, verify checksum or signature, then execute. curl -fsSL <url> -o /tmp/x.sh && sha256sum -c <(echo '<digest> /tmp/x.sh') && bash /tmp/x.sh. Vendor installers from well-known hosts (rustup.rs, get.docker.com, ...) are reported with vendor_trusted=true so reviewers can calibrate.

Source: DF-004 in the Dockerfile provider.

DF-010: apt-get dist-upgrade / upgrade pulls unknown package versions LOW

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Running apt-get upgrade (or dist-upgrade) inside a Dockerfile is the classic pet-vs-cattle anti-pattern. Two back-to-back builds with the same Dockerfile can produce different images because the upstream archive moved between the two RUN invocations. dist-upgrade additionally relaxes dependency resolution. It can install / remove arbitrary packages to satisfy upgrades, so the resulting image's package set isn't even bounded by what the Dockerfile declares.

Recommendation. Drop the upgrade step. Build on a recent base image instead (rebuild your image when the base image gets a security patch, pin the base by digest per DF-001 so the rebuild is deterministic). apt-get install pkg=<version> for specific packages stays reproducible; upgrade / dist-upgrade does not.

Source: DF-010 in the Dockerfile provider.

DF-011: Package manager install without cache cleanup in same layer LOW

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Each Dockerfile RUN produces a layer. Installing packages in one layer and cleaning the cache in a later layer leaves the cache files in the lower layer forever, final image size is unchanged and the residual files broaden the attack surface (e.g. apt's signed-by keys, package metadata). The fix is layout, not behavior: do install + cleanup in the same RUN.

Recommendation. Combine the install and cleanup into the same RUN so the cache lands in a single layer that gets discarded together. Idiomatic pattern: RUN apt-get update && apt-get install -y <pkgs> && rm -rf /var/lib/apt/lists/*. Equivalent forms: apk add --no-cache <pkgs>, dnf install -y … && dnf clean all, yum install -y … && yum clean all, zypper -n in … && zypper clean -a.

Source: DF-011 in the Dockerfile provider.

DF-016: Image lacks OCI provenance labels LOW

Evidences: REB-3 L4: Generate SBOMs for artifacts produced.

How this is detected. The OCI image-spec annotation set is a small de facto standard maintained by the OCI working group. Only image.source and image.revision are checked because they're the two whose absence makes incident response materially harder; image.title / image.description are nice-to-have but the rule doesn't fire on those.

Recommendation. Add a LABEL line carrying at least org.opencontainers.image.source (the URL of the source repo) and org.opencontainers.image.revision (the commit SHA built into the image). Most registries surface those fields in the UI and on manifest inspect, which closes the source-to-image gap that GHA-006 / SLSA Build-L2 provenance attestation also addresses.

Known false positives.

  • A multi-stage build's intermediate stages don't need provenance labels, only the final image ships. The rule fires per Dockerfile, not per stage; suppress for files where the final FROM is intentional throwaway scratch.

Source: DF-016 in the Dockerfile provider.

ECR-001: Image scanning on push not enabled HIGH

Evidences: SCA-1 L1: Scan OSS for known vulnerabilities.

How this is detected. scan-on-push runs a CVE check against the image's OS package layers at the moment it lands in ECR. Without it, an image with a known CVE deploys silently. The ECR basic scanner is free; ECR-007 covers the Inspector v2 enhanced scanner that adds language-ecosystem CVEs (npm, pip, gem).

Recommendation. Enable imageScanningConfiguration.scanOnPush on the repository. Consider also enabling Amazon Inspector continuous scanning for ongoing CVE detection against images already in the registry.

Source: ECR-001 in the AWS provider.

ECR-002: Image tags are mutable HIGH

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Mutable tags mean :latest, :v1.0, and :stable can be re-pushed silently, the same tag points to different image content over time. Pinning by digest (sha256:...) in deployment manifests is the only durable reference; IMMUTABLE on the repo enforces the property registry-side so a forgotten digest reference doesn't drift.

Recommendation. Set imageTagMutability=IMMUTABLE on the repository. Reference images by digest (sha256:...) in deployment manifests for strongest immutability guarantees.

Source: ECR-002 in the AWS provider.

ECR-005: Repository encrypted with AES256 rather than KMS CMK MEDIUM

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. Same shape as CP-002 / CWL-002 / CCM-002: AES256 (the AWS-managed default) gives confidentiality at rest but no key-policy or CloudTrail Decrypt-event story. Container images are arguably sensitive intellectual property, the same key-policy + audit shape as build outputs in S3 is warranted.

Recommendation. Set encryptionType=KMS with a customer-managed key ARN.

Source: ECR-005 in the AWS provider.

ECR-006: ECR pull-through cache rule uses an untrusted upstream HIGH

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. AWS supports pull-through cache for ECR Public, Quay, K8s, GitHub Container Registry, GitLab, and Docker Hub. A rule pointing at registry-1.docker.io without an authenticated credential silently caches whatever the public namespace resolves to.

Recommendation. Scope pull-through cache rules to AWS-trusted registries (ECR Public, Quay.io with authentication, or a vetted private registry). Avoid wildcard or unauthenticated upstreams, a malicious image there gets cached into your account registry on first pull.

Source: ECR-006 in the AWS provider.

ECR-007: Inspector v2 enhanced scanning disabled for ECR MEDIUM

Evidences: SCA-1 L1: Scan OSS for known vulnerabilities.

How this is detected. ECR-001's basic on-push scan covers OS-level packages, apt / yum / apk lineage. Most production CVE risk is in language ecosystems (npm, pip, gem, mvn) which the basic scanner ignores. Inspector v2 enhanced scanning closes that gap and runs continuously, so a CVE published two weeks after a build still surfaces against the deployed image.

Recommendation. Enable Amazon Inspector v2 for the ECR scan type on this account. Basic ECR scanning on-push only covers OS packages; Inspector v2 enhanced scanning adds language-ecosystem CVEs and runs continuously as new vulnerabilities are published.

Source: ECR-007 in the AWS provider.

GCB-001: Cloud Build step image not pinned by digest HIGH 🔧 fix

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Bare references (gcr.io/cloud-builders/docker) are treated as :latest by Cloud Build. Tag-only references (:20, :latest) count as unpinned. Only @sha256:… suffixes pass.

Recommendation. Pin every steps[].name image to an @sha256:<digest> suffix. gcr.io/cloud-builders/docker:latest is mutable; Google publishes new builder images frequently and the next build would pull whatever is current. Resolve the digest with gcloud artifacts docker images describe <ref> --format='value(image_summary.digest)' and pin it.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: GCB-001 in the Cloud Build provider.

GCB-008: No vulnerability scanning step in Cloud Build pipeline MEDIUM

Evidences: SCA-1 L1: Scan OSS for known vulnerabilities.

How this is detected. The detector matches tool names anywhere in the document, step images, args, or entrypoint strings. Container Analysis API scanning configured at the project level counts as compensating control but is out of scope for this YAML-only check; if you rely on it, suppress this rule via --checks.

Recommendation. Add a step that runs a vulnerability scanner, trivy, grype, snyk test, npm audit, pip-audit, osv-scanner, or govulncheck. In Cloud Build this typically looks like a step with name: aquasec/trivy or an entrypoint: bash step that invokes trivy image / grype <ref> on the built image.

Source: GCB-008 in the Cloud Build provider.

GCB-009: Artifacts not signed (no cosign / sigstore step) MEDIUM

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. Silent-pass when the pipeline does not appear to produce artifacts (no docker push / gcloud run deploy / kubectl apply / etc. in any step). The detector matches cosign, sigstore, slsa-framework, and notation.

Recommendation. Add a signing step before images: is resolved, for example, a step with name: gcr.io/projectsigstore/cosign that runs cosign sign --yes <registry>/<repo>@<digest>. Pair with an attestation step (cosign attest --predicate sbom.json --type cyclonedx) so consumers can verify both the signature and the build provenance.

Source: GCB-009 in the Cloud Build provider.

GHA-001: Action not pinned to commit SHA HIGH 🔧 fix

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Every uses: reference should pin a specific 40-char commit SHA. Tag and branch refs (@v4, @main) can be silently moved to malicious commits by whoever controls the upstream repository, a third-party action compromise will propagate into the pipeline on the next run.

Recommendation. Replace tag/branch references (@v4, @main) with the full 40-char commit SHA. Use Dependabot or StepSecurity to keep the pins fresh.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Seen in the wild.

  • tj-actions/changed-files compromise (CVE-2025-30066, March 2025): a malicious commit retagged behind @v1 / @v45 shipped CI-secret exfiltration to roughly 23,000 repos that had pinned the action to a mutable tag instead of a commit SHA.
  • reviewdog/action-setup compromise (CVE-2025-30154, March 2025): same week, similar mechanism. Tag-pinned consumers auto-pulled the malicious version; SHA-pinned consumers were unaffected.

Proof of exploit.

Tag-pinned reference (vulnerable):

  • uses: tj-actions/changed-files@v45

Attack: the upstream maintainer (or anyone who compromises

the upstream repo) force-moves the v45 tag to a malicious

commit:

git tag -f v45

git push --force origin v45

Every consumer's next workflow run pulls the new code

automatically, executing the attacker's payload with the

job's secrets and GITHUB_TOKEN in scope.

Safe: pin to a 40-char commit SHA (immutable):

Source: GHA-001 in the GitHub Actions provider.

GHA-006: Artifacts not signed (no cosign/sigstore step) MEDIUM

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. Unsigned artifacts cannot be verified downstream, so a tampered build is indistinguishable from a legitimate one. The check recognizes cosign, sigstore, slsa-github-generator, slsa-framework, and notation-sign as signing tools.

Recommendation. Add a signing step, e.g. sigstore/cosign-installer followed by cosign sign, or slsa-framework/slsa-github-generator for keyless SLSA provenance. Publish the signature alongside the artifact and verify it at consumption time.

Seen in the wild.

  • SolarWinds Orion compromise (December 2020): SUNBURST trojanized builds shipped to ~18,000 customers because no post-build signature could be checked against a trusted signing identity. Cryptographic signing on every release would have given downstream consumers a verifiable break with the upstream key, the absence of which was the ambient signal of compromise.
  • PyTorch nightly compromise (December 2022): the torchtriton dependency was hijacked via PyPI dependency-confusion. Sigstore-style attestation tied to the official publisher would have made the impostor build fail verification rather than silently install.

Source: GHA-006 in the GitHub Actions provider.

GHA-007: SBOM not produced (no CycloneDX/syft/Trivy-SBOM step) MEDIUM

Evidences: REB-3 L4: Generate SBOMs for artifacts produced.

How this is detected. Without an SBOM, downstream consumers cannot audit the exact set of dependencies shipped in the artifact, delaying vulnerability response when a transitive dep is disclosed. The check recognises CycloneDX, syft, Anchore SBOM action, spdx-sbom-generator, Microsoft sbom-tool, and Trivy in SBOM mode.

Recommendation. Add an SBOM generation step, anchore/sbom-action, syft . -o cyclonedx-json, Trivy with --format cyclonedx, or Microsoft's sbom-tool. Attach the SBOM to the release so consumers can ingest it into their vuln-management pipeline.

Source: GHA-007 in the GitHub Actions provider.

GHA-014: Deploy job missing environment binding MEDIUM 🔧 fix

Evidences: ENF-1 L2: Enforce security policy of OSS usage (block on violation).

How this is detected. Without an environment: binding, a deploy job can't be gated by required reviewers, deployment-branch policies, or wait timers. Any push to the triggering branch will deploy immediately.

Recommendation. Add environment: <name> to jobs that deploy. Configure required reviewers, wait timers, and branch-protection rules on the matching GitHub environment.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Known false positives.

  • Integration-test jobs that run terraform apply or kubectl apply against a local mock (LocalStack, Moto, kind, k3d) aren't real deploys. The rule auto-suppresses a step whose env carries AWS_ENDPOINT_URL or KUBE_API_URL pointing at a localhost address.

Source: GHA-014 in the GitHub Actions provider.

GHA-018: Package install from insecure source HIGH 🔧 fix

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Detects package-manager invocations that use plain HTTP registries (--index-url http://, --registry=http://) or disable TLS verification (--trusted-host, --no-verify) in a workflow. These patterns allow man-in-the-middle injection of malicious packages.

Recommendation. Use HTTPS registry URLs. Remove --trusted-host and --no-verify flags. Pin to a private registry with TLS.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: GHA-018 in the GitHub Actions provider.

GHA-020: No vulnerability scanning step MEDIUM

Evidences: SCA-1 L1: Scan OSS for known vulnerabilities.

How this is detected. Without a vulnerability scanning step, known-vulnerable dependencies ship to production undetected. The check recognises trivy, grype, snyk, npm audit, yarn audit, safety check, pip-audit, osv-scanner, and govulncheck.

Recommendation. Add a vulnerability scanning step, trivy, grype, snyk test, npm audit, pip-audit, or osv-scanner. Publish results so vulnerabilities surface before deployment.

Source: GHA-020 in the GitHub Actions provider.

GHA-021: Package install without lockfile enforcement MEDIUM 🔧 fix

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Detects package-manager install commands that do not enforce a lockfile or hash verification. Without lockfile enforcement the resolver pulls whatever version is currently latest, exactly the window a supply-chain attacker exploits.

Recommendation. Use lockfile-enforcing install commands: npm ci instead of npm install, pip install --require-hashes -r requirements.txt, yarn install --frozen-lockfile, bundle install --frozen, and go install tool@v1.2.3.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: GHA-021 in the GitHub Actions provider.

GHA-022: Dependency update command bypasses lockfile pins MEDIUM 🔧 fix

Evidences: UPD-2 L3: Enable automated OSS updates (Dependabot / Renovate).

How this is detected. Detects pip install --upgrade, npm update, yarn upgrade, bundle update, cargo update, go get -u, and composer update. These commands bypass lockfile pins and pull whatever version is currently latest. Tooling upgrades (pip install --upgrade pip) are exempted.

Recommendation. Remove dependency-update commands from CI. Use lockfile-pinned install commands (npm ci, pip install -r requirements.txt) and update dependencies via a dedicated PR workflow (e.g. Dependabot, Renovate).

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Known false positives.

  • Common build-tool bootstrapping idioms (pip install --upgrade pip, pip install --upgrade setuptools wheel virtualenv) and security-tool installs (pip install --upgrade pip-audit / cyclonedx-bom / semgrep) are exempted by the DEP_UPDATE_RE tooling allowlist. Other tooling-upgrade idioms not yet on the list can still trip the rule. Defaults to MEDIUM confidence so CI gates can require --min-confidence HIGH to ignore.

Source: GHA-022 in the GitHub Actions provider.

GHA-024: No SLSA provenance attestation produced MEDIUM

Evidences: REB-4 L4: Digitally sign SBOMs produced (attested provenance).

How this is detected. Provenance generation is distinct from signing. A signed artifact proves who published it; a provenance attestation proves where/how it was built. Consumers can then verify the build happened on a trusted runner, from a specific source commit, with known parameters. Without it, a leaked signing key forges identity but a leaked build environment also forges provenance. You need both for the SLSA L3 non-falsifiability guarantee.

Recommendation. Call slsa-framework/slsa-github-generator or actions/attest-build-provenance after the build step to emit an in-toto attestation alongside the artifact. cosign sign alone (covered by GHA-006) signs the artifact but doesn't record how it was built. SLSA Build L3 requires the provenance statement.

Source: GHA-024 in the GitHub Actions provider.

GHA-025: Reusable workflow not pinned to commit SHA HIGH

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. A reusable workflow runs with the caller's GITHUB_TOKEN and secrets by default. If uses: org/repo/.github/workflows/release.yml@v1 resolves to an attacker-modified commit, their code executes with your repository's permissions. This is the same threat model as unpinned step actions (GHA-001) but over a different uses: surface.

Recommendation. Pin every jobs.<id>.uses: reference to a 40-char commit SHA (owner/repo/.github/workflows/foo.yml@<sha>). Tag refs (@v1, @main) can be silently repointed by whoever controls the callee repository.

Source: GHA-025 in the GitHub Actions provider.

GHA-027: Workflow contains indicators of malicious activity CRITICAL

Evidences: SCA-3 L2: Scan OSS for malware.

How this is detected. Distinct from the hygiene checks. GHA-016 flags curl | bash as a risky default; this rule fires only on concrete indicators, reverse shells, base64-decoded execution, known miner binaries or pool URLs, exfil-channel domains, credential-dump pipes, history-erasure commands. Categories reported: obfuscated-exec, reverse-shell, crypto-miner, exfil-channel, credential-exfil, audit-erasure.

Recommendation. Treat this as a potential pipeline compromise. Inspect the matching step(s), identify the author and the PR that introduced them, rotate any credentials the workflow has access to, and audit CloudTrail/AuditLogs for exfil. If the match is a legitimate red-team exercise, whitelist via .pipelinecheckignore with an expires: date, never a permanent suppression.

Known false positives.

  • Security-training repositories, CTF challenges, and red-team exercise workflows legitimately contain reverse-shell strings or exfil domains as literals. Matches inside YAML keys / HCL attributes whose names contain example, fixture, sample, demo, or test are auto-suppressed; bare lines in a production workflow still fire.
  • Defaults to LOW confidence. Filter with --min-confidence MEDIUM to ignore all matches; the rule still surfaces the hit for teams that want to spot-check.

Source: GHA-027 in the GitHub Actions provider.

GHA-029: Package install bypasses registry integrity (git / path / tarball source) MEDIUM

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Package installs that pull from git+… without a pinned commit, from a local path (./dir, file:…, absolute paths), or from a direct tarball URL are invisible to the normal lockfile integrity controls. A moving branch head, a sibling checkout the build assumes exists, or a tarball whose hash isn't verified all give an attacker who controls any of those surfaces the ability to substitute code into the build.

Recommendation. Pin git dependencies to a commit SHA (pip install git+https://…/repo@<sha>, cargo install --git … --rev <sha>). Publish private packages to an internal registry instead of installing from a filesystem path or tarball URL.

Source: GHA-029 in the GitHub Actions provider.

GL-001: Image not pinned to specific version or digest HIGH 🔧 fix

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Floating tags (latest or major-only) can be silently swapped under the job. Every image: reference should pin a specific version tag or digest.

Recommendation. Reference images by @sha256:<digest> or at minimum a full immutable version tag (e.g. python:3.12.1-slim). Avoid :latest and bare tags like :3.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: GL-001 in the GitLab CI provider.

GL-004: Deploy job lacks manual approval or environment gate MEDIUM

Evidences: ENF-1 L2: Enforce security policy of OSS usage (block on violation), ENF-2 L2: Break the build when a violation is detected.

How this is detected. A job whose stage or name contains deploy / release / publish / promote should either require manual approval or declare an environment: binding. Otherwise any push to the trigger branch ships to the target.

Recommendation. Add when: manual (optionally with rules: for protected branches) or bind the job to an environment: with a deployment tier so approvals and audit are enforced by GitLab's environment controls.

Source: GL-004 in the GitLab CI provider.

GL-005: include: pulls remote / project without pinned ref HIGH

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Cross-project and remote includes can be silently re-pointed. Branch-name refs (main/master/develop/head) are treated as unpinned; tag and SHA refs are considered safe.

Recommendation. Pin include: project: entries with ref: set to a tag or commit SHA. Avoid include: remote: for untrusted URLs; mirror the content into a trusted project and pin it.

Source: GL-005 in the GitLab CI provider.

GL-006: Artifacts not signed MEDIUM

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. Unsigned artifacts can't be verified downstream, so a tampered build is indistinguishable from a legitimate one. Pass when any of cosign / sigstore / slsa-* / notation-sign appears in the pipeline text.

Recommendation. Add a job that runs cosign sign (keyless OIDC with GitLab's id_tokens works out of the box) or notation sign. Publish the signature next to the artifact and verify it on consume.

Source: GL-006 in the GitLab CI provider.

GL-007: SBOM not produced MEDIUM

Evidences: REB-3 L4: Generate SBOMs for artifacts produced.

How this is detected. Without an SBOM, downstream consumers can't audit the dependency set shipped in the artifact. Passes when CycloneDX / syft / anchore / spdx-sbom-generator / sbom-tool / Trivy-SBOM appears in the pipeline body.

Recommendation. Add an SBOM step, syft . -o cyclonedx-json, Trivy with --format cyclonedx, or GitLab's built-in CycloneDX dependency-scanning template. Attach the SBOM as a pipeline artifact.

Source: GL-007 in the GitLab CI provider.

GL-009: Image pinned to version tag rather than sha256 digest LOW

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. GL-001 fails floating tags at HIGH; GL-009 is the stricter tier. Even immutable-looking version tags (python:3.12.1) can be repointed by registry operators. Digest pins are the only tamper-evident form.

Recommendation. Resolve each image to its current digest (docker buildx imagetools inspect <ref> prints it) and replace the tag with @sha256:<digest>. Automate refreshes with Renovate.

Source: GL-009 in the GitLab CI provider.

GL-018: Package install from insecure source HIGH 🔧 fix

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Detects package-manager invocations that use plain HTTP registries (--index-url http://, --registry=http://) or disable TLS verification (--trusted-host, --no-verify) in a pipeline. These patterns allow man-in-the-middle injection of malicious packages.

Recommendation. Use HTTPS registry URLs. Remove --trusted-host and --no-verify flags. Pin to a private registry with TLS.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: GL-018 in the GitLab CI provider.

GL-019: No vulnerability scanning step MEDIUM

Evidences: SCA-1 L1: Scan OSS for known vulnerabilities.

How this is detected. Without a vulnerability scanning step, known-vulnerable dependencies ship to production undetected. The check recognises trivy, grype, snyk, npm audit, yarn audit, safety check, pip-audit, osv-scanner, and govulncheck.

Recommendation. Add a vulnerability scanning step, trivy, grype, snyk test, npm audit, pip-audit, or osv-scanner. Publish results so vulnerabilities surface before deployment.

Source: GL-019 in the GitLab CI provider.

GL-021: Package install without lockfile enforcement MEDIUM 🔧 fix

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Detects package-manager install commands that do not enforce a lockfile or hash verification. Without lockfile enforcement the resolver pulls whatever version is currently latest, exactly the window a supply-chain attacker exploits.

Recommendation. Use lockfile-enforcing install commands: npm ci instead of npm install, pip install --require-hashes -r requirements.txt, yarn install --frozen-lockfile, bundle install --frozen, and go install tool@v1.2.3.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: GL-021 in the GitLab CI provider.

GL-022: Dependency update command bypasses lockfile pins MEDIUM 🔧 fix

Evidences: UPD-2 L3: Enable automated OSS updates (Dependabot / Renovate).

How this is detected. Detects pip install --upgrade, npm update, yarn upgrade, bundle update, cargo update, go get -u, and composer update. These commands bypass lockfile pins and pull whatever version is currently latest. Tooling upgrades (pip install --upgrade pip) are exempted.

Recommendation. Remove dependency-update commands from CI. Use lockfile-pinned install commands (npm ci, pip install -r requirements.txt) and update dependencies via a dedicated PR workflow (e.g. Dependabot, Renovate).

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Known false positives.

  • Common build-tool bootstrapping idioms (pip install --upgrade pip, pip install --upgrade setuptools wheel virtualenv) and security-tool installs (pip install --upgrade pip-audit / cyclonedx-bom / semgrep) are exempted by the DEP_UPDATE_RE tooling allowlist. Other tooling-upgrade idioms not yet on the list can still trip the rule. Defaults to MEDIUM confidence so CI gates can require --min-confidence HIGH to ignore.

Source: GL-022 in the GitLab CI provider.

GL-024: No SLSA provenance attestation produced MEDIUM

Evidences: REB-4 L4: Digitally sign SBOMs produced (attested provenance).

How this is detected. cosign sign and cosign attest look similar but mean different things: the first binds identity to bytes; the second binds a structured claim (builder, source, inputs) to the artifact. SLSA Build L3 verifiers check the latter.

Recommendation. Add a job that runs cosign attest against a provenance.intoto.jsonl statement, or adopt a SLSA-aware builder (the SLSA project ships GitLab templates). Signing the artifact (GL-006) isn't enough for SLSA L3, the attestation describes how the build ran.

Source: GL-024 in the GitLab CI provider.

GL-025: Pipeline contains indicators of malicious activity CRITICAL

Evidences: SCA-3 L2: Scan OSS for malware.

How this is detected. Fires on concrete indicators (reverse shells, base64-decoded execution, miner binaries, Discord/Telegram webhooks, webhook.site callbacks, env | curl credential dumps, history -c audit erasure). Orthogonal to GL-003 (curl pipe) and GL-017 (Docker insecure flags). Those flag risky defaults; this flags evidence.

Recommendation. Treat as a potential compromise. Identify the MR that added the matching job(s), rotate any credentials the pipeline can reach, and audit recent runs for outbound traffic to the matched hosts. A legitimate red-team exercise should be time-bounded via .pipelinecheckignore with expires:.

Known false positives.

  • Security-training repositories, CTF challenges, and red-team exercise pipelines legitimately contain reverse-shell strings or exfil domains as literals. Matches inside YAML keys / HCL attributes whose names contain example, fixture, sample, demo, or test are auto-suppressed; bare lines in a production pipeline still fire.
  • Defaults to LOW confidence. Filter with --min-confidence MEDIUM to ignore all matches; the rule still surfaces the hit for teams that want to spot-check.

Source: GL-025 in the GitLab CI provider.

GL-027: Package install bypasses registry integrity (git / path / tarball source) MEDIUM

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Complements GL-021 (missing lockfile flag). Git URL installs without a commit pin, local-path installs, and direct tarball URLs all bypass the registry integrity controls the lockfile relies on, an attacker who can move a branch head, drop a sibling checkout, or change a served tarball can substitute code into the build.

Recommendation. Pin git dependencies to a commit SHA (pip install git+https://…/repo@<sha>, cargo install --git … --rev <sha>). Publish private packages to an internal registry instead of installing from a filesystem path or tarball URL.

Source: GL-027 in the GitLab CI provider.

GL-028: services: image not pinned HIGH

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. services: entries (top-level or per-job) can be either a string (redis:7) or a dict ({name: redis:7, alias: cache}). Both forms are normalized via image_ref-style extraction and evaluated with the same floating-tag regex GL-001 uses for image:.

Recommendation. Pin every services: entry the same way image: is pinned, prefer @sha256:<digest>, or at minimum a full immutable version tag (postgres:16.2-alpine). Avoid :latest and bare tags like :16.

Source: GL-028 in the GitLab CI provider.

GL-029: Manual deploy job defaults to allow_failure: true MEDIUM

Evidences: ENF-2 L2: Break the build when a violation is detected.

How this is detected. This is the most common GitLab deployment gotcha: a manual deploy job looks like a gate in the UI, but the pipeline reports success on the first run because the job is marked allow_failure by default. Downstream jobs (and the overall pipeline status) proceed as though the human approved.

Recommendation. Add allow_failure: false to every deploy-like when: manual job. GitLab defaults allow_failure to true for manual jobs, which makes the pipeline report success whether or not the operator clicks, exactly the opposite of the gate you meant to add.

Source: GL-029 in the GitLab CI provider.

GL-030: trigger: include: pulls child pipeline without pinned ref HIGH

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. GL-005 only audits top-level include:. Parent-child and multi-project pipelines that load YAML via the job-level trigger: include: slot slip through. Branch refs (main/master/develop/head) count as unpinned.

Recommendation. Pin trigger: include: project: entries with ref: set to a tag or commit SHA. Avoid trigger: include: remote: for untrusted URLs; mirror the content into a trusted project and pin it there.

Source: GL-030 in the GitLab CI provider.

HELM-001: Chart.yaml declares legacy apiVersion: v1 MEDIUM 🔧 fix

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. apiVersion lives at the top of Chart.yaml. v1 is Helm 2's format and uses a sibling requirements.yaml for dependencies; v2 is Helm 3's format and inlines them in Chart.yaml alongside a Chart.lock for digest pinning. Without v2 there is no in-tree dependency manifest to lock, which is why HELM-002 only fires on v2 charts.

Recommendation. Bump Chart.yaml to apiVersion: v2 and migrate any sibling requirements.yaml entries into the dependencies: list inside Chart.yaml. Run helm dependency update to regenerate Chart.lock so HELM-002's per-dependency digest check has something to read. Helm 3 has been the default shipping channel since November 2019; the v1 format is kept for read-compat but blocks lockfile-based supply-chain controls.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: HELM-001 in the Helm provider.

HELM-002: Chart.lock missing per-dependency digests HIGH 🔧 fix

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions), REB-3 L4: Generate SBOMs for artifacts produced.

How this is detected. Three failure shapes:

  1. Chart.yaml declares dependencies but no Chart.lock exists at all.
  2. Chart.lock exists but its dependencies: list is missing entries declared in Chart.yaml (drift after an edit without re-running helm dependency update).
  3. Chart.lock lists every dependency but one or more entries lack a digest: field (lock generated by an old Helm 3 version that didn't always populate it).

v1 charts (HELM-001) are skipped. They predate Chart.lock and use requirements.lock against a sibling requirements.yaml. Fix HELM-001 first.

Recommendation. After every change to dependencies: in Chart.yaml, re-run helm dependency update and commit the regenerated Chart.lock. The lock records the resolved version and a sha256:... digest that helm dependency build verifies on download, without it, a compromised chart repo can swap the tarball under the same version and helm install will happily use the substitute.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Known false positives.

  • Charts with no dependencies (the dependencies: key is absent or empty) pass automatically. There is nothing to lock.

Source: HELM-002 in the Helm provider.

HELM-003: Chart dependency declared on a non-HTTPS repository HIGH 🔧 fix

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Walks Chart.yaml dependencies: (v2 charts only) and inspects each entry's repository: URL. Accepted schemes:

  • https://, chart-museum / OSS chart repos. The default for public Helm charts.
  • oci://, registry-hosted charts. TLS is enforced by the registry, not the URL scheme; we still accept this shape because Helm 3.8+ pulls OCI charts over HTTPS unless explicitly configured otherwise.
  • file://, in-repo dependency. No network surface.
  • @alias, local alias for a previously registered helm repo add URL. The scheme of the original URL is the user's responsibility (and is captured in the chart consumer's ~/.config/helm/repositories.yaml).

Recommendation. Switch each dependencies[].repository value to an https:// chart repo URL, an oci:// registry reference, or a file:// path for in-repo charts. Plaintext http:// (and other non-TLS schemes like git://) lets any on-path attacker substitute the dependency tarball during helm dependency build; Chart.lock's digest check (HELM-002) only catches that on the next update, not the compromised pull itself.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: HELM-003 in the Helm provider.

HELM-004: Chart dependency version is a range, not an exact pin MEDIUM

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. An exact pin is a string that contains only digits, dots, and at most a single leading v / trailing pre-release or build identifier (1.2.3, v1.2.3, 1.2.3-rc1, 1.2.3+build.5). Anything carrying ^ / ~ / > / < / * / x / X / || / a space (>=4 <5) is treated as a range. The bias is toward false positives, a chart maintainer can suppress per-rule via --ignore-file if they specifically want range semantics, but the default for production charts is a pin.

Recommendation. Replace each dependencies[].version constraint with the exact resolved version from Chart.lock. 17.0.0 instead of ^17.0.0, v1.2.3 instead of ~1.2. Range syntax (^, ~, >=, *, x) lets helm dependency update move every consumer of the chart to a newer dep on the next refresh, even when the lock file looked stable.

Source: HELM-004 in the Helm provider.

HELM-008: Chart.lock generated more than 90 days ago MEDIUM

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Reads Chart.lock's top-level generated: timestamp (an ISO-8601 string Helm writes when the lock was last regenerated) and compares against now. Fires when the delta is more than 90 days. Charts without Chart.lock are skipped. HELM-002 covers the missing-lock case directly. Charts whose generated: field is malformed or absent silently pass on this rule (HELM-002 covers the absent-lock case from a different angle).

Recommendation. Run helm dependency update against every dependency-carrying chart at least once per release cycle, and commit the regenerated Chart.lock. The lock pins versions and digests; the update cadence is what brings in CVE fixes and deprecation notices from the last quarter. CI can run the same command against main weekly to surface drift as a PR rather than letting the lock sit stale until the next release.

Known false positives.

  • A chart that pins exact versions and never needs new dependencies (e.g. a chart packaging a single internal library that itself updates rarely) may legitimately have a stale Chart.lock. Suppress with --ignore-file when this matches your situation.

Source: HELM-008 in the Helm provider.

HELM-009: Chart home / sources URL uses a non-HTTPS scheme LOW

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Walks Chart.yaml home: (single string) and sources: (list of strings). Fires on any value whose scheme is http://, ftp://, or other plaintext form. Empty / missing fields pass, the rule only evaluates URLs that are populated with the wrong scheme. HELM-003 covers the same risk for dependency-repo URLs.

Recommendation. Switch every home: URL and every entry in sources: to https://. Most chart-listing UIs display these as click-through links from a public chart registry; serving them over plaintext is a confused-deputy footgun for anyone evaluating the chart's provenance. http:// URLs against localhost are not exempted, production charts shouldn't ship references to a developer-local endpoint anyway.

Source: HELM-009 in the Helm provider.

JF-001: Shared library not pinned to a tag or commit HIGH

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. @main, @master, @develop, no-@ref, and any non-semver / non-SHA ref are floating. Whoever controls the upstream library can ship code into your build by pushing to that branch.

Recommendation. Pin every @Library('name@<ref>') to a release tag (e.g. @v1.4.2) or a 40-char commit SHA. Configure the library in Jenkins with 'Allow default version to be overridden' disabled so a pipeline can't escape the pin.

Source: JF-001 in the Jenkins provider.

JF-005: Deploy stage missing manual input approval MEDIUM

Evidences: ENF-1 L2: Enforce security policy of OSS usage (block on violation).

How this is detected. A stage named deploy / release / publish / promote should either use the declarative input { ... } directive or call input message: ... somewhere in its body. Without one, any push that triggers the pipeline ships to the target with no human review.

Recommendation. Add an input step to every deploy-like stage (e.g. input message: 'Promote to prod?', submitter: 'releasers'). Combine with a Jenkins folder-scoped permission so only release engineers see the prompt.

Source: JF-005 in the Jenkins provider.

JF-006: Artifacts not signed MEDIUM

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. Passes when cosign / sigstore / slsa-* / notation-sign appears in executable Jenkinsfile text (comments are stripped before matching).

Recommendation. Add a sh 'cosign sign --yes …' step (the cosign-installer Jenkins plugin handles binary install). Publish the signature next to the artifact and verify it at deploy.

Source: JF-006 in the Jenkins provider.

JF-007: SBOM not produced MEDIUM

Evidences: REB-3 L4: Generate SBOMs for artifacts produced.

How this is detected. Passes when a direct SBOM tool token (CycloneDX, syft, anchore, spdx-sbom-generator, sbom-tool) appears in executable code, or when Trivy is paired with sbom / cyclonedx in the same file. Comments are stripped before matching.

Recommendation. Add a sh 'syft . -o cyclonedx-json > sbom.json' step (or Trivy with --format cyclonedx) and archive the result with archiveArtifacts.

Source: JF-007 in the Jenkins provider.

JF-009: Agent docker image not pinned to sha256 digest HIGH

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. agent { docker { image 'name:tag' } } is not digest-pinned, so a repointed registry tag silently swaps the executor under every subsequent build. Unlike the YAML providers, Jenkins has no separate tag-pinning check, so this one fires at HIGH regardless of whether the tag is floating or immutable.

Recommendation. Resolve each image to its current digest (docker buildx imagetools inspect <ref> prints it) and reference it via image '<repo>@sha256:<digest>'. Automate refreshes with Renovate.

Source: JF-009 in the Jenkins provider.

JF-018: Package install from insecure source HIGH 🔧 fix

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Detects package-manager invocations that use plain HTTP registries (--index-url http://, --registry=http://) or disable TLS verification (--trusted-host, --no-verify) in a Jenkinsfile. These patterns allow man-in-the-middle injection of malicious packages.

Recommendation. Use HTTPS registry URLs. Remove --trusted-host and --no-verify flags. Pin to a private registry with TLS.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: JF-018 in the Jenkins provider.

JF-020: No vulnerability scanning step MEDIUM

Evidences: SCA-1 L1: Scan OSS for known vulnerabilities.

How this is detected. Without a vulnerability scanning step, known-vulnerable dependencies ship to production undetected. The check recognises trivy, grype, snyk, npm audit, yarn audit, safety check, pip-audit, osv-scanner, and govulncheck. Comments are stripped before matching.

Recommendation. Add a vulnerability scanning step, trivy, grype, snyk test, npm audit, pip-audit, or osv-scanner. Publish results so vulnerabilities surface before deployment.

Source: JF-020 in the Jenkins provider.

JF-021: Package install without lockfile enforcement MEDIUM 🔧 fix

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Detects package-manager install commands that do not enforce a lockfile or hash verification. Without lockfile enforcement the resolver pulls whatever version is currently latest, exactly the window a supply-chain attacker exploits.

Recommendation. Use lockfile-enforcing install commands: npm ci instead of npm install, pip install --require-hashes -r requirements.txt, yarn install --frozen-lockfile, bundle install --frozen, and go install tool@v1.2.3.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: JF-021 in the Jenkins provider.

JF-022: Dependency update command bypasses lockfile pins MEDIUM 🔧 fix

Evidences: UPD-2 L3: Enable automated OSS updates (Dependabot / Renovate).

How this is detected. Detects pip install --upgrade, npm update, yarn upgrade, bundle update, cargo update, go get -u, and composer update. These commands bypass lockfile pins and pull whatever version is currently latest. Tooling upgrades (pip install --upgrade pip) are exempted.

Recommendation. Remove dependency-update commands from CI. Use lockfile-pinned install commands (npm ci, pip install -r requirements.txt) and update dependencies via a dedicated PR pipeline (e.g. Dependabot, Renovate).

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Known false positives.

  • Common build-tool bootstrapping idioms (pip install --upgrade pip, pip install --upgrade setuptools wheel virtualenv) and security-tool installs (pip install --upgrade pip-audit / cyclonedx-bom / semgrep) are exempted by the DEP_UPDATE_RE tooling allowlist. Other tooling-upgrade idioms not yet on the list can still trip the rule. Defaults to MEDIUM confidence so CI gates can require --min-confidence HIGH to ignore.

Source: JF-022 in the Jenkins provider.

JF-024: input approval step missing submitter restriction MEDIUM

Evidences: ENF-1 L2: Enforce security policy of OSS usage (block on violation).

How this is detected. JF-005 already flags deploy stages with no input step. This rule catches the subtler case: the gate exists, but it doesn't actually restrict approvers. submitter accepts a comma-separated list of Jenkins usernames and group names; scope it to the smallest release-eligible pool.

Recommendation. Add a submitter: 'releasers,sre' (or a single role) argument to every input step in a deploy-like stage. Without it, any user with the Jenkins job Build permission can approve a production promotion, the approval gate becomes advisory.

Source: JF-024 in the Jenkins provider.

JF-028: No SLSA provenance attestation produced MEDIUM

Evidences: REB-4 L4: Digitally sign SBOMs produced (attested provenance).

How this is detected. cosign sign signs the artifact bytes. cosign attest signs an in-toto statement describing how the build ran, builder, source commit, input parameters. SLSA L3 verifiers check the latter so consumers can enforce policy on where and how artifacts were produced.

Recommendation. Add a sh 'cosign attest --predicate=provenance.intoto.jsonl …' step after the build, or integrate the TestifySec witness run attestor. JF-006 covers signing; this rule covers the build-provenance statement SLSA Build L3 requires.

Source: JF-028 in the Jenkins provider.

JF-029: Jenkinsfile contains indicators of malicious activity CRITICAL

Evidences: SCA-3 L2: Scan OSS for malware.

How this is detected. Distinct from JF-016 (curl pipe) and JF-019 (Groovy sandbox escape). Those flag risky defaults; this flags concrete evidence, reverse shells, base64-decoded execution, miner binaries, exfil channels, credential-dump pipes, shell-history erasure. Runs on the comment-stripped Groovy text so // cosign verify … // webhook.site in a legitimate annotation doesn't false-positive.

Recommendation. Treat as a potential compromise. Identify the commit that introduced the matching stage(s), rotate Jenkins credentials the job can reach, review controller/agent audit logs for outbound traffic to the matched hosts, and re-image the agent pool if the compromise may have persisted.

Known false positives.

  • Security-training repositories, CTF challenges, and red-team exercise pipelines legitimately contain reverse-shell strings or exfil domains as literals. Matches inside YAML keys / HCL attributes whose names contain example, fixture, sample, demo, or test are auto-suppressed; bare lines in a production pipeline still fire.
  • Defaults to LOW confidence. Filter with --min-confidence MEDIUM to ignore all matches; the rule still surfaces the hit for teams that want to spot-check.

Source: JF-029 in the Jenkins provider.

JF-031: Package install bypasses registry integrity (git / path / tarball source) MEDIUM

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Complements JF-021 (missing lockfile flag). Git URL installs without a commit pin, local-path installs, and direct tarball URLs bypass the registry integrity controls the lockfile relies on.

Recommendation. Pin git dependencies to a commit SHA. Publish private packages to an internal registry (Artifactory, Nexus) instead of installing from a filesystem path or tarball URL.

Source: JF-031 in the Jenkins provider.

LMB-001: Lambda function has no code-signing config HIGH

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. Lambda code-signing config + a Signer profile (SIGN-001) validates that an uploaded zip was signed by a known profile before it's allowed to run. Without one, anyone who reaches lambda:UpdateFunctionCode, a CI/CD role compromise, a misattached IAM policy, can replace the function's code with no chain-of-custody check.

Recommendation. Create an AWS Signer profile, reference it from an aws_lambda_code_signing_config with untrusted_artifact_on_deployment = Enforce and attach that config to the function. Without one, the Lambda runtime will execute any code that a principal with lambda:UpdateFunctionCode uploads.

Source: LMB-001 in the AWS provider.

SIGN-001: No AWS Signer profile defined for Lambda deploys MEDIUM

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. AWS Signer profiles are the upstream of LMB-001's code-signing config. Without a profile defined, no function in the account can enforce code-signing, LMB-001's recommendation has nothing to point at. The profile is the foundation; the per-function code-signing config attaches it.

Recommendation. Create an AWS Signer profile with platform AWSLambda-SHA384-ECDSA and reference it from every Lambda code-signing config used by the pipeline. Without a profile, LMB-001 remediation isn't possible and release artifacts can't be signed at build time.

Source: SIGN-001 in the AWS provider.

SIGN-002: AWS Signer profile is revoked or inactive HIGH

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. A revoked or canceled Signer profile invalidates every signature it ever produced. Lambda functions configured to enforce code-signing fail to deploy until the profile is replaced (or, if UntrustedArtifactOnDeployment = Warn, deploy with a CloudWatch warning the operator rarely reads).

Recommendation. Rotate the signing profile: create a replacement and update every code-signing config that references the revoked profile. A revoked or canceled profile invalidates every signature it produced, lambdas relying on it will fail verification.

Source: SIGN-002 in the AWS provider.

TKN-001: Tekton step image not pinned to a digest HIGH

Evidences: UPD-1 L1: Update vulnerable OSS manually (pin + track versions).

How this is detected. Applies to Task and ClusterTask kinds. The image must contain @sha256: followed by a 64-char hex digest. Any tag-only reference, including :latest, fails.

Recommendation. Pin every step image to a content-addressable digest (gcr.io/tekton-releases/git-init@sha256:<digest>). Tag-only references (alpine:3.18) and rolling tags (alpine:latest) let a compromised registry update redirect the step at the next pull, with no audit trail in the Task manifest.

Source: TKN-001 in the Tekton provider.

TKN-008: Tekton step script pipes remote install or disables TLS HIGH 🔧 fix

Evidences: ING-1 L1: Use package managers trusted by your organization.

How this is detected. Uses the cross-provider CURL_PIPE_RE and TLS_BYPASS_RE regexes so detection is consistent with the GHA / GitLab / CircleCI / Cloud Build providers.

Recommendation. Replace curl ... | sh with a download-then-verify-then-execute pattern. Drop TLS-bypass flags (curl -k, git config http.sslverify false); install the missing CA into the step image instead. Both forms let an attacker controlling DNS / a transparent proxy substitute the script the step runs.

Autofix. pipeline_check --fix will patch this finding automatically. Review the diff before committing; the fixer applies the conservative remediation pattern (e.g. swap a floating tag for the digest it currently resolves to), not the most aggressive one.

Source: TKN-008 in the Tekton provider.

TKN-009: Artifacts not signed (no cosign/sigstore step) MEDIUM

Evidences: REB-2 L4: Digitally sign rebuilt / produced OSS artifacts.

How this is detected. Detection mirrors GHA-006 / BK-009 / CC-006, the shared signing-token catalog (cosign, sigstore, slsa-github-generator, slsa-framework, notation-sign) is searched across every string in the Task / Pipeline document. The rule only fires on artifact-producing Tasks (those that invoke docker build / docker push / buildah / kaniko / helm upgrade / aws s3 sync / etc.) so lint-only Tasks don't trip it.

Recommendation. Add a signing step to the Task, either a dedicated cosign sign step after the build, or use the official cosign Tekton catalog Task as a referenced step. The Task should sign by digest (cosign sign --yes <repo>@sha256:<digest>) so a re-pushed tag can't bypass the signature.

Source: TKN-009 in the Tekton provider.

TKN-010: No SBOM generated for build artifacts MEDIUM

Evidences: REB-3 L4: Generate SBOMs for artifacts produced.

How this is detected. An SBOM (CycloneDX or SPDX) records every component baked into the build. Without one, post-incident triage can't answer did this CVE ship? for a given artifact. Detection uses the shared SBOM-token catalog: syft, cyclonedx, cdxgen, spdx-tools, microsoft/sbom-tool. Fires only on artifact-producing Tasks.

Recommendation. Add an SBOM-generation step. syft <artifact> -o cyclonedx-json > $(workspaces.output.path)/sbom.json runs in the official syft Tekton catalog Task. cyclonedx-cli and cdxgen are alternatives. Publish the SBOM as a Workspace result so downstream Tasks can consume it.

Source: TKN-010 in the Tekton provider.

TKN-011: No SLSA provenance attestation produced MEDIUM

Evidences: REB-4 L4: Digitally sign SBOMs produced (attested provenance).

How this is detected. Provenance generation is distinct from signing. A signed artifact proves who published it; a provenance attestation proves where / how it was built. Tekton Chains is the Tekton-native answer, once enabled on the cluster, every TaskRun's outputs are signed and attested without per-Task wiring. Detection uses the shared provenance-token catalog (slsa-framework, cosign attest, in-toto, attest-build-provenance, witness run). Tasks produced by tekton-chains pass on the cosign attest match.

Recommendation. After the build step, run cosign attest --predicate slsa.json --type slsaprovenance <ref> (or use the tekton-chains controller, which signs and attests every TaskRun automatically when configured). Publish the attestation alongside the artifact so consumers can verify how it was built, not just who signed it.

Source: TKN-011 in the Tekton provider.

TKN-012: No vulnerability scanning step MEDIUM

Evidences: SCA-1 L1: Scan OSS for known vulnerabilities.

How this is detected. Vulnerability scanning sits at a different layer from signing and SBOM. It answers does this artifact ship a known CVE? rather than can we verify what it is?. Detection uses the shared vuln-scan-token catalog: trivy, grype, snyk, npm-audit, pip-audit, osv-scanner, govulncheck, anchore, codeql-action, semgrep, bandit, checkov, tfsec, dependency-check. Walks every Task / Pipeline / *Run document; passes if any document includes a scanner reference.

Recommendation. Add a vulnerability scanner step. trivy fs $(workspaces.src.path) for source / filesystem; trivy image <ref> for container images. The official Tekton catalog ships trivy-scanner and grype-scanner Tasks if you'd rather reference one. Fail the step on findings above a chosen severity so a regression blocks the merge instead of shipping.

Source: TKN-012 in the Tekton provider.


This page is generated. Edit pipeline_check/core/standards/data/s2c2f.py (mappings) or scripts/gen_standards_docs.py (intro / per-control prose) and run python scripts/gen_standards_docs.py s2c2f.