Shift-left security integrates security testing early in the software development lifecycle, catching vulnerabilities before they reach production. By embedding security into CI/CD pipelines, teams can identify and fix issues when they’re cheapest to remediate.
Shift-Left Security Stages
- Pre-commit: Secrets scanning, linting
- Build: SAST, dependency scanning
- Test: DAST, container scanning
- Deploy: IaC scanning, compliance checks
Pre-commit Hooks
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
- repo: https://github.com/hadolint/hadolint
rev: v2.12.0
hooks:
- id: hadolint-docker
- repo: https://github.com/bridgecrewio/checkov
rev: 3.0.0
hooks:
- id: checkov
args: ['--framework', 'terraform']
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: detect-private-key
- id: check-added-large-filesGitHub Actions Security Pipeline
name: Security Pipeline
on: [push, pull_request]
jobs:
secrets-scan:
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
steps:
- uses: actions/checkout@v4
- name: Run Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: p/default
dependency-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Snyk
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
container-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t app:${{ github.sha }} .
- name: Run Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: app:${{ github.sha }}
severity: CRITICAL,HIGH
exit-code: 1
iac-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: terraform/
soft_fail: falseGitLab CI Security
# .gitlab-ci.yml
include:
- template: Security/SAST.gitlab-ci.yml
- template: Security/Dependency-Scanning.gitlab-ci.yml
- template: Security/Container-Scanning.gitlab-ci.yml
- template: Security/Secret-Detection.gitlab-ci.yml
stages:
- build
- test
- security
- deploy
sast:
stage: security
variables:
SAST_EXCLUDED_PATHS: "spec, test, tests"
container_scanning:
stage: security
variables:
CS_SEVERITY_THRESHOLD: HIGH
dependency_scanning:
stage: security
variables:
DS_EXCLUDED_ANALYZERS: "gemnasium-python"Quality Gates
# SonarQube quality gate check
name: Quality Gate
on: [push]
jobs:
sonarqube:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: SonarQube Scan
uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
- name: Quality Gate Check
uses: sonarsource/sonarqube-quality-gate-action@master
timeout-minutes: 5
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}Security Findings Dashboard
# DefectDojo integration
import requests
def upload_scan_results(scan_type, file_path, engagement_id):
url = "https://defectdojo.company.com/api/v2/import-scan/"
headers = {"Authorization": f"Token {DEFECTDOJO_TOKEN}"}
with open(file_path, 'rb') as f:
data = {
'engagement': engagement_id,
'scan_type': scan_type,
'active': True,
'verified': False
}
files = {'file': f}
response = requests.post(url, headers=headers, data=data, files=files)
return response.json()Conclusion
Shift-left security transforms security from a gate at the end of development to a continuous process throughout the SDLC. By automating security testing in CI/CD pipelines, teams catch vulnerabilities early when they’re easiest and cheapest to fix.


