How to embed automated security scanning — static analysis, dependency checking, container scanning, and secret detection — directly into your CI/CD pipeline so vulnerabilities are caught before they reach production.
How to embed automated security scanning — static analysis, dependency checking, container scanning, and secret detection — directly into your CI/CD pipeline so vulnerabilities are caught before they reach production.
Manual code reviews miss security bugs, vulnerable dependencies ship unnoticed, and secrets get committed to Git — all because security checks happen too late (or not at all) in the development cycle.
Vulnerabilities are discovered in production, often by attackers. Remediating a flaw found in production costs 6–30× more than catching it during development, and the business impact (breach, downtime, compliance failure) can be catastrophic.
Every pull request and every build automatically runs SAST, dependency scanning, container scanning, and secret detection. Security issues are flagged as PR comments or build failures — developers fix them before merging, treating security exactly like any other quality gate.
Lesson outline
A complete security scanning strategy in CI/CD covers four distinct categories. Each catches a different class of vulnerability.
| Pillar | What It Finds | When It Runs | Example Tools |
|---|---|---|---|
| SAST (Static Application Security Testing) | Vulnerable code patterns — SQL injection, XSS, hardcoded passwords, insecure functions | On every PR / commit | Semgrep, Snyk Code, CodeQL, Checkmarx, Bandit (Python), ESLint-security |
| SCA (Software Composition Analysis) | Known CVEs in open-source dependencies | On every PR / dependency update | Snyk, Dependabot, OWASP Dependency-Check, Renovate with security checks |
| Container / Image Scanning | CVEs in base OS packages and installed libraries inside container images | After docker build | Trivy, Snyk Container, Grype, AWS ECR scanning, Clair |
| Secret Scanning | API keys, tokens, passwords accidentally committed to Git | Pre-commit hook + every PR | gitleaks, truffleHog, GitHub Secret Scanning, GitLab Secret Detection |
Shift left — catch bugs where they are cheapest to fix
A CVE caught by a pre-commit hook costs 5 minutes to fix. The same CVE found in production during a pen test costs days of emergency patching, possible downtime, and potential breach notification obligations. Run scanners as early in the pipeline as possible.
SAST tools analyse source code (or compiled bytecode) without running the application. They look for patterns that commonly lead to security vulnerabilities.
What SAST catches
SAST has high false positive rates — tune your rules
Out-of-the-box SAST can flag hundreds of issues, many of which are false positives. Start with a curated rule set (e.g. Semgrep's OWASP Top 10 rules), suppress known false positives with inline comments + a review process, and add custom rules for your specific framework and threat model. Noisy scanners get ignored.
Developer pushes code
│
▼
┌─────────────────────────────────────────────────────────┐
│ CI Pipeline (on every PR) │
│ │
│ ① SAST ② SCA ③ Secret Scan │
│ Semgrep Snyk/OWASP gitleaks │
│ CodeQL Dependency- (also pre-commit) │
│ Bandit Check │
│ │ │ │ │
│ └───────┬────────┘ │ │
│ ▼ │ │
│ ┌──────────────┐ │ │
│ │ Build + │◄────────────────┘ │
│ │ docker build│ │
│ └──────┬───────┘ │
│ ▼ │
│ ④ Container Scan │
│ Trivy / Grype │
│ │ │
│ ▼ │
│ Results → PR comments / build failure / SARIF upload │
└─────────────────────────────────────────────────────────┘
│
▼ (if all pass)
Merge → DeployFour scanning layers run in parallel where possible. Container scanning runs after the image is built.
1# Semgrep SAST — GitHub Actions2name: SAST Scan34on: [pull_request]56jobs:7semgrep:8name: SAST with Semgrep9runs-on: ubuntu-latest10container:11image: semgrep/semgrep12steps:13- uses: actions/checkout@v41415- name: Run Semgrepp/owasp-top-ten = curated rules for OWASP Top 1016run: |17semgrep scan --config p/owasp-top-ten --config p/secrets --config p/python --sarif --output semgrep-results.sarif --error # Fail build on findings1819- name: Upload SARIF to GitHub Security tab20uses: github/codeql-action/upload-sarif@v3--error causes non-zero exit (build fails) on any finding21if: always() # Upload even if scan found issues22with:23sarif_file: semgrep-results.sarifSARIF = industry standard format for security findings24category: semgrep
Modern applications use hundreds of open-source packages. Software Composition Analysis (SCA) scans your dependency graph against known CVE databases (NVD, OSV, GitHub Advisory Database) to find vulnerable versions.
The Log4Shell lesson: one dependency, global impact
CVE-2021-44228 (Log4Shell) affected Log4j — a logging library used by millions of Java applications, often as a transitive dependency (a dependency of a dependency). SCA tools discovered which applications used Log4j 2.0–2.14.1 within minutes. Without SCA, teams spent days manually auditing package.json, pom.xml, and build files.
SCA in practice
Set severity thresholds — not all CVEs block deploys
Configure your SCA tool to: FAIL the build on Critical/High CVEs with a fix available, WARN on Medium CVEs or High CVEs with no fix, IGNORE Low CVEs in pipeline (track separately). Blocking on every Low CVE creates noise and alert fatigue.
1# Trivy — container image scanning + SCA in one tool2# Trivy scans both OS packages (apk/apt/rpm) and language packages (pip/npm/go)3name: Container Security Scan45on:6push:7branches: [main]8pull_request:910jobs:11trivy-scan:12runs-on: ubuntu-latest13steps:14- uses: actions/checkout@v41516- name: Build image17run: docker build -t myapp:${{ github.sha }} .1819- name: Run Trivy container scan20uses: aquasecurity/trivy-action@master21with:22image-ref: myapp:${{ github.sha }}23format: sarifseverity: CRITICAL,HIGH — avoid alert fatigue from Low/Medium24output: trivy-results.sarif25severity: CRITICAL,HIGH # Only report C/Hignore-unfixed: skip CVEs where no patch exists yet26exit-code: '1' # Fail on findings27ignore-unfixed: true # Ignore CVEs with no patch yet2829- name: Upload Trivy results30uses: github/codeql-action/upload-sarif@v331if: always()32with:33sarif_file: trivy-results.sarif34category: trivy-containerfs scan also catches Python/Node/Go vulnerable packages3536# Also scan filesystem (SCA for Python/Node/Go deps)37- name: Run Trivy filesystem scan38uses: aquasecurity/trivy-action@master39with:40scan-type: fs41scan-ref: .42format: table43severity: CRITICAL,HIGH44exit-code: '1'
Secret scanners look for high-entropy strings and known credential patterns in your codebase and commit history. They catch AWS keys, GitHub tokens, Stripe secrets, JWT secrets, and more.
Layered secret scanning strategy
01
Pre-commit hook (gitleaks / git-secrets) — blocks commits containing secrets on the developer's machine before they ever leave
02
CI pipeline scan (gitleaks in GitHub Actions / GitLab Secret Detection) — catches anything that slipped past the pre-commit hook
03
GitHub / GitLab native secret scanning — platform-level scanning that also covers historical commits and notifies you of newly added patterns
04
Periodic full-history scan (truffleHog --entropy) — finds secrets buried in old commits from before scanning was in place
Pre-commit hook (gitleaks / git-secrets) — blocks commits containing secrets on the developer's machine before they ever leave
CI pipeline scan (gitleaks in GitHub Actions / GitLab Secret Detection) — catches anything that slipped past the pre-commit hook
GitHub / GitLab native secret scanning — platform-level scanning that also covers historical commits and notifies you of newly added patterns
Periodic full-history scan (truffleHog --entropy) — finds secrets buried in old commits from before scanning was in place
Pre-commit hooks can be bypassed with --no-verify
Developers can skip pre-commit hooks with git commit --no-verify. This is why CI pipeline scanning is the non-bypassable safety net. Pre-commit hooks are the fast developer feedback loop; CI scanning is the enforcement gate.
| Tool | Type | Coverage | Best For |
|---|---|---|---|
| gitleaks | Open source | Git history, staged files, CI | Pre-commit hooks, CI pipeline |
| truffleHog | Open source | Full Git history, entropy analysis | Historical audit of existing repos |
| GitHub Secret Scanning | Platform native | All commits, PRs, issues (for GitHub token patterns) | GitHub-hosted repos — zero config |
| GitLab Secret Detection | Platform native | Commits in MR pipeline | GitLab CI/CD — built into Ultimate tier |
| Semgrep (p/secrets) | Open source + SaaS | Source code patterns | Combined SAST + secret scan in one run |
1# gitleaks pre-commit hook + CI enforcement2# Step 1: Install gitleaks pre-commit hook (developer machine)3# .pre-commit-config.yaml4repos:5- repo: https://github.com/gitleaks/gitleaks6rev: v8.18.27hooks:8- id: gitleaksPre-commit hook blocks commits with secrets on dev machine9# gitleaks will scan staged files before each commit10# If a secret is found, the commit is blocked with the finding1112# Step 2: CI enforcement (GitHub Actions)13name: Secret Scanning1415on: [push, pull_request]1617jobs:18gitleaks:19runs-on: ubuntu-latest20steps:21- uses: actions/checkout@v422with:23fetch-depth: 0 # Full history — scan all commits in the PRfetch-depth: 0 ensures full PR history is scanned, not just HEAD2425- uses: gitleaks/gitleaks-action@v226env:27GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}28# GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} # For org-level scan2930# Step 3: Historical audit (run once on existing repos)31# docker run --rm -v $(pwd):/repo zricethezav/gitleaks \32# detect --source /repo --report-format sarif \Historical audit — run this once on all existing repos33# --report-path gitleaks-report.sarif3435# gitleaks.toml — custom rules (optional)36# [rules]37# [[rules.rules]]38# description = "Internal API key pattern"39# regex = 'MYCO-[A-Z0-9]{32}'40# tags = ["key", "myco"]
Security scanning that doubles build time gets disabled. Parallelise, cache, and threshold-tune to keep the feedback loop fast.
Performance and ergonomics best practices
The golden rule: security gates must not slow CI by more than 20%
A pipeline that took 5 minutes and now takes 20 minutes due to security scanning will be disabled or bypassed. Target total additional time of under 2–3 minutes through parallelisation and incremental scanning. Fast, accurate, actionable is the goal.
Pipeline security scanning appears in DevSecOps engineer interviews, senior backend/platform roles, and any role where you own CI/CD. Expect scenario questions about triaging scanner findings and balancing security with developer velocity.
Common questions:
Strong answer: Mentions parallelisation for speed, SARIF for centralised reporting, severity thresholds to avoid alert fatigue, and the importance of the pre-commit hook layer for secrets.
Red flags: Thinking SAST is the only security scanner needed, not knowing what SCA stands for, or believing container scanning is covered by language-level dependency scanning.
Quick check · Security in CI/CD: SAST, SCA, and Secret Scanning
1 / 4
Key takeaways
Your Trivy scan reports 47 CVEs in your Node.js Docker image. What is your triage approach?
First, filter by severity — focus on Critical and High with a fix available (ignore-unfixed flag). Second, separate OS-level CVEs (in the base image — fix by updating to a newer base image or using distroless/Alpine) from application dependency CVEs (fix by updating package.json). Third, check if the vulnerable code path is actually reachable in your application — some CVEs in libraries your code never calls have no real impact. Prioritise: Critical CVEs with exploits in the wild → Critical CVEs with fix available → High CVEs. Create tickets for Medium/Low with no urgency.
What is the difference between SAST and DAST, and when would you use each in a pipeline?
SAST (Static) analyses source code without running the application — catches code-level bugs (injection, insecure functions, hardcoded secrets) early in the pipeline, fast. DAST (Dynamic) runs against a live application by sending HTTP requests and observing responses — catches runtime issues (authentication bypasses, misconfigured headers, server-side logic bugs) that require the app to be running. Use SAST on every PR (fast, no infrastructure needed). Use DAST in a staging environment after deploy (slower, requires a running app). SAST catches what you wrote; DAST catches how it behaves.
A developer argues that security scanning is slowing down their pipeline too much. How do you respond?
Acknowledge the concern — slow pipelines do get disabled. Then diagnose: (1) Are scans running sequentially instead of in parallel? (2) Is the dependency cache being rebuilt every run? (3) Are we scanning the full repo on every commit instead of just changed files? Fix the implementation first. If scanning genuinely cannot be fast enough, apply incremental scanning (changed files only for SAST), run expensive scans only on merge to main (not on every PR commit), and use asynchronous scanning (non-blocking) with a separate PR check for slower deep scans. Never remove scanning — adjust the implementation.
From the books
The DevSecOps Handbook (Gene Kim / John Willis, IT Revolution)
Part IV: The Third Way — Continual Learning and Experimentation
Covers integrating security into the Three Ways of DevOps — flow, feedback, and continuous learning. Chapter on security scanning pipelines is directly applicable.
Alice and Bob Learn Application Security (Tanya Jain, Wiley)
Practical application security guide covering SAST, DAST, threat modelling, and secure code review. One of the most accessible security books for developers.
💡 Analogy
Airport security — multiple checkpoints, each catching different threats
⚡ Core Idea
No single scanner catches everything. SAST finds vulnerable code patterns. SCA finds vulnerable libraries. Container scanning finds vulnerable OS packages. Secret scanning finds leaked credentials. You need all four, layered, running automatically on every code change.
🎯 Why It Matters
The cost and blast radius of a security vulnerability grow exponentially the later they are found. A SQL injection bug found by SAST in a PR review is a 30-minute fix. The same bug found in production after a breach is a regulatory investigation, customer notification, and months of remediation.
Ready to see how this works in the cloud?
Switch to Career Paths for structured paths (e.g. Developer, DevOps) and provider-specific lessons.
View role-based pathsSign in to track your progress and mark lessons complete.
Questions? Discuss in the community or start a thread below.
Join DiscordSign in to start or join a thread.