How to Implement DevSecOps: Pipeline Security Step by Step
Integrate security into your CI/CD pipeline. Covers SAST, DAST, dependency scanning, container scanning, secrets detection, and compliance gates.
Security as an afterthought is a breach waiting to happen. DevSecOps shifts security left — making it part of every commit, build, and deploy. The cost of fixing a vulnerability in production is 30x more expensive than catching it during development. This guide shows you exactly where to add each security check in your pipeline, with working configurations you can deploy today.
The core principle: make security automatic and fast. If a security check takes 20 minutes and blocks the build, developers will find ways around it. If it runs in 2 minutes and provides clear, actionable feedback, they’ll fix issues as naturally as they fix failing tests.
The DevSecOps Pipeline
Commit → Build → Test → Security Scan → Deploy → Monitor
│ │ │ │ │ │
Secrets SAST Unit Dependency Container Runtime
Scan Scan Tests Scan Scan Detection
Scan Timing and Impact
| Scan Type | Stage | Blocking? | Typical Duration | Catches |
|---|---|---|---|---|
| Secrets detection | Pre-commit | Yes (immediate) | < 5s | API keys, passwords in code |
| SAST | Build | Yes (PR gate) | 1-5 min | SQL injection, XSS, insecure patterns |
| Dependency scan | Build | Yes (critical/high) | 30s-2 min | Known CVEs in libraries |
| Container scan | Pre-deploy | Yes (critical) | 1-3 min | OS-level CVEs, misconfigurations |
| DAST | Post-deploy (staging) | No (report only) | 10-60 min | Runtime vulnerabilities, OWASP Top 10 |
| Runtime detection | Production | Alert only | Continuous | Active exploitation, anomalies |
Step 1: Secrets Detection (Pre-Commit)
Catch secrets before they ever reach the repository. Once a secret hits a commit, it’s in the Git history forever (even if you delete the file).
1.1 Install and Configure
# Install gitleaks (general purpose, actively maintained)
brew install gitleaks
# Create .gitleaks.toml configuration
cat > .gitleaks.toml << 'EOF'
title = "Custom Gitleaks Config"
[[rules]]
id = "api-key-generic"
description = "Generic API Key"
regex = '''(?i)api[_-]?key\s*[:=]\s*['"]?([a-zA-Z0-9]{32,})['"]?'''
tags = ["key", "api"]
[[rules]]
id = "jwt-token"
description = "JSON Web Token"
regex = '''eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}'''
tags = ["jwt"]
[[rules]]
id = "private-key"
description = "Private Key"
regex = '''-----BEGIN (RSA |EC |DSA )?PRIVATE KEY-----'''
tags = ["key", "private"]
[allowlist]
paths = ['''\.test\.''', '''\.spec\.''', '''__tests__''', '''\.example''']
EOF
1.2 Add Pre-Commit Hook
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
# Install
pip install pre-commit
pre-commit install
# Run on all files (initial scan)
pre-commit run --all-files
What to Do When Secrets Are Found
| Scenario | Action |
|---|---|
| Secret not yet committed | Remove and add to .gitignore |
| Secret committed but not pushed | git reset --soft HEAD~1, remove, recommit |
| Secret pushed to remote | Rotate the secret immediately, then clean history with git filter-branch or BFG |
| Secret in production | Rotate within 1 hour, incident response triggered |
Step 2: Static Analysis — SAST (Build Stage)
SAST scans your source code for vulnerabilities without executing it. It catches patterns like SQL injection, XSS, and insecure deserialization.
GitHub Actions Integration
# .github/workflows/security.yml
name: Security Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Semgrep — fast, customizable SAST scanner
- name: Semgrep Scan
uses: returntocorp/semgrep-action@v1
with:
config: >-
p/security-audit
p/owasp-top-ten
p/javascript
p/python
# CodeQL (GitHub native — free for public repos)
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: javascript, python
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
SAST Tool Comparison
| Tool | Languages | False Positive Rate | Speed | Cost |
|---|---|---|---|---|
| Semgrep | 30+ | Low (rule-based) | Fast (< 2 min) | Free (OSS) + paid rules |
| CodeQL | 10+ | Medium | Medium (5-15 min) | Free (GitHub) |
| SonarQube | 25+ | Medium-High | Medium | Free (Community) + paid |
| Snyk Code | 10+ | Low | Fast | Free tier + paid |
Step 3: Dependency Scanning (Build Stage)
90% of your code is dependencies. A single vulnerable dependency can compromise your entire application.
dependency-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Trivy for comprehensive scanning (multi-ecosystem)
- name: Trivy FS Scan
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
severity: 'HIGH,CRITICAL'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy Results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
Manual Check (All Ecosystems)
# Node.js — npm audit
npm audit --production --audit-level=high
# Python — pip-audit
pip-audit --output json | jq '.[] | select(.fix_versions != [])'
# Go — govulncheck
govulncheck ./...
# .NET — dotnet
dotnet list package --vulnerable --include-transitive
# Java — OWASP Dependency Check
mvn org.owasp:dependency-check-maven:check
# Ruby — bundler-audit
bundle audit check --update
Dependency Management Best Practices
| Practice | Why | How |
|---|---|---|
| Pin exact versions | Prevent surprise updates | package-lock.json, requirements.txt with == |
| Automated dependency updates | Stay current with patches | Dependabot, Renovate (weekly PRs) |
| Audit before merging | Don’t add new vulnerabilities | npm audit in CI for every PR |
| Remove unused dependencies | Reduce attack surface | depcheck (Node), pip-extra-reqs (Python) |
Step 4: Container Security Scanning (Pre-Deploy)
container-scan:
runs-on: ubuntu-latest
needs: [build]
steps:
- name: Build Container
run: docker build -t myapp:${{ github.sha }} .
- name: Trivy Container Scan
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
severity: 'HIGH,CRITICAL'
exit-code: '1' # Fail the pipeline on HIGH/CRITICAL
- name: Dockle — Dockerfile Best Practices
uses: erzz/dockle-action@v1
with:
image: 'myapp:${{ github.sha }}'
failure-threshold: warn
Dockerfile Hardening
# Use distroless or minimal base (fewer packages = fewer CVEs)
FROM cgr.dev/chainguard/node:latest
# Don't run as root (critical security requirement)
USER nonroot
# Set filesystem to read-only where possible
COPY --chown=nonroot:nonroot . /app
WORKDIR /app
# Multi-stage build — no build tools in production image
FROM node:20-slim AS builder
WORKDIR /build
COPY package*.json ./
RUN npm ci --production
COPY . .
RUN npm run build
FROM gcr.io/distroless/nodejs20
COPY --from=builder /build/dist /app
CMD ["/app/server.js"]
Step 5: Dynamic Application Security Testing — DAST (Post-Deploy)
DAST tests your running application, finding vulnerabilities that SAST can’t detect (misconfigured headers, authentication bypasses, CORS issues).
dast:
runs-on: ubuntu-latest
needs: [deploy-staging]
steps:
- name: OWASP ZAP Scan
uses: zaproxy/action-full-scan@v0.7.0
with:
target: 'https://staging.myapp.com'
rules_file_name: '.zap/rules.tsv'
allow_issue_writing: false
Step 6: Compliance Gates
Block deployments that don’t meet security standards.
compliance-gate:
runs-on: ubuntu-latest
needs: [sast, dependency-scan, container-scan]
steps:
- name: Check Security Results
run: |
CRITICAL=$(cat security-results.json | jq '.critical_count')
HIGH=$(cat security-results.json | jq '.high_count')
if [ "$CRITICAL" -gt 0 ]; then
echo "❌ BLOCKED: $CRITICAL critical vulnerabilities found"
exit 1
fi
if [ "$HIGH" -gt 5 ]; then
echo "⚠️ WARNING: $HIGH high vulnerabilities — review required"
exit 1
fi
echo "✅ Security gate passed"
DevSecOps Maturity Model
| Level | Practices | Automation | Typical Timeline |
|---|---|---|---|
| Level 1: Reactive | Manual code reviews, annual pen test | None | Starting point |
| Level 2: Foundational | SAST in CI, dependency scanning | Partial (build-time) | Month 1-2 |
| Level 3: Integrated | Full pipeline security, DAST in staging | Full pre-deploy gates | Month 3-6 |
| Level 4: Proactive | Runtime detection, chaos engineering, threat modeling | Full + monitoring | Month 6-12 |
| Level 5: Optimized | Red team exercises, security champions program, supply chain security | Full + adaptive | Year 2+ |
Security Tool Integration Points
| Pipeline Stage | Security Activity | Tool Examples | Block on Failure |
|---|---|---|---|
| Pre-commit | Secret scanning, lint | git-secrets, Gitleaks | Yes |
| Build | SAST (static analysis) | Semgrep, SonarQube, CodeQL | Critical only |
| Build | Dependency scanning (SCA) | Snyk, Dependabot, Trivy | Critical and High |
| Test | DAST (dynamic analysis) | OWASP ZAP, Burp Suite | Critical only |
| Package | Container scanning | Trivy, Grype, Snyk Container | Critical and High |
| Deploy | IaC scanning | Checkov, tfsec, KICS | Critical only |
| Runtime | RASP, WAF | AWS WAF, Cloudflare, Falco | Monitor + Alert |
Shift-Left Security ROI
Finding and fixing security issues earlier is exponentially cheaper:
- Design phase: $500 to fix
- Development: $1,500 to fix
- Testing: $5,000 to fix
- Production: $25,000+ to fix (including incident response, customer notification, reputation)
Implementation Checklist
- Pre-commit hooks: gitleaks for secrets detection on every commit
- SAST: Semgrep or CodeQL running on every PR (blocking)
- Dependency scanning: Trivy or npm audit on every build
- Automated dependency updates: Dependabot or Renovate (weekly PRs)
- Container scanning: Trivy + Dockle on every image build
- Dockerfile hardened: non-root user, distroless base, multi-stage build
- DAST: OWASP ZAP against staging on every deploy
- Compliance gate blocking deployments with critical/high findings
- Security results uploaded to SARIF dashboard for visibility
- Incident response runbook for security findings documented
- Quarterly security review cadence with engineering leadership
- Secret rotation procedure documented and tested
:::note[Source] This guide is derived from operational intelligence at Garnet Grid Consulting. For CI/CD security audits, visit garnetgrid.com. :::