Skip to main content
Technology & EngineeringDevsecops Pipeline159 lines

SAST and DAST Integration in CI/CD

Integrate static and dynamic application security testing into the CI/CD

Quick Summary18 lines
Most security tooling is run at the wrong time — at the end of a release cycle, by a separate security team, on a code base that is too large to reason about. Move it left: into the developer's PR, before the merge, with feedback loops measured in minutes. That's what DevSecOps is. The pipeline is where you build the discipline.

## Key Points

1. **False-positive rate**. The lower, the better. Engineers ignore high-FP tools and the security value drops to zero.
2. **Language coverage**. Match your stack. A great tool for Java is useless if you write Go.
3. **CI integration**. Plain CLI that runs in any pipeline beats a SaaS-only black box. You want to be able to run it locally too.
4. **Findings model**. Per-rule, per-file, per-line, with severity and explanation. The finding has to be readable by an engineer who didn't run it.
- New findings in the diff: blocking.
- Existing findings unchanged: not blocking; tracked but not gating.
- Existing findings increasing in severity: blocking.
- On merge to main, against staging.
- Nightly or weekly, against production-like data.
- Optionally, on PRs that change auth, sessions, or user-facing endpoints (gated by labels or paths).
- Quick scans (10–15 minutes) on every PR that touches relevant code paths.
- Deep scans (1–4 hours) nightly or weekly.
skilldb get devsecops-pipeline-skills/SAST and DAST Integration in CI/CDFull skill: 159 lines
Paste into your CLAUDE.md or agent config

Most security tooling is run at the wrong time — at the end of a release cycle, by a separate security team, on a code base that is too large to reason about. Move it left: into the developer's PR, before the merge, with feedback loops measured in minutes. That's what DevSecOps is. The pipeline is where you build the discipline.

SAST: Static Application Security Testing

SAST tools analyze source code without running it. They find injection vulnerabilities, hardcoded secrets, insecure cryptographic patterns, and known-vulnerable dependencies. The good ones produce actionable findings; the bad ones drown the developer in noise.

Pick a SAST tool by:

  1. False-positive rate. The lower, the better. Engineers ignore high-FP tools and the security value drops to zero.
  2. Language coverage. Match your stack. A great tool for Java is useless if you write Go.
  3. CI integration. Plain CLI that runs in any pipeline beats a SaaS-only black box. You want to be able to run it locally too.
  4. Findings model. Per-rule, per-file, per-line, with severity and explanation. The finding has to be readable by an engineer who didn't run it.

Run SAST on every PR. The check is:

  • New findings in the diff: blocking.
  • Existing findings unchanged: not blocking; tracked but not gating.
  • Existing findings increasing in severity: blocking.

This policy avoids the common failure where SAST is enabled, finds 4,000 historical issues, blocks every PR, and the team disables it within a week. By gating only on the diff, you stop the bleeding without requiring a remediation sprint first.

DAST: Dynamic Application Security Testing

DAST tools test the running application — they crawl, fuzz, and probe for vulnerabilities that are visible only at runtime. SQL injection, XSS, broken auth flows, exposed admin endpoints. DAST complements SAST; it does not replace it.

DAST runs against a deployed environment, typically staging or a per-PR preview environment. Run it:

  • On merge to main, against staging.
  • Nightly or weekly, against production-like data.
  • Optionally, on PRs that change auth, sessions, or user-facing endpoints (gated by labels or paths).

DAST is slower than SAST. A full DAST scan can take 30 minutes to several hours. Time it:

  • Quick scans (10–15 minutes) on every PR that touches relevant code paths.
  • Deep scans (1–4 hours) nightly or weekly.
  • Exhaustive scans pre-release.

Secrets Detection

Distinct from SAST: scan every commit for accidentally checked-in secrets. AWS keys, Stripe keys, OAuth tokens, private keys. The good tools recognize patterns specific to providers (AKIAIOSFODNN... is an AWS access key; sk_live_... is a Stripe live key).

Secrets detection runs:

  • On every PR (block if new secret detected).
  • On every push to main (in case of force-push or rebase).
  • On the entire git history, periodically — to catch secrets that have been historic but never triggered the per-PR scan.

When a secret is detected, the response is two-step:

  1. Block the merge. The secret cannot land.
  2. Rotate the secret. Even if the PR was never merged, treat the secret as compromised. Rotate it. Audit access logs. The git history might have been pushed somewhere.

Make the rotation automatic where possible — your secrets manager exposes APIs to revoke and reissue. The detection tool fires a webhook that triggers the rotation. Faster than the manual playbook.

Dependency Scanning

Run dependency scanning on every PR and nightly:

  • New dependencies added: flag if they have known CVEs.
  • Existing dependencies: flag if a CVE was published since last scan.
  • Dependency licenses: flag any that conflict with your release license.

The findings are noisy. Most CVEs in transitive dependencies are not exploitable in your specific application. Triage:

  • Critical/high CVE in a dependency you call directly: fix immediately or accept with a documented mitigation.
  • Critical/high CVE in a transitive dependency: investigate exploitability. Often safe; sometimes not.
  • Medium/low CVE: track but don't block on it. Sweep monthly.

Your dependency scanner should integrate with your dependency-update tool (Dependabot, Renovate). The same PR that fixes the CVE is the PR that lands the new version.

Container Image Scanning

If you ship containers, scan them. The image layers contain not just your application but the base OS, runtime libraries, and any tooling pulled in by the build. Each layer can have CVEs.

Scan:

  • On every image build (PR + main).
  • Before every deploy (against the image about to be promoted).
  • Nightly against production images, in case a CVE was published for something you've been running.

Gate the deploy on:

  • Critical CVEs: blocking.
  • High CVEs in your direct application code: blocking.
  • High CVEs only in base layers: warning, with fast-track to fix.
  • Medium and below: tracked, not blocking.

Choose a minimal base image. Distroless or Alpine cuts the attack surface dramatically. Many of the high-volume CVE findings disappear when you stop running a full Debian userspace.

Infrastructure-as-Code Scanning

Terraform, CloudFormation, Kubernetes manifests get scanned for security misconfigurations: public S3 buckets, security groups open to 0.0.0.0/0, missing encryption, missing logging.

Run on every PR that touches IaC. The tools (Checkov, tfsec, Trivy) flag misconfigurations against benchmark frameworks (CIS, NIST). The findings are typically high signal — your team didn't intend to create a public bucket; the scanner catches the mistake before it ships.

Gating Policy

The policy that determines what blocks a PR:

  • Critical SAST or DAST finding new in the diff: block.
  • New secret committed: block, ideally also revoke automatically.
  • New direct dependency with critical CVE: block.
  • New IaC with public exposure: block unless explicitly approved.
  • High findings: warn; require sign-off from security or team lead.
  • Medium and below: tracked, not blocking.

Document the gating policy in the repository. Engineers know what will block them; security knows what's being enforced.

The policy needs an exemption process. A finding is sometimes a false positive; the team needs a way to mark it acknowledged and proceed. Without exemptions, engineers find ways to disable the scanners. The exemption process should be documented, tracked, and audited periodically.

Reporting

Aggregate findings across the org. A weekly dashboard:

  • New critical findings introduced this week.
  • Critical findings open more than 30 days.
  • Most-affected services.
  • Most-affected dependencies.

The dashboard gives security leadership an overview without requiring them to read every PR. It also gives engineering teams visibility into how their service compares.

Don't shame teams in the dashboard. The data is for prioritization, not for performance reviews. Teams that feel watched will hide findings; the dashboard becomes wrong.

False-Positive Discipline

False positives are the single largest threat to a SecDevOps program. The flow:

  1. Engineer hits a finding, investigates, decides it's a false positive.
  2. They want to ship.
  3. If exempting the finding is hard, they disable the scanner or commit a workaround.
  4. Real findings now slip through too.

To avoid this, make exemption easy and accountable. The engineer files the exemption with a one-paragraph rationale, links to the line, and the exemption is recorded for the security team to audit. Exemptions that are clearly false positives get accepted; ones that look concerning get reviewed.

Track the rate of false positives per tool. A tool consistently producing 30%+ FPs is hurting more than helping; tune it or replace it.

Anti-Patterns

Block all historical findings on day one. The team faces 4,000 issues. They disable the tool. Diff-only gating prevents this.

No exemption process. Engineers can't ship around false positives, so they disable the scanners. Document an exemption flow.

SAST without DAST. SAST sees code patterns but misses runtime issues like auth bypasses. Run both.

Secrets in commits go unrotated. Detection blocked the merge; you assume the secret is safe because it never landed. Rotate anyway.

Findings dashboard as performance review. Teams hide findings; data becomes wrong. Use the dashboard for prioritization only.

Heavy DAST on every PR. A 4-hour scan in the PR loop is unworkable. Time-box: quick scans on PRs, deep scans nightly.

Install this skill directly: skilldb add devsecops-pipeline-skills

Get CLI access →