Shifting Security Left: DevSecOps Without the Overhead

Shifting Security Left: DevSecOps Without the Overhead

DevSecOps applies the shift-left principle to security: instead of a security review at the end of a release cycle, security checks run continuously throughout development. This post covers the practical tools and pipeline configuration for shifting security left — catching vulnerabilities before they reach production.

Key Takeaways

Security review at release time is too late. A vulnerability discovered in a production penetration test requires emergency patching, incident response, and often customer notification. The same vulnerability caught in a pull request requires a code fix.

Secrets detection is the highest-ROI first step. A leaked API key or database credential in a git commit costs more than all other security issues combined. Secrets scanners run in seconds and prevent the most catastrophic class of security incident.

Dependency vulnerabilities are the most common attack vector. Most security incidents involve a known vulnerability in a third-party dependency, not a novel attack on custom code. Dependency scanning catches these in CI before deployment.

SAST and DAST are complementary, not interchangeable. SAST (static) catches code-level issues at author time. DAST (dynamic) tests a running application for runtime vulnerabilities. Both are necessary; neither is sufficient alone.

Security gates should block, not warn. A security finding that generates a warning doesn't get fixed. Critical and high severity findings must block merge. Warnings are for medium and low severity issues pending prioritization.

Security as a Shift-Left Problem

Traditional software development security looked like this: development teams build features, QA teams test functionality, and somewhere before release a security team runs a penetration test or code audit. If they find something serious, the release slips. If they don't find it, it ships to production and is discovered by attackers instead.

This model has a name: shift-right security. Every security check happens at the far right of the development timeline, close to release. The cost of findings is maximum — rework, schedule impact, potential breach.

DevSecOps — Development, Security, Operations — applies the shift-left principle to security. Security checks run as early as possible: in the IDE, on commit, on every pull request. The development team owns security checks the same way they own unit tests. The security team moves to an advisory and tooling role rather than a gatekeeper role.

The DevSecOps Toolchain

1. Secrets Detection (Author Time to CI)

The highest-ROI first step in any DevSecOps program is secrets detection. A leaked API key committed to a public repository is immediately harvested by bots that scan GitHub in real time. The damage from a leaked AWS credential — unauthorized compute charges, data exfiltration — can exceed the cost of all other security incidents combined.

Pre-commit secrets scanning:

pip install detect-secrets
detect-secrets scan > .secrets.baseline
# Add to pre-commit
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/Yelp/detect-secrets
    rev: v1.4.0
    hooks:
      - id: detect-secrets
        args: ['--baseline', '.secrets.baseline']

Alternatives:

  • Gitleaks — Fast, configurable, supports 150+ secret types
  • TruffleHog — Scans git history (important for secrets already committed)
  • GitHub Secret Scanning — Built-in, scans pushes to GitHub, free for public repos

In CI:

secrets-scan:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0  # Full history for TruffleHog
    - name: TruffleHog scan
      uses: trufflesecurity/trufflehog@main
      with:
        path: ./
        base: main
        head: HEAD

2. Dependency Vulnerability Scanning (CI)

The 2021 Log4Shell vulnerability affected millions of systems. The 2017 Equifax breach exploited a known Struts vulnerability that had been patched two months before the breach. In both cases, the vector was a known vulnerability in a dependency — not a novel attack on custom code.

Dependency scanning checks your package.json, requirements.txt, Gemfile, or equivalent against databases of known CVEs:

dependency-scan:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - name: Node.js audit
      run: npm audit --audit-level=high
    - name: Snyk scan
      uses: snyk/actions/node@master
      env:
        SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
      with:
        args: --severity-threshold=high

Tools by language:

  • Node.js: npm audit, Snyk, Socket.dev
  • Python: pip-audit, Safety, Snyk
  • Java: OWASP Dependency-Check, Snyk
  • Go: govulncheck, Nancy
  • Ruby: bundle-audit
  • Rust: cargo audit

Configure CI to fail on high and critical severity findings. Medium severity can produce warnings; low severity can be tracked separately.

3. SAST — Static Application Security Testing (CI)

SAST tools analyze source code for security vulnerabilities: SQL injection, XSS, insecure deserialization, path traversal, weak cryptography, dangerous function calls.

Semgrep (open source, multi-language):

sast:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - uses: returntocorp/semgrep-action@v1
      with:
        config: >-
          p/owasp-top-ten
          p/secrets
          p/sql-injection

CodeQL (GitHub-native):

analyze:
  runs-on: ubuntu-latest
  permissions:
    security-events: write
  steps:
    - uses: actions/checkout@v4
    - uses: github/codeql-action/init@v3
      with:
        languages: javascript, python
    - uses: github/codeql-action/analyze@v3

CodeQL results appear directly in GitHub's Security tab and in pull request checks. Findings can be dismissed with justification, creating an audit trail.

Language-specific SAST:

  • Bandit (Python) — 100+ security checks for common Python vulnerabilities
  • Brakeman (Rails) — Rails-specific security scanner
  • FindSecBugs (Java) — OWASP-aligned Java security scanner
  • Gosec (Go) — Go security scanner

4. DAST — Dynamic Application Security Testing (Staging Environment)

DAST tools test a running application for vulnerabilities that only appear at runtime: authentication bypass, business logic flaws, race conditions, session management issues.

DAST requires a deployed environment, so it runs later in the pipeline than SAST — typically against a staging or preview environment after deployment.

OWASP ZAP (open source):

dast:
  needs: deploy-staging
  runs-on: ubuntu-latest
  steps:
    - name: ZAP Baseline Scan
      uses: zaproxy/action-baseline@v0.10.0
      with:
        target: 'https://staging.yourdomain.com'
        rules_file_name: '.zap/rules.tsv'
        cmd_options: '-a'

ZAP baseline scan is passive (no attack attempts) — safe for staging environments. For authenticated scanning, use ZAP's full scan with authentication configuration.

Alternatives:

  • Burp Suite Enterprise — Commercial, comprehensive, widely used in security teams
  • Nuclei — Fast, template-based vulnerability scanner
  • Nikto — Web server scanner, free, basic but fast

5. Container and Infrastructure Scanning

If you ship Docker containers or infrastructure-as-code, scan those too:

Container scanning:

- name: Trivy scan
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: 'myapp:latest'
    severity: 'CRITICAL,HIGH'
    exit-code: '1'

Infrastructure-as-code scanning:

- name: Checkov IaC scan
  uses: bridgecrewio/checkov-action@master
  with:
    directory: terraform/
    framework: terraform

Trivy scans container images for OS-level CVEs, misconfigurations, and secrets. Checkov scans Terraform, CloudFormation, and Kubernetes manifests for security misconfigurations.

Building the Full DevSecOps Pipeline

A complete shift-left security pipeline looks like this:

[Author time]  → Secrets detection (pre-commit), IDE SAST warnings
[PR opened]    → Secrets scan, SAST, dependency scan (blocks merge on critical/high)
[Merge to main] → Full SAST, container scan, IaC scan
[Deploy staging] → DAST baseline scan
[Weekly]        → Full dependency audit, penetration test scheduling

This structure catches different vulnerability classes at different stages:

Stage Tool Catches
Author time Secrets scanner Hardcoded credentials
Author time IDE SAST Injection flaws, dangerous APIs
PR SAST SQL injection, XSS, weak crypto
PR Dependency scan Known CVEs in dependencies
Post-merge Container scan OS-level CVEs in base images
Staging DAST Runtime vulnerabilities

Cultural Shift: Who Owns Security?

The biggest barrier to DevSecOps adoption is cultural. Security scanning produces findings. Who owns those findings?

In a shift-left security model:

Development teams own findings from their code. A Semgrep finding in a pull request is the author's responsibility, the same as a failing unit test. The security team provides tooling and guidance; the dev team fixes the issue.

Security teams own policy and tooling. What tools run, what severity levels block merge, what false positive exceptions are allowed — this is security team territory. They're not reviewers of every PR; they're setting the rules.

Critical findings are non-negotiable. Critical severity findings from SAST, DAST, or dependency scans block release until fixed or formally accepted risk with documented justification.

Medium and low findings are tracked, not ignored. Create GitHub issues or Jira tickets for medium/low findings. Assign them to the team that owns the affected code. Review at the sprint planning level.

The Bottom Line

Shifting security left doesn't mean making developers into security experts. It means giving developers the tools to catch the most common security mistakes before they reach production — and making those tools run automatically so security becomes part of the normal development workflow.

The investment is modest: a few pipeline stages, a handful of open source tools, and a policy decision about which findings block merge. The alternative is discovering security vulnerabilities in production, which is much more expensive.

Start with secrets detection and dependency scanning — they're fast, low false positive, and address the most common attack vectors. Add SAST after that. Save DAST for when you have a staging environment to run it against.

Security quality, like functional quality, is cheapest when caught early.

Read more

Start now free