DevSecOps Guide 2026: Security in Every Stage of the Pipeline

Sanjeev SharmaSanjeev Sharma
4 min read

Advertisement

DevSecOps 2026: Shift Security Left

The average data breach costs $4.45 million and takes 277 days to identify. DevSecOps catches vulnerabilities before they reach production — at a fraction of the cost.

SAST: Static Code Analysis

# .github/workflows/security.yml
name: Security Scanning

on: [push, pull_request]

jobs:
  # CodeQL: Finds security vulnerabilities in code
  codeql:
    name: CodeQL Analysis
    runs-on: ubuntu-latest
    permissions:
      security-events: write

    strategy:
      matrix:
        language: ['javascript', 'typescript']

    steps:
      - uses: actions/checkout@v4

      - uses: github/codeql-action/init@v3
        with:
          languages: ${{ matrix.language }}
          queries: security-and-quality

      - uses: github/codeql-action/autobuild@v3

      - uses: github/codeql-action/analyze@v3
        with:
          category: '/language:${{ matrix.language }}'

Dependency Scanning

  # Check for known vulnerabilities in dependencies
  dependency-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: npm audit
        run: npm audit --audit-level=high
        # Fails if high or critical vulnerabilities found

      - name: Snyk dependency scan
        uses: snyk/actions/node@master
        with:
          args: --severity-threshold=high
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

      - name: OWASP Dependency Check
        uses: dependency-check/Dependency-Check_Action@main
        with:
          project: 'webcoderspeed'
          path: '.'
          format: 'HTML'
          args: >
            --failOnCVSS 7
            --enableRetired

      - uses: actions/upload-artifact@v4
        with:
          name: dependency-report
          path: reports/

Secrets Detection

  # Find accidental secrets committed to code
  secrets-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Full history for Gitleaks

      - name: Gitleaks - detect secrets
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: TruffleHog scan
        uses: trufflesecurity/trufflehog@main
        with:
          path: ./
          base: ${{ github.event.repository.default_branch }}
          extra_args: --debug --only-verified
# .gitleaks.toml — Custom rules
[[rules]]
description = "Custom API Key"
regex = '''(?i)webcoderspeed[_\-]?api[_\-]?key['":\s]+[a-zA-Z0-9]{20,}'''
tags = ["api", "custom"]

[allowlist]
paths = [".gitleaks.toml", "tests/"]
regexes = ["EXAMPLE_KEY", "YOUR_KEY_HERE"]

Container Security Scanning

  # Scan Docker images for vulnerabilities
  container-scan:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Trivy scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'ghcr.io/${{ github.repository }}:${{ github.sha }}'
          format: 'sarif'
          output: 'trivy-results.sarif'
          severity: 'CRITICAL,HIGH'
          exit-code: '1'  # Fail on critical/high

      - uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: 'trivy-results.sarif'
# Security hardening in Dockerfile
FROM node:20-alpine

# Don't run as root
RUN addgroup --system --gid 1001 nodejs && \
    adduser --system --uid 1001 nodeuser

# Install security updates
RUN apk update && apk upgrade && rm -rf /var/cache/apk/*

# Read-only filesystem
WORKDIR /app
COPY --chown=nodeuser:nodejs . .

USER nodeuser

# No new privileges
# Use: docker run --security-opt=no-new-privileges myapp

SBOM: Software Bill of Materials

  # Generate inventory of all dependencies
  sbom:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Generate SBOM with Syft
        uses: anchore/sbom-action@v0
        with:
          format: spdx-json
          output-file: sbom.spdx.json

      - uses: actions/upload-artifact@v4
        with:
          name: sbom
          path: sbom.spdx.json

Infrastructure Security

# Terraform: Security group — principle of least privilege
resource "aws_security_group" "api" {
  name = "api-sg"
  vpc_id = aws_vpc.main.id

  # Allow only HTTPS inbound
  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # Deny all other inbound by default

  # Allow all outbound (restrict for sensitive apps)
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# Never allow SSH from 0.0.0.0/0 in production
# Use AWS Systems Manager Session Manager instead

Security Checklist for Every PR

# .github/pull_request_template.md
## Security Checklist

- [ ] No secrets or API keys committed (Gitleaks passed)
- [ ] No new HIGH/CRITICAL vulnerabilities (npm audit passed)
- [ ] Input validation on all new API endpoints
- [ ] Authorization check for user-owned resources
- [ ] SQL queries use parameterized statements
- [ ] New dependencies reviewed for security
- [ ] Sensitive data not logged

Security is not a feature you add at the end — it's a discipline you practice throughout development. One leaked secret or unpatched vulnerability is all it takes.

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro