DevSecOps is the practice of building automated security testing into every stage of a CI/CD pipeline so vulnerabilities are caught by the pipeline itself rather than by a human audit or an attacker. In concrete terms it means running secret scanning and static analysis (SAST) on every commit, dependency scanning (SCA) and container scanning at build time, infrastructure-as-code checks before deploy, dynamic testing (DAST) against staging, and continuous monitoring in production — each check gating the next so insecure code cannot progress. The core principle is "shift left": find flaws when they are cheap, because a defect caught in code review costs a fraction of the same defect found in production.
That's the summary an AI gives you. What it can't show you is the sequence — which scan runs where, what it gates, and what a real, copy-pasteable pipeline looks like end to end. The animated flow below maps every scan to its pipeline stage, and the rest of this guide is a working GitHub Actions pipeline you can lift, stage by stage.
What Is DevSecOps?
DevSecOps integrates security practices into the DevOps workflow:
- Shift left - Find issues earlier in the development cycle
- Automate - Security checks run automatically, not manually
- Continuous - Every commit and deployment gets scanned
- Collaborative - Security is everyone's responsibility, not just the security team
The goal: deploy faster AND more securely by catching issues before they reach production.
The DevSecOps Pipeline
A mature DevSecOps pipeline includes security at every stage. The diagram below traces a commit through all six gates — a moving pulse follows the code from the developer's laptop to production, and each stage lists the scans that gate it:
Which Scan Finds What
The single most common DevSecOps mistake is treating these scan types as interchangeable. They find different classes of bug, at different points, and none of them substitutes for another. Use this to decide what to add and where it runs:
| Scan | What it inspects | Finds | Runs at | Speed | Add it when |
|---|---|---|---|---|---|
| Secret scanning | Diffs & git history | Leaked keys, tokens, passwords | Pre-commit + push | Seconds | First — highest signal, zero ambiguity |
| SCA | Third-party dependencies | Known CVEs in libraries you imported | Build | Seconds–mins | First — most breaches start here |
| SAST | Your own source code | Injection, XSS, unsafe crypto in code you wrote | Build (per commit) | Mins | After secrets + SCA are stable |
| Container scan | Image layers & OS packages | Vulnerable base images, OS CVEs | Package | Mins | Once you ship containers |
| IaC scan | Terraform/K8s/CloudFormation | Misconfig: open buckets, 0.0.0.0/0, no encryption | Deploy | Seconds | Once infra lives in code |
| DAST | The running application | Runtime/OWASP Top 10, auth & config flaws | Test (staging) | 10–30 min | Once you have a stable staging URL |
| Runtime / CSPM | Live production | Drift, exposed services, active exploitation | Monitor | Continuous | Once you're in production |
The rule of thumb: SAST finds bugs you wrote, SCA finds bugs you imported, DAST finds bugs that only appear when the app is live. You need all three, plus the infrastructure and runtime layers around them.
Stage 1: Secure Code (Pre-Commit)
Catch issues before code enters the repository.
Pre-Commit Hooks
Run security checks locally before commits:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: detect-private-key
- id: detect-aws-credentials
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
- repo: https://github.com/PyCQA/bandit
rev: 1.7.6
hooks:
- id: bandit
args: ["-r", "src/"]
- repo: https://github.com/aquasecurity/tfsec
rev: v1.28.4
hooks:
- id: tfsec
Secret Scanning
Prevent credentials from entering version control:
Gitleaks configuration:
# .gitleaks.toml
title = "Custom Gitleaks Config"
[[rules]]
id = "api-key"
description = "API Key"
regex = '''(?i)(api[_-]?key|apikey)['":\s]*[=:]\s*['"]?([a-z0-9]{32,})['"]?'''
tags = ["api", "key"]
[[rules]]
id = "aws-access-key"
description = "AWS Access Key"
regex = '''AKIA[0-9A-Z]{16}'''
tags = ["aws", "key"]
Stage 2: Static Analysis (Build)
Analyze code without executing it.
SAST (Static Application Security Testing)
Scan source code for vulnerabilities:
GitHub Actions example:
name: Security Scan
on: [push, pull_request]
jobs:
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Semgrep for multi-language SAST
- name: Semgrep Scan
uses: returntocorp/semgrep-action@v1
with:
config: >-
p/security-audit
p/owasp-top-ten
p/cwe-top-25
# CodeQL for deeper analysis
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: javascript, python
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
Popular SAST tools:
| Tool | Languages | Best For |
|---|---|---|
| Semgrep | 30+ languages | Speed, custom rules |
| CodeQL | 10+ languages | Deep analysis, GitHub integration |
| SonarQube | 25+ languages | Quality + security |
| Snyk Code | 10+ languages | Developer experience |
| Checkmarx | 25+ languages | Enterprise, compliance |
SCA (Software Composition Analysis)
Scan dependencies for known vulnerabilities:
- name: Dependency Check
uses: dependency-check/Dependency-Check_Action@main
with:
project: 'MyApp'
path: '.'
format: 'SARIF'
args: >-
--failOnCVSS 7
--enableRetired
- name: Snyk Dependencies
uses: snyk/actions/node@master
with:
args: --severity-threshold=high
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
What SCA finds:
- Known CVEs in dependencies
- Outdated packages
- License compliance issues
- Transitive dependency risks
Stage 3: Container Security (Package)
Secure container images before they ship.
Image Scanning
container-scan:
runs-on: ubuntu-latest
steps:
- name: Build Image
run: docker build -t myapp:${{ github.sha }} .
- name: Trivy Scan
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1'
- name: Grype Scan
uses: anchore/scan-action@v3
with:
image: 'myapp:${{ github.sha }}'
fail-build: true
severity-cutoff: high
Image Signing
Ensure only trusted images deploy:
- name: Sign Image
run: |
cosign sign --key env://COSIGN_KEY \
${{ env.REGISTRY }}/myapp:${{ github.sha }}
env:
COSIGN_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
Stage 4: Infrastructure Security (Deploy)
Scan infrastructure configurations before deployment.
IaC Scanning
infrastructure-scan:
runs-on: ubuntu-latest
steps:
- name: Checkov IaC Scan
uses: bridgecrewio/checkov-action@master
with:
directory: terraform/
framework: terraform
output_format: sarif
- name: KICS Scan
uses: checkmarx/kics-github-action@v1.7.0
with:
path: ./
fail_on: high
output_formats: 'sarif'
Kubernetes Manifest Scanning
- name: Kubesec Scan
uses: controlplaneio/kubesec-action@v0.0.2
with:
input: k8s/deployment.yaml
- name: Polaris Audit
run: |
polaris audit --audit-path ./k8s/ \
--format json \
--set-exit-code-on-danger
Stage 5: Dynamic Testing (Test)
Test running applications for vulnerabilities.
DAST (Dynamic Application Security Testing)
Scan running applications for OWASP Top 10 issues:
dast:
runs-on: ubuntu-latest
steps:
- name: Start Application
run: docker-compose up -d
- name: Wait for App
run: sleep 30
- name: ZAP Baseline Scan
uses: zaproxy/action-baseline@v0.10.0
with:
target: 'http://localhost:8080'
rules_file_name: '.zap/rules.tsv'
- name: ZAP Full Scan
uses: zaproxy/action-full-scan@v0.8.0
with:
target: 'http://localhost:8080'
API Security Testing
- name: API Security Test
run: |
# Postman/Newman for API tests
newman run api-security-tests.json \
--environment staging.json \
--reporters cli,junit
# OWASP Juice Shop example
nuclei -u http://localhost:8080 \
-t api/ \
-severity critical,high
Stage 6: Runtime Security (Monitor)
Continuous monitoring after deployment.
Security Monitoring Integration
# Send findings to SIEM
- name: Export to SIEM
run: |
# Convert SARIF to your SIEM format
cat results.sarif | jq '.runs[].results[]' | \
while read finding; do
curl -X POST ${{ secrets.SIEM_WEBHOOK }} \
-H "Content-Type: application/json" \
-d "$finding"
done
Continuous Scanning
Schedule regular scans of deployed infrastructure:
name: Scheduled Security Scan
on:
schedule:
- cron: '0 2 * * *' # Daily at 2 AM
jobs:
scan-production:
runs-on: ubuntu-latest
steps:
- name: Scan Production Images
run: |
trivy image --severity HIGH,CRITICAL \
${{ secrets.REGISTRY }}/myapp:production
- name: Cloud Security Posture
run: |
prowler aws --severity high critical \
--output-formats json
Sample Complete Pipeline
name: DevSecOps Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
# Stage 1: Secret Scanning
secrets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Gitleaks
uses: gitleaks/gitleaks-action@v2
# Stage 2: SAST
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: p/security-audit
# Stage 3: SCA
sca:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Snyk
uses: snyk/actions/node@master
with:
args: --severity-threshold=high
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
# Stage 4: Container Scan
container:
needs: [secrets, sast, sca]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: docker build -t myapp:${{ github.sha }} .
- name: Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
exit-code: '1'
severity: 'CRITICAL,HIGH'
# Stage 5: IaC Scan
iac:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: terraform/
# Stage 6: Deploy (only if all scans pass)
deploy:
needs: [container, iac]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- name: Deploy to Production
run: echo "Deploying secure code..."
Metrics to Track
| Metric | Target |
|---|---|
| Mean Time to Remediate (MTTR) | < 7 days for critical |
| Vulnerabilities blocked pre-production | > 90% |
| False positive rate | < 10% |
| Pipeline pass rate | > 95% |
| Security scan coverage | 100% of deployments |
Frequently Asked Questions
How do I handle false positives?
False positives are inevitable. Create suppression files for known false positives, regularly review and update them, and track false positive rates as a metric. Most tools support inline comments to suppress specific findings.
Will security scans slow down my pipeline?
Well-designed security scans add 5-15 minutes to pipelines. Run scans in parallel, use incremental scanning where possible, and cache results. The time is worth it compared to fixing production vulnerabilities.
Should security block deployments?
Yes, for critical and high severity findings. Use a tiered approach: block critical issues, warn on medium issues, and log low issues for later review. Gradually increase strictness as your team matures.
How do I get developer buy-in for DevSecOps?
Make security frictionless. Provide clear remediation guidance, integrate findings into existing tools (IDE plugins, PR comments), and celebrate security wins. Developers adopt security when it's helpful, not punitive.
What's the most important security scan to add first?
Start with secret scanning and SCA—they have the highest signal-to-noise ratio and catch issues developers commonly miss. Add SAST next, then container scanning, then IaC scanning.
DevSecOps Rollout Checklist
Add these in order. Each row is a gate you can turn from "warn" to "block" once the false-positive rate settles. Do not try to enable everything at once — that is how teams end up disabling the whole pipeline.
- Week 1 — Secrets: Gitleaks pre-commit hook + repo-side secret scanning. Rotate anything it finds.
- Week 1 — Dependencies (SCA): Enable Dependabot/Snyk; fail build on high-severity CVEs.
- Week 2 — SAST: Add Semgrep with
p/security-audit; run diff-only on PRs to stay fast. - Week 3 — SBOM: Generate an SBOM (Syft/CycloneDX) on every build and store it as an artifact.
- Week 3 — Container scan: Trivy or Grype on the built image; block CRITICAL/HIGH.
- Week 4 — Image signing: Sign images with Cosign; verify signatures at deploy.
- Week 4 — IaC scan: Checkov/KICS over Terraform and Kubernetes manifests.
- Week 5 — DAST: ZAP baseline against staging on merge; full scan nightly.
- Week 6 — Runtime: Ship findings to your SIEM; schedule daily production image + CSPM scans.
- Ongoing — Gate tuning: Track false-positive rate; ratchet gates from warn to block as they stabilize.
Take Action
- Add secret scanning - Prevent credentials from entering your repository
- Enable dependency scanning - Catch known CVEs in your dependencies
- Scan container images - Check for vulnerabilities before deployment
- Implement IaC scanning - Catch misconfigurations in infrastructure code
- Track metrics - Measure MTTR, blocked vulnerabilities, and coverage
For more cloud security guidance, see our comprehensive guide: 30 Cloud Security Tips for 2026.
Need Help Implementing DevSecOps?
Our team helps organizations integrate security into CI/CD pipelines without slowing down deployments:
- DevSecOps Services: SAST/DAST integration, container security, SBOM generation, and compliance automation
- DevOps Consulting: CI/CD pipeline design, Kubernetes, and infrastructure as code
- Hire DevOps Engineers: Staff augmentation with security-minded DevOps professionals