DevSecOpsCI/CDSecurity

Shifting Left: Integrating Security into CI/CD

Sven Nellemann
Jan 20248 min read

Introduction

The traditional approach to software security—bolting it on at the end of the development cycle—is fundamentally broken. When security vulnerabilities are discovered in production, the cost to fix them is exponentially higher than if they'd been caught during development. This is where "shifting left" comes in: moving security practices earlier in the software development lifecycle (SDLC).

In this article, I'll walk you through implementing a comprehensive security scanning pipeline that catches vulnerabilities before they reach production.

What Does "Shifting Left" Actually Mean?

The term comes from visualising the software development lifecycle as a timeline flowing left to right:

Planning → Development → Testing → Deployment → Production
   ←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←
         "Shifting Left" = Moving security HERE

Instead of waiting until the testing or deployment phase to think about security, we integrate security checks throughout—starting from the moment code is written.

The Security Scanning Stack

A robust CI/CD security pipeline typically includes several types of scanning:

1. Static Application Security Testing (SAST)

SAST tools analyse your source code without executing it, looking for patterns that indicate security vulnerabilities.

Popular Tools:

  • Semgrep - Fast, open-source, supports many languages
  • SonarQube - Comprehensive code quality and security
  • Snyk Code - Developer-friendly with IDE integration
  • CodeQL - GitHub's powerful semantic code analysis

Example: Semgrep in GitHub Actions

name: SAST Scan
on: [push, pull_request]

jobs:
  semgrep:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Run Semgrep
        uses: returntocorp/semgrep-action@v1
        with:
          config: >-
            p/security-audit
            p/secrets
            p/owasp-top-ten

2. Software Composition Analysis (SCA)

Most modern applications are built on open-source dependencies. SCA tools scan these dependencies for known vulnerabilities.

Popular Tools:

  • Snyk - Industry leader with excellent developer experience
  • Dependabot - Native to GitHub, automatic PRs for updates
  • OWASP Dependency-Check - Open-source, language-agnostic
  • Trivy - Fast, comprehensive, and free

Example: Dependency Scanning with Snyk

name: Dependency Scan
on: [push, pull_request]

jobs:
  snyk:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Run Snyk to check for vulnerabilities
        uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        with:
          args: --severity-threshold=high

3. Secret Detection

Accidentally committed secrets are one of the most common security incidents. Catching them before they're pushed is critical.

Popular Tools:

  • GitLeaks - Fast, configurable, great for CI/CD
  • TruffleHog - Entropy-based detection
  • detect-secrets - Yelp's auditable baseline approach
  • GitHub Secret Scanning - Native GitHub feature

Example: GitLeaks Pre-commit Hook

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.1
    hooks:
      - id: gitleaks

In CI/CD:

name: Secret Scan
on: [push, pull_request]

jobs:
  gitleaks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          
      - name: Run Gitleaks
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

4. Container Image Scanning

If you're deploying containers, scanning images for vulnerabilities in the base OS and installed packages is essential.

Popular Tools:

  • Trivy - Comprehensive, fast, and free
  • Grype - Anchore's open-source scanner
  • Snyk Container - Great integration with development workflow
  • Clair - CoreOS's original container scanner

Example: Trivy Container Scanning

name: Container Scan
on:
  push:
    branches: [main]

jobs:
  trivy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Build image
        run: docker build -t myapp:${{ github.sha }} .
        
      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: myapp:${{ github.sha }}
          format: 'sarif'
          output: 'trivy-results.sarif'
          severity: 'CRITICAL,HIGH'
          
      - name: Upload Trivy scan results
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: 'trivy-results.sarif'

5. Infrastructure as Code (IaC) Scanning

Your Terraform, CloudFormation, or Kubernetes manifests can contain security misconfigurations.

Popular Tools:

  • Checkov - Comprehensive IaC scanner
  • tfsec - Terraform-focused security scanner
  • KICS - Checkmarx's open-source IaC scanner
  • Terrascan - Policy as code for IaC

Example: Checkov for Terraform

name: IaC Scan
on: [push, pull_request]

jobs:
  checkov:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Run Checkov
        uses: bridgecrewio/checkov-action@master
        with:
          directory: terraform/
          framework: terraform
          soft_fail: false

Building a Complete Pipeline

Here's how to combine all these tools into a comprehensive security pipeline:

name: Security Pipeline
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  secrets:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  sast:
    runs-on: ubuntu-latest
    needs: secrets
    steps:
      - uses: actions/checkout@v4
      - uses: returntocorp/semgrep-action@v1
        with:
          config: p/security-audit

  sca:
    runs-on: ubuntu-latest
    needs: secrets
    steps:
      - uses: actions/checkout@v4
      - uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

  container:
    runs-on: ubuntu-latest
    needs: [sast, sca]
    steps:
      - uses: actions/checkout@v4
      - name: Build image
        run: docker build -t app:${{ github.sha }} .
      - uses: aquasecurity/trivy-action@master
        with:
          image-ref: app:${{ github.sha }}
          severity: CRITICAL,HIGH
          exit-code: 1

Handling Findings: The Developer Experience

Security scanning is only useful if developers act on the findings. Here's how to make that happen:

1. Fail Fast, But Not Too Fast

Start with warning-only mode, then gradually increase strictness.

2. Provide Context

Use SARIF format to integrate findings directly into the GitHub Security tab.

3. Enable Self-Service Fixes

Many tools provide auto-fix capabilities.

4. Create a Security Champion Programme

Designate developers in each team who triage security findings and help teammates.

Metrics That Matter

Track these metrics to measure your shift-left success:

MetricTargetWhy It Matters
Mean Time to Remediate (MTTR)< 7 days for high severityShows responsiveness
Vulnerability Escape Rate< 5%Measures pipeline effectiveness
False Positive Rate< 10%Indicates tool configuration quality
Developer Satisfaction> 4/5Security shouldn't slow you down

Common Pitfalls to Avoid

1. Alert Fatigue

Too many findings overwhelm developers. Start with critical/high severity only.

2. Blocking Everything

If your pipeline blocks every PR, developers will work around it.

3. No Baseline

Create a baseline of known issues and only block on new findings.

4. Ignoring Developer Feedback

Security tools are only useful if developers use them.

Conclusion

Shifting security left isn't just about adding tools to your pipeline—it's about creating a culture where security is everyone's responsibility. Start small, iterate based on feedback, and remember that the goal is to empower developers to write secure code, not to create barriers.

Next Steps

  1. Assess your current state: What security scanning do you have today?
  2. Pick one tool: Start with secret detection—it's fast and high-value
  3. Iterate: Add more scanning types over time
  4. Measure: Track your metrics and adjust based on data

Security is a journey, not a destination. Start shifting left today.


Have questions about implementing security in your CI/CD pipeline? Feel free to reach out—I'd love to help.