Security Scanning (DevSecOps)
DevSecOps integrates security into every stage of the CI/CD pipeline — catching vulnerabilities early (“shift left”) instead of discovering them in production. This page covers the scanning tools and techniques that make security a first-class citizen in your pipeline.
Shift Left
Section titled “Shift Left”Traditional: Code ──► Build ──► Test ──► Deploy ──► Security audit (months later) ▲ expensive to fix
Shift Left (DevSecOps): Code ──► SAST ──► Build ──► SCA ──► Container scan ──► DAST ──► Deploy ▲ ▲ ▲ ▲ cheap to fix cheap to fix cheap to fix still cheaperFinding a vulnerability in development costs 10x less to fix than in production. Security scanning in CI catches issues before they reach users.
Types of Security Scanning
Section titled “Types of Security Scanning”| Type | What It Scans | When It Runs | Finds |
|---|---|---|---|
| SAST | Source code | Before/during build | SQL injection, XSS, hardcoded secrets, insecure patterns |
| SCA | Dependencies | After dependency install | Known CVEs in packages |
| Container Scanning | Docker images | After image build | OS-level and package CVEs in the image |
| IaC Scanning | Terraform, CloudFormation, K8s YAML | Before apply/deploy | Misconfigurations, insecure defaults |
| Secret Detection | Source code and git history | Pre-commit or CI | API keys, passwords, tokens committed to code |
| DAST | Running application | After deployment (staging) | Runtime vulnerabilities (XSS, CSRF, auth issues) |
| License Scanning | Dependencies | During build | Incompatible open-source licenses |
SAST (Static Application Security Testing)
Section titled “SAST (Static Application Security Testing)”SAST analyzes source code without running the application — looking for insecure patterns, injection flaws, and coding mistakes.
| Tool | Languages | Open Source | Notes |
|---|---|---|---|
| Semgrep | 30+ languages | Yes | Rule-based, fast, easy custom rules |
| CodeQL | C/C++, C#, Go, Java, JS, Python, Ruby | Free on GitHub | Deep dataflow analysis, GitHub-native |
| SonarQube | 30+ languages | Community + Commercial | Code quality + security, dashboards |
| Bandit | Python | Yes | Python-specific security linter |
| Brakeman | Ruby (Rails) | Yes | Rails security scanner |
| gosec | Go | Yes | Go security linter |
| ESLint security plugins | JavaScript/TypeScript | Yes | eslint-plugin-security, eslint-plugin-no-secrets |
GitHub Actions — Semgrep
Section titled “GitHub Actions — Semgrep”security-sast: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: returntocorp/semgrep-action@v1 with: config: >- p/default p/owasp-top-ten p/pythonGitHub Actions — CodeQL
Section titled “GitHub Actions — CodeQL”security-codeql: 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/autobuild@v3 - uses: github/codeql-action/analyze@v3CodeQL results appear in GitHub’s Security tab → Code scanning alerts.
GitLab — SAST
Section titled “GitLab — SAST”include: - template: Security/SAST.gitlab-ci.yml
# GitLab auto-detects languages and runs appropriate scanners# Results appear in the MR security widgetSCA (Software Composition Analysis)
Section titled “SCA (Software Composition Analysis)”SCA scans your dependencies for known vulnerabilities (CVEs) using public databases like the National Vulnerability Database (NVD).
| Tool | Type | Notes |
|---|---|---|
| Dependabot | GitHub-native | Auto-creates PRs to update vulnerable deps |
| Renovate | Multi-platform | Auto-update PRs, highly configurable |
| Snyk | SaaS + CLI | Deep SCA + container scanning, fix suggestions |
| Trivy | CLI (open source) | SCA + container + IaC scanning (all-in-one) |
| OWASP Dependency-Check | CLI (open source) | Java/Maven focused, broad language support |
| npm audit | Built-in (Node.js) | npm audit / npm audit fix |
| pip-audit | Built-in (Python) | pip-audit |
cargo audit | Built-in (Rust) | cargo audit |
GitHub Actions — Trivy (Dependencies)
Section titled “GitHub Actions — Trivy (Dependencies)”security-sca: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: aquasecurity/trivy-action@master with: scan-type: fs scan-ref: . severity: CRITICAL,HIGH exit-code: 1 # Fail the pipeline on critical/highDependabot Configuration
Section titled “Dependabot Configuration”version: 2updates: - package-ecosystem: npm directory: / schedule: interval: weekly open-pull-requests-limit: 10 labels: [dependencies] reviewers: [myorg/security-team]
- package-ecosystem: docker directory: / schedule: interval: weekly
- package-ecosystem: github-actions directory: / schedule: interval: weeklyDependabot automatically opens PRs when a dependency has a known vulnerability.
Container Scanning
Section titled “Container Scanning”Scans Docker images for vulnerabilities in OS packages and application dependencies embedded in the image.
| Tool | Open Source | Notes |
|---|---|---|
| Trivy | Yes | Fast, comprehensive, supports OS + language deps |
| Grype | Yes (Anchore) | Fast, pairs with Syft for SBOM |
| Snyk Container | Commercial + free tier | Fix suggestions, base image recommendations |
| AWS ECR Scanning | AWS-native | Basic (Clair) or enhanced (Inspector) |
| Azure Defender for Containers | Azure-native | Scans ACR images |
GitHub Actions — Trivy (Container)
Section titled “GitHub Actions — Trivy (Container)”container-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- run: docker build -t myapp:${{ github.sha }} .
- uses: aquasecurity/trivy-action@master with: image-ref: myapp:${{ github.sha }} severity: CRITICAL,HIGH exit-code: 1 format: sarif output: trivy-results.sarif
- uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: trivy-results.sarif # Results appear in GitHub Security tabGitLab — Container Scanning
Section titled “GitLab — Container Scanning”include: - template: Security/Container-Scanning.gitlab-ci.yml
container_scanning: variables: CS_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHAReducing Image Vulnerabilities
Section titled “Reducing Image Vulnerabilities”| Practice | Impact |
|---|---|
| Use minimal base images | alpine, distroless, scratch — fewer packages = fewer CVEs |
| Multi-stage builds | Only copy build artifacts into the final image (no build tools) |
| Pin base image versions | node:20.11-alpine not node:latest |
| Update base images regularly | Rebuild images weekly to pick up OS security patches |
| Don’t run as root | USER nonroot in Dockerfile |
IaC Scanning
Section titled “IaC Scanning”Scans Infrastructure as Code (Terraform, CloudFormation, Kubernetes YAML, Dockerfiles) for security misconfigurations.
| Tool | Scans | Open Source | Notes |
|---|---|---|---|
| Checkov | Terraform, CloudFormation, K8s, Docker | Yes | 1000+ built-in rules |
| tfsec (now part of Trivy) | Terraform | Yes | Terraform-specific, fast |
| KICS | Terraform, K8s, Docker, Ansible | Yes | Multi-IaC scanner |
| Trivy | Terraform, CloudFormation, K8s, Docker | Yes | All-in-one (IaC + SCA + container) |
| OPA / Conftest | Any (Rego policies) | Yes | Custom policy engine |
GitHub Actions — Checkov
Section titled “GitHub Actions — Checkov”iac-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: bridgecrewio/checkov-action@v12 with: directory: infra/ framework: terraform soft_fail: false # Fail pipeline on violations output_format: sarif output_file_path: checkov.sarif
- uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: checkov.sarifCommon IaC Misconfigurations
Section titled “Common IaC Misconfigurations”| Finding | Risk |
|---|---|
| S3 bucket with public access | Data leak |
| Security group allowing 0.0.0.0/0 on port 22 | Unauthorized SSH access |
| RDS without encryption at rest | Data exposure |
| Kubernetes pod running as root | Container breakout |
| Azure storage account without HTTPS enforcement | Data interception |
IAM policy with * resource and * action | Over-privileged access |
Secret Detection
Section titled “Secret Detection”Scans source code and git history for accidentally committed secrets — API keys, passwords, tokens, private keys.
| Tool | Open Source | Notes |
|---|---|---|
| gitleaks | Yes | Scans git history, fast, regex + entropy |
| truffleHog | Yes | Deep git history scanning, verified secrets |
| detect-secrets (Yelp) | Yes | Pre-commit hook + baseline file |
| GitHub Secret Scanning | GitHub-native | Automatic for public repos, alerts on 200+ secret types |
| GitLab Secret Detection | GitLab-native | Built-in CI template |
Pre-Commit Hook (Prevent Secrets from Being Committed)
Section titled “Pre-Commit Hook (Prevent Secrets from Being Committed)”repos: - repo: https://github.com/gitleaks/gitleaks rev: v8.18.0 hooks: - id: gitleaksGitHub Actions — Gitleaks
Section titled “GitHub Actions — Gitleaks”secret-detection: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # Full history for scanning - uses: gitleaks/gitleaks-action@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}What to Do When a Secret Is Committed
Section titled “What to Do When a Secret Is Committed”- Rotate the secret immediately — assume it’s compromised.
- Remove from code — don’t just delete; rewrite git history with
git filter-repoor BFG Repo Cleaner. - Add to
.gitignore— prevent re-committing. - Add a pre-commit hook — prevent future leaks.
- Audit usage — check if the secret was used maliciously.
DAST (Dynamic Application Security Testing)
Section titled “DAST (Dynamic Application Security Testing)”DAST tests a running application by sending crafted requests and analyzing responses — like an automated penetration test.
| Tool | Open Source | Notes |
|---|---|---|
| OWASP ZAP | Yes | Most popular open-source DAST |
| Nuclei | Yes | Template-based, fast, community templates |
| Burp Suite | Commercial | Industry standard for pen testing |
| GitLab DAST | GitLab-native | Built-in CI template |
GitHub Actions — OWASP ZAP
Section titled “GitHub Actions — OWASP ZAP”dast: runs-on: ubuntu-latest needs: deploy-staging # Only run after staging deployment steps: - uses: zaproxy/action-full-scan@v0.10.0 with: target: https://staging.myapp.com rules_file_name: .zap-rules.tsv cmd_options: '-a'DAST runs after deployment to staging — it needs a live application to test against.
Pipeline Integration Pattern
Section titled “Pipeline Integration Pattern”A recommended ordering for security scans in your pipeline:
push ──► SAST + Secret Detection ──► Build ──► SCA ──► Container Scan ──► Deploy Staging ──► DAST (source code) │ (deps) (image) │ (running app) │ │ └── IaC Scan (Terraform/K8s) ───────┘Full Security Pipeline (GitHub Actions)
Section titled “Full Security Pipeline (GitHub Actions)”name: Securityon: push: branches: [main] pull_request:
jobs: secrets: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: gitleaks/gitleaks-action@v2
sast: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: returntocorp/semgrep-action@v1 with: config: p/default
sca: runs-on: ubuntu-latest needs: [secrets, sast] steps: - uses: actions/checkout@v4 - run: npm ci - uses: aquasecurity/trivy-action@master with: scan-type: fs severity: CRITICAL,HIGH exit-code: 1
container-scan: runs-on: ubuntu-latest needs: sca steps: - uses: actions/checkout@v4 - run: docker build -t myapp:${{ github.sha }} . - uses: aquasecurity/trivy-action@master with: image-ref: myapp:${{ github.sha }} severity: CRITICAL,HIGH exit-code: 1
iac-scan: runs-on: ubuntu-latest if: hashFiles('infra/**') != '' steps: - uses: actions/checkout@v4 - uses: bridgecrewio/checkov-action@v12 with: directory: infra/SBOM (Software Bill of Materials)
Section titled “SBOM (Software Bill of Materials)”An SBOM is a complete list of components in your software — like an ingredient list. It’s increasingly required for compliance and supply chain security.
Generating an SBOM
Section titled “Generating an SBOM”| Tool | Format | What It Scans |
|---|---|---|
| Syft (Anchore) | SPDX, CycloneDX | Container images, filesystems |
| Trivy | SPDX, CycloneDX | Container images, filesystems |
npm sbom | SPDX, CycloneDX | Node.js packages |
| GitHub Dependency Graph | GitHub-native | Auto-generated for supported ecosystems |
# Generate SBOM with Syftsyft myapp:latest -o spdx-json > sbom.spdx.json
# Generate SBOM with Trivytrivy image --format spdx-json -o sbom.spdx.json myapp:latestSigning Container Images
Section titled “Signing Container Images”Use cosign (Sigstore) to sign images and verify provenance:
# Sign an imagecosign sign --key cosign.key myregistry/myapp:v1.2.3
# Verify a signaturecosign verify --key cosign.pub myregistry/myapp:v1.2.3Severity Handling
Section titled “Severity Handling”Not all vulnerabilities are equal. Define a policy for how to handle each severity:
| Severity | Pipeline Action | SLA to Fix |
|---|---|---|
| Critical | Block merge / deployment | Within 24 hours |
| High | Block merge / deployment | Within 1 week |
| Medium | Warn (allow merge) | Within 1 month |
| Low | Informational | Best effort |
# Trivy: fail only on critical and high- uses: aquasecurity/trivy-action@master with: severity: CRITICAL,HIGH exit-code: 1 # Fail the pipelineKey Takeaways
Section titled “Key Takeaways”- Shift left — run security scans early in the pipeline (SAST, secret detection) to catch issues cheaply.
- SAST (Semgrep, CodeQL) scans source code; SCA (Trivy, Snyk, Dependabot) scans dependencies; Container scanning (Trivy, Grype) scans images.
- IaC scanning (Checkov, tfsec) catches misconfigurations in Terraform and Kubernetes manifests.
- Secret detection (gitleaks, pre-commit hooks) prevents API keys from reaching the repository.
- DAST (ZAP, Nuclei) tests the running application after deployment to staging.
- SBOM provides a component inventory for supply chain transparency.
- Define a severity policy — block on critical/high, warn on medium, inform on low.
- Use Dependabot or Renovate to auto-update vulnerable dependencies.