Verified by Garnet Grid

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 TypeStageBlocking?Typical DurationCatches
Secrets detectionPre-commitYes (immediate)< 5sAPI keys, passwords in code
SASTBuildYes (PR gate)1-5 minSQL injection, XSS, insecure patterns
Dependency scanBuildYes (critical/high)30s-2 minKnown CVEs in libraries
Container scanPre-deployYes (critical)1-3 minOS-level CVEs, misconfigurations
DASTPost-deploy (staging)No (report only)10-60 minRuntime vulnerabilities, OWASP Top 10
Runtime detectionProductionAlert onlyContinuousActive 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

ScenarioAction
Secret not yet committedRemove and add to .gitignore
Secret committed but not pushedgit reset --soft HEAD~1, remove, recommit
Secret pushed to remoteRotate the secret immediately, then clean history with git filter-branch or BFG
Secret in productionRotate 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

ToolLanguagesFalse Positive RateSpeedCost
Semgrep30+Low (rule-based)Fast (< 2 min)Free (OSS) + paid rules
CodeQL10+MediumMedium (5-15 min)Free (GitHub)
SonarQube25+Medium-HighMediumFree (Community) + paid
Snyk Code10+LowFastFree 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

PracticeWhyHow
Pin exact versionsPrevent surprise updatespackage-lock.json, requirements.txt with ==
Automated dependency updatesStay current with patchesDependabot, Renovate (weekly PRs)
Audit before mergingDon’t add new vulnerabilitiesnpm audit in CI for every PR
Remove unused dependenciesReduce attack surfacedepcheck (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

LevelPracticesAutomationTypical Timeline
Level 1: ReactiveManual code reviews, annual pen testNoneStarting point
Level 2: FoundationalSAST in CI, dependency scanningPartial (build-time)Month 1-2
Level 3: IntegratedFull pipeline security, DAST in stagingFull pre-deploy gatesMonth 3-6
Level 4: ProactiveRuntime detection, chaos engineering, threat modelingFull + monitoringMonth 6-12
Level 5: OptimizedRed team exercises, security champions program, supply chain securityFull + adaptiveYear 2+

Security Tool Integration Points

Pipeline StageSecurity ActivityTool ExamplesBlock on Failure
Pre-commitSecret scanning, lintgit-secrets, GitleaksYes
BuildSAST (static analysis)Semgrep, SonarQube, CodeQLCritical only
BuildDependency scanning (SCA)Snyk, Dependabot, TrivyCritical and High
TestDAST (dynamic analysis)OWASP ZAP, Burp SuiteCritical only
PackageContainer scanningTrivy, Grype, Snyk ContainerCritical and High
DeployIaC scanningCheckov, tfsec, KICSCritical only
RuntimeRASP, WAFAWS WAF, Cloudflare, FalcoMonitor + 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. :::

Jakub Dimitri Rezayev
Jakub Dimitri Rezayev
Founder & Chief Architect • Garnet Grid Consulting

Jakub holds an M.S. in Customer Intelligence & Analytics and a B.S. in Finance & Computer Science from Pace University. With deep expertise spanning D365 F&O, Azure, Power BI, and AI/ML systems, he architects enterprise solutions that bridge legacy systems and modern technology — and has led multi-million dollar ERP implementations for Fortune 500 supply chains.

View Full Profile →