CloudOpsGuide
devsecops

DevSecOps Pipeline: Security in CI/CD

Advanced
17 minutes
October 2026
CloudOpsGuide Team

DevSecOps Pipeline: Security in CI/CD

Build a security-first CI/CD pipeline with SAST, DAST, dependency scanning, container scanning, and secrets detection — from commit to production.

Table of Contents

Pipeline Security Layers

Commit ──► Pre-commit ──► SAST ──► Deps ──► Build ──► Container ──► DAST ──► Deploy
          (secrets)       scan      scan     image     scan         test     monitor

Each layer catches different threats — a complete pipeline layers them all.

Stage-by-Stage Security

1. Pre-Commit — Secrets Detection

Stop secrets before they enter the repo:

# Install gitleaks pre-commit hook
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
gitleaks git --pre-commit --staged --verbose
if [ $? -ne 0 ]; then
  echo "⚠️  Secret detected! Commit blocked."
  exit 1
fi
EOF
chmod +x .git/hooks/pre-commit

2. SAST — Static Analysis

Scan source code for vulnerabilities:

stage('SAST') {
    steps {
        sh 'semgrep scan --config auto . --sarif -o semgrep.sarif'
        sh 'sonar-scanner -Dsonar.projectKey=myapp -Dsonar.sources=.'
    }
}

3. Dependency Scanning

Check third-party packages for CVEs:

# npm
npm audit --audit-level=high

# Python
pip install safety && safety check

# Go
go list -m all | nancy sleuth

# Multi-language — Snyk
snyk test --all-projects

4. Container Scanning

Scan built images before pushing:

# Trivy — fastest option
trivy image myapp:latest --severity HIGH,CRITICAL

# Grype — alternative
grype myapp:latest --fail-on high

5. DAST — Dynamic Testing

Test the running application:

# OWASP ZAP baseline scan
docker run -t owasp/zap2docker-stable zap-baseline.py \
  -t http://staging.example.com -r zap-report.html

6. Secrets in CI/CD

# Scan repo history for leaked secrets
gitleaks git --verbose .
trufflehog git file://. --only-verified

Complete Pipeline Example

pipeline {
    agent any

    stages {
        stage('Checkout') {
            steps { checkout scm }
        }

        // Stage 1: Secrets Scan
        stage('Secrets Scan') {
            steps {
                sh 'gitleaks git --verbose . || true'
                sh 'trufflehog git file://. --only-verified || true'
            }
        }

        // Stage 2: SAST
        stage('SAST') {
            parallel {
                stage('Semgrep') {
                    steps {
                        sh 'semgrep scan --config auto . --sarif -o semgrep.sarif || true'
                    }
                }
                stage('SonarQube') {
                    steps {
                        sh 'sonar-scanner -Dsonar.projectKey=myapp -Dsonar.sources=. || true'
                    }
                }
            }
        }

        // Stage 3: Dependencies
        stage('Dependency Scan') {
            steps {
                sh 'npm audit --audit-level=high || true'
                sh 'snyk test --severity-threshold=high || true'
            }
        }

        // Stage 4: Build
        stage('Build') {
            steps {
                sh 'docker build -t myapp:${BUILD_NUMBER} .'
            }
        }

        // Stage 5: Container Scan
        stage('Container Scan') {
            steps {
                sh '''
                    trivy image myapp:${BUILD_NUMBER} \
                      --severity HIGH,CRITICAL \
                      --exit-code 0 \
                      -o trivy-report.txt
                '''
            }
        }

        // Stage 6: Deploy to Staging
        stage('Deploy Staging') {
            when { branch 'main' }
            steps {
                sh 'kubectl apply -f k8s/staging/ -n staging'
            }
        }

        // Stage 7: DAST
        stage('DAST') {
            when { branch 'main' }
            steps {
                sh '''
                    docker run --rm -t owasp/zap2docker-stable zap-baseline.py \
                      -t http://staging.example.com \
                      -r zap-report.html || true
                '''
            }
        }

        // Stage 8: Security Gate
        stage('Security Gate') {
            steps {
                script {
                    // Check results and fail pipeline if critical issues found
                    def critical = sh(
                        script: 'grep -c "CRITICAL" trivy-report.txt || true',
                        returnStdout: true
                    ).trim() as int

                    if (critical > 0) {
                        error("${critical} critical vulnerabilities found — deployment blocked")
                    }
                }
            }
        }

        // Stage 9: Deploy Production
        stage('Deploy Production') {
            when { branch 'main' }
            input { message 'Deploy to production?' }
            steps {
                sh 'kubectl apply -f k8s/production/ -n production'
            }
        }
    }

    post {
        always {
            archiveArtifacts artifacts: '**/*.sarif,**/*.html,**/*.txt', allowEmptyArchive: true
        }
    }
}

Tool Selection Matrix

LayerRecommendedAlternative
SecretsGitleaks, TruffleHogGitGuardian
SASTSemgrep, SonarQubeCheckmarx, CodeQL
DependenciesSnyk, npm auditDependabot, Renovate
ContainerTrivyGrype, Clair
DASTOWASP ZAPBurp Suite, Nikto
IaCCheckov, tfsecTerrascan, KICS
LicenseFOSSA, ScanCodeSnyk License

Quality Gates

Block on Critical Findings

// Only pass if no critical issues
stage('Security Gate') {
    steps {
        script {
            def criticals = sh(
                script: 'jq "[.Results[] | select(.Vulnerabilities[]?.Severity == \"CRITICAL\")] | length" trivy-results.json',
                returnStdout: true
            ).trim() as int

            if (criticals > 0) {
                error("${criticals} critical vulnerabilities — deploy blocked")
            }
        }
    }
}

Warning vs Blocking

SeverityAction
CRITICALBlock pipeline, alert team
HIGHBlock production, warn staging
MEDIUMWarn, don't block
LOWLog for tracking
// Smart gate: block prod on HIGH+, warn staging
if (params.ENVIRONMENT == 'prod' && findings.HIGH > 0) {
    error("HIGH+ findings in production build")
}

Best Practices

1. Shift Left — Scan Early

Cost of fixing a bug:
  Pre-commit: £0    ← cheapest
  CI build:   £10
  Staging:    £100
  Production: £1000+ ← most expensive

2. Baseline Before Blocking

# First run: accept existing issues
semgrep scan --config auto . --baseline-commit main
# Only flag NEW issues going forward

3. Automate Remediation

# Auto-fix what's fixable
npm audit fix --force
terraform fmt
eslint --fix .

4. Scan the Pipeline Itself

# Checkov for Terraform
checkov -d terraform/

# tfsec
tfsec terraform/

# Kubesec for K8s
kubesec scan k8s/

5. Supply Chain Security

# Verify image signatures
cosign verify myregistry/myapp:latest --key cosign.pub

# Generate SBOM
syft packages myapp:latest -o spdx-json > sbom.json

# Scan SBOM for vulnerabilities
grype sbom:sbom.json

Metrics That Matter

  • MTTR (Mean Time to Remediate) — how fast critical findings get fixed
  • Coverage — % of code/images scanned
  • False Positive Rate — tune rules quarterly
  • Escape Rate — vulnerabilities found in prod vs caught earlier

Related Articles


Last Updated: October 2026
Author: CloudOpsGuide Team
Difficulty: Advanced
Estimated Reading Time: 17 minutes