Home/Blog/DevSecOps Pipeline: How to Build Security into CI/CD
Cloud Security

DevSecOps Pipeline: How to Build Security into CI/CD

Learn how to integrate security into your CI/CD pipeline. This guide covers SAST, DAST, SCA, container scanning, and security automation for DevSecOps teams.

By InventiveHQ Team
DevSecOps Pipeline: How to Build Security into CI/CD

DevSecOps isn't about slowing down releases with security gates—it's about finding vulnerabilities earlier when they're cheaper to fix. A bug found in production costs 100x more to remediate than one caught in development.

This guide shows how to build security into every stage of your CI/CD pipeline without sacrificing deployment velocity.


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:

[Code] → [Build] → [Test] → [Deploy] → [Monitor]
   ↓        ↓         ↓         ↓          ↓
 SAST     SCA      DAST      IaC      Runtime
 Secrets  Container  API     Config    SIEM
 Linting  Signing   Pentest  Policy    Alerts

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:

ToolLanguagesBest For
Semgrep30+ languagesSpeed, custom rules
CodeQL10+ languagesDeep analysis, GitHub integration
SonarQube25+ languagesQuality + security
Snyk Code10+ languagesDeveloper experience
Checkmarx25+ languagesEnterprise, 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/[email protected]
      with:
        path: ./
        fail_on: high
        output_formats: 'sarif'

Kubernetes Manifest Scanning

- name: Kubesec Scan
  uses: controlplaneio/[email protected]
  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/[email protected]
      with:
        target: 'http://localhost:8080'
        rules_file_name: '.zap/rules.tsv'

    - name: ZAP Full Scan
      uses: zaproxy/[email protected]
      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

MetricTarget
Mean Time to Remediate (MTTR)< 7 days for critical
Vulnerabilities blocked pre-production> 90%
False positive rate< 10%
Pipeline pass rate> 95%
Security scan coverage100% 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.


Take Action

  1. Add secret scanning - Prevent credentials from entering your repository
  2. Enable dependency scanning - Catch known CVEs in your dependencies
  3. Scan container images - Check for vulnerabilities before deployment
  4. Implement IaC scanning - Catch misconfigurations in infrastructure code
  5. Track metrics - Measure MTTR, blocked vulnerabilities, and coverage

For more cloud security guidance, see our comprehensive guide: 30 Cloud Security Tips for 2026.

Let's turn this knowledge into action

Get a free 30-minute consultation with our experts. We'll help you apply these insights to your specific situation.