On this page
  1. What you’ll build
  2. Step 1 — Add secret scanning
  3. Step 2 — Add dependency scanning
  4. Step 3 — Add static analysis (SAST)
  5. Step 4 — Decide what blocks a merge
  6. Where AI coding assistants get this wrong
  7. Checklist
  8. FAQ
    1. What is the difference between SAST and dependency scanning?
    2. Should scans block merges?
    3. Is Gitleaks the only secret scanner?
  9. Related topics
  10. Sources
tutorial

How to Add Security Scanning to Your CI/CD Pipeline

Add secret, dependency, and SAST scanning to a GitHub Actions pipeline. A practical tutorial with working workflow YAML.

Quick answer

  • Add three scanners to CI/CD: secrets (Gitleaks), dependencies, and static analysis (Semgrep or CodeQL).
  • Each runs on every pull request and fails the build on critical findings.
  • The result is that a generated commit shipping a secret or a SQL injection gets caught before merge.

What you’ll build

Security scanning for a GitHub Actions pipeline, layered on top of the CI workflow from the GitHub Actions tutorial. Three checks run on every pull request: secret detection, dependency vulnerability scanning, and static analysis.

Step 1 — Add secret scanning

Add a job that runs Gitleaks:

  secrets:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

How to verify it worked: push a commit containing a fake secret like AKIAIOSFODNN7EXAMPLE, open a pull request, and confirm the secrets job fails with the finding.

Step 2 — Add dependency scanning

For a Node.js project, use npm audit (or a dedicated scanner like Trivy for broader coverage):

  deps:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npm audit --audit-level=high

How to verify it worked: npm audit exits non-zero when a high-severity vulnerability exists, failing the job.

Step 3 — Add static analysis (SAST)

Add Semgrep, which scans source code for vulnerability patterns:

  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: semgrep/semgrep-action@v1
        with:
          config: p/default

How to verify it worked: introduce a classic flaw (a raw SQL query built with string concatenation) and confirm Semgrep flags it in the pull request.

Step 4 — Decide what blocks a merge

Start by failing on secrets and high-severity dependency issues, and reporting (not blocking) on everything else. Over-blocking produces alert fatigue and skipped checks; under-blocking defeats the point. Revisit the policy as the noise settles.

Where this bites vibecoders

Security scanning is the safety net for AI-generated code: the assistant won’t remember your team’s security rules, but the pipeline enforces them every time. The trap is turning on every scanner at once, seeing a wall of findings, and disabling them. Start with secrets plus one more check, tune the noise, then expand.

Where AI coding assistants get this wrong

  • Pasting scanner jobs with action versions or config keys that don’t exist.
  • Wiring scans to run only on main, so problems surface after merge instead of before.
  • Configuring every check to block, guaranteeing alert fatigue and eventual disablement.
  • Scanning but not acting: findings with no triage or fix step are decoration.

Checklist

  • Run scans on every pull request, not just on main.
  • Fail on secrets and high-severity findings; report the rest.
  • Verify each scanner actually catches a planted test issue.
  • Triage findings and fix or suppress them deliberately.
  • Revisit thresholds as noise drops.

FAQ

What is the difference between SAST and dependency scanning?

SAST analyzes your source code for vulnerability patterns (SQL injection, XSS). Dependency scanning checks the third-party libraries you import for known CVEs. They catch different problems and belong together. See What Is SAST?.

Should scans block merges?

High-confidence, high-impact findings (leaked secrets, critical CVEs) should block. Noisier checks should report first, then block once tuned. A pipeline that blocks on everything gets bypassed; one that blocks on nothing is theater.

Is Gitleaks the only secret scanner?

No. Alternatives include TruffleHog and the built-in GitHub secret scanning. Gitleaks is a common choice because it’s open source and works locally and in CI.

Sources

Share: