The 2023 CircleCI incident and the recent GhostAction GitHub attack are reminders that a CI credential or workflow change can be more valuable to an attacker than a single application vulnerability. Neither problem is solved by buying a second dependency scanner when the missing control is workflow review, token scope, or deployment identity.

The usual CI/CD security buying process starts with a vendor category: SAST, SCA, secret scanning, container security, or supply-chain security. That creates tool sprawl because most products now cover at least two categories, while the actual pipeline still has unprotected handoffs.

A better purchasing unit is the pipeline control: the place where code, credentials, build inputs, artifacts, or production access can change. Buy one primary tool or native control for each control point. Add another only when it protects a materially different path, repository population, or policy requirement.

Map tools to the pipeline control they actually protect

A pull request can be safe at the source-code layer and still become unsafe in CI. For example, CodeQL may find no vulnerability in an application change, while a workflow edit changes permissions: contents: read into a broad token, checks out an untrusted ref, or introduces an action from an unreviewed publisher.

Use the following map when comparing products. A vendor may appear in multiple cells, but that does not mean you should enable every module it sells.

Pipeline control What can go wrong Primary control Useful tool examples
Source Vulnerable application code reaches the default branch Static analysis and required pull-request review GitHub CodeQL, Semgrep
Dependencies A new direct or transitive package introduces a known vulnerability or unacceptable license Dependency inventory, pull-request diff review, update workflow GitHub Dependabot and dependency review, Snyk, Black Duck
Secrets API keys, tokens, private keys, or passwords enter Git history Pre-commit and server-side secret detection plus revocation Gitleaks, GitHub secret scanning
Workflow behavior A workflow gains unsafe permissions, runs untrusted code, or imports an unsafe action Workflow linting, action pinning, least-privilege tokens Zizmor, OpenSSF Scorecard, GitHub repository rules
Artifacts A deployed package or image cannot be tied to the reviewed build that produced it SBOM generation, immutable registry storage, signing or provenance Syft, Cosign, GitHub Packages
Deployment Long-lived cloud credentials or an unrestricted workflow can reach production OIDC federation, protected environments, deployment approvals GitHub Actions OIDC, GitHub Environments, cloud IAM

The important distinction is between finding bad code and controlling a release path. SAST and dependency tools are valuable, but neither proves that the artifact deployed to production came from the protected branch, a reviewed workflow, and a constrained deployment identity.

The overlap test: when not to buy another scanner

Before adding a product, ask one narrow question: Which pipeline decision will this tool block, approve, or make auditable that the current stack cannot? If the answer is “it has more findings,” require a second answer: which finding class is currently escaping, and who will triage the new queue?

Three common purchases create duplicate work:

  • Two SAST products that both comment on the same pull request. Keep both only when one covers a language, framework, or custom-rule requirement the other cannot.
  • Two SCA products that both flag the same CVE in package-lock.json, pom.xml, or requirements.txt. One may still be justified when a separate license-governance workflow is required, but that is a policy requirement, not extra vulnerability coverage.
  • A container vulnerability scanner plus an application dependency scanner without a defined boundary. Scan application manifests before merge; scan a final container image when OS packages, base images, or image configuration are part of the release risk.

The second-order cost is not license cost; it is policy disagreement. If Tool A marks a CVE as blocking, Tool B marks it as informational, and neither owns exception expiry, developers learn that every finding is negotiable. One blocking source of truth per control is usually more effective than three dashboards.

This is also where “platform” purchasing can be sensible. A GitHub-centered team can use GitHub-native controls for several adjacent controls, reducing integration work. A multi-forge organization may prefer a dedicated application-security platform, but it should still assign one system as the authority for each gate.

Reference stack: a small GitHub Actions project

For a project with one repository or a small number of maintainers, start with controls that are cheap to operate and visible in the pull request. The goal is not to simulate an enterprise security program. The goal is to prevent a bad workflow change, exposed secret, vulnerable dependency update, or uncontrolled production deployment from becoming routine.

Control Minimal implementation Gate
Source Enable CodeQL code scanning for supported languages and require its check on the default branch Block a pull request on newly introduced high-confidence findings according to team policy
Dependencies Enable Dependabot alerts and dependency updates; use dependency review on pull requests Review newly added dependencies and risky version changes before merge
Secrets Run Gitleaks locally and in CI; enable GitHub secret scanning where available Fail builds containing a detected secret and rotate exposed credentials
Workflow behavior Run Zizmor against .github/workflows; keep GITHUB_TOKEN permissions minimal Require review for workflow-file changes
Artifacts Generate an SBOM with Syft for release artifacts or container images Store the SBOM with the release artifact
Deployment Use GitHub Actions OIDC with cloud IAM; protect the production environment Permit production deployment only from the release workflow and protected environment

A practical secret check can be run locally before opening a pull request:

gitleaks detect --source . --redact

For an SBOM generated from a built image, use the artifact rather than only the repository directory. That captures the base image and operating-system packages that a manifest-only dependency check will not see.

syft your-registry/example-app:1.4.0 -o spdx-json=sbom.spdx.json

Do not give every workflow write access because one release job needs it. Set workflow-level permissions explicitly, then grant the smallest job-level permission necessary. A documentation build normally does not need package publishing, repository write access, cloud credentials, or a production environment.

Reference stack: a growing engineering organization

Once multiple teams ship from dozens of repositories, the problem changes from detection to consistency. A security engineer cannot manually inspect 80 workflow files, track 400 dependency exceptions, and verify whether every production deployment uses short-lived cloud credentials.

A growing organization should centralize policy while keeping pull-request feedback close to developers. The stack below assumes GitHub Actions remains the primary CI system.

Control Organization-scale choice Operating rule
Source, dependencies, and secrets GitHub Advanced Security or one alternative platform selected as the primary application-security authority Centralize severity policy, alert ownership, exception expiry, and reporting
Workflow behavior Repository rulesets, required workflow review, reusable hardened workflows, Zizmor or Scorecard checks Do not allow each repository to invent its own deployment workflow
Artifacts Central package or container registry, SBOM retention, artifact signing or provenance verification Deploy only immutable artifact references, not mutable tags such as latest
Deployment Cloud OIDC trust policies tied to repository, branch, and environment claims Separate staging and production identities; production requires a protected environment
Governance Security ownership data and a monthly exception review Every accepted risk has an owner and review date

The commercial decision is usually between a GitHub-centered bundle and a specialist platform. Choose the GitHub-centered route when repositories, identities, pull requests, and CI already live in GitHub and the priority is lower operational overhead. Evaluate a specialist tool such as Semgrep, Snyk, or Black Duck when you have a concrete gap: multiple source-control systems, a required language coverage gap, deeper software-composition governance, or a security team that needs central policy independent of a single forge.

Do not buy Semgrep, Snyk, Black Duck, and GitHub Advanced Security by default. Create a one-page coverage sheet first: source authority, dependency authority, secret authority, workflow authority, artifact authority, deployment authority. Empty cells identify investments; duplicate cells identify candidates to retire.

Work through one release path, not six product demos

Consider a Node.js API that publishes a container image after a pull request merges into main. A useful security design makes a decision at every handoff.

  1. A developer adds a package to package.json. Dependency review identifies the change in the pull request, while the chosen SCA authority determines whether a known vulnerability or license rule blocks merge.
  2. CodeQL or the chosen SAST authority analyzes the changed source. A finding is attached to the pull request rather than discovered days later in a separate dashboard.
  3. Gitleaks checks the branch. If it finds a cloud key, the fix is not merely deleting the line: revoke or rotate the credential because Git history may already contain it.
  4. Zizmor checks the workflow edit. The team reviews changes to .github/workflows as security-sensitive changes, not as ordinary YAML maintenance.
  5. The release workflow builds a specific image digest, generates an SBOM, and publishes both to the registry or release record. Deployment uses the digest, not a moving tag.
  6. The deployment job requests a short-lived cloud identity through OIDC and targets a protected production environment. No static cloud access key needs to sit in repository secrets for that deployment path.

This sequence reveals why scanner count is the wrong metric. The dependency scanner makes a merge decision. The workflow control limits who can alter the build. Artifact controls answer what was built. OIDC and environment protection determine what can reach production.

Build the minimum viable stack this week

Start with one repository that deploys something real. Do not begin by turning on every available alert across the organization; begin by making one release path explainable from pull request to production.

  1. List the repository’s current controls under the six headings: source, dependencies, secrets, workflow behavior, artifacts, and deployment.
  2. Mark each control as blocked, detected only, or uncovered. “Detected only” means someone receives an alert but a release can still proceed without an explicit decision.
  3. Enable a single required source check, a single dependency gate, and a secret scan. Assign an owner for triage before making any check blocking.
  4. Add workflow-file review and set explicit GitHub Actions token permissions. Review every workflow that has package publishing, repository write access, or cloud access.
  5. Replace long-lived cloud deployment secrets with GitHub Actions OIDC where your cloud provider and workflow support it.
  6. Generate and retain an SBOM for the next release artifact. This is the first step toward proving what was deployed instead of reconstructing it after an incident.

Finally, schedule a 30-minute quarterly overlap review. For every scanner, name the pipeline control it owns, the required check it produces, the person who triages it, and the condition under which it can be removed. If two tools cannot be distinguished by those four answers, keep one and spend the saved budget on the control your pipeline still lacks.