Last reviewed 9 min read

Section 09

Secure SDLC Integration

Integrating security into the Software Development Lifecycle (SDLC) ensures that security is considered at every phase—from requirements to retirement.

Secure SDLC Pipeline Gates

Pre-commit, build, test, scan/SBOM, sign, and admission-verify gates across the pipeline.

SDLC Security Activities

Requirements
  • • Define security requirements (confidentiality, integrity, availability)
  • • Identify compliance requirements (GDPR, HIPAA, PCI)
  • • Create abuse cases alongside use cases
  • • Data classification for all data types
Design
  • • Threat modeling (STRIDE, PASTA)
  • • Security architecture review
  • • Attack surface analysis
  • • Select secure design patterns
  • • Define security controls
Development
  • • Follow secure coding guidelines
  • • Use security linters and IDE plugins
  • • SAST in CI/CD pipeline
  • • Peer code review for security
  • • Secrets management (not in code)
Testing
  • • DAST and IAST scans
  • • Security unit tests
  • • Penetration testing
  • • Fuzz testing
  • • Dependency vulnerability scanning
Deployment
  • • Infrastructure as Code security scanning
  • • Container image scanning
  • • Configuration hardening verification
  • • Security sign-off gate
Operations
  • • Security monitoring and alerting
  • • Incident response procedures
  • • Vulnerability management
  • • Patch management
  • • Bug bounty program

Security Gates

Security gates are checkpoints where security criteria must be met before proceeding.

A gate is only useful if it can stop the pipeline. Gates that emit warnings without a pass/fail decision become background noise, so each one needs a defined threshold, an owner, and an escape hatch that requires explicit risk acceptance. Order them cheapest-and-earliest first: a secret caught by a pre-commit hook never reaches git history, where removal means rewriting history rather than reverting a commit.

Pre-Commit Gate

  • • Secret scanning (prevent credential commits)
  • • Linting for security anti-patterns
  • • Pre-commit hooks

Build Gate

  • • SAST scan pass/fail
  • • Dependency vulnerability check
  • • License compliance

Deploy Gate

  • • DAST scan results
  • • Container scan pass
  • • IaC policy compliance

Release Gate

  • • Penetration test sign-off
  • • Compliance verification
  • • Risk acceptance for exceptions

Threat Modeling in CI

Threat modeling is only a gate if it runs in the pipeline. Page 01 — Threat Modeling defines the model; this subsection makes it executable. Treat the model as a versioned artifact committed next to the code — Threagile models it as YAML (assets, data flows, trust boundaries, and per-flow authentication), so the model lives in the same pull request as the architecture it describes.

The pipeline then runs the model as code on every change and fails the build when the analysis yields an unmitigated high or critical risk:

  1. Commit the model (threat-model/threagile.yaml) and review it in the same PR as the design change.
  2. Run Threagile in a CI job against the committed model — it ships as a container image, so no local install is needed.
  3. Parse the generated risk report and assert that no high or critical risk is left unmitigated.
  4. Fail the job — and therefore the merge — when that assertion is false; allow only an explicit, reviewed risk acceptance to pass.

This closes the loop with page 01: a new data flow that crosses a trust boundary without authentication shows up as a diff in the model, not as a finding discovered during penetration testing months later. The common failure is running the tool once and filing the report — a threat model that does not re-run cannot reflect the architecture it is meant to govern.

Practical: Pre-Commit Hooks

.pre-commit-config.yaml
repos:
  # Secret detection — catch before they enter git
  - repo: https://github.com/Yelp/detect-secrets
    rev: v1.5.0
    hooks:
      - id: detect-secrets
        args: ['--baseline', '.secrets.baseline']

  # TruffleHog for high-entropy strings
  - repo: https://github.com/trufflesecurity/trufflehog
    rev: v3.97.4
    hooks:
      - id: trufflehog
        args: ['git', 'file://./']

  # Security linting
  - repo: https://github.com/PyCQA/bandit
    rev: 1.9.4
    hooks:
      - id: bandit
        args: ['-c', 'pyproject.toml']

  # Terraform security — tfsec is deprecated; pre-commit-terraform replaced
  # the terraform_tfsec hook with terraform_trivy
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    rev: v1.109.1
    hooks:
      - id: terraform_trivy

  # Dockerfile linting
  - repo: https://github.com/hadolint/hadolint
    rev: v2.15.1
    hooks:
      - id: hadolint

Practical: GitHub Actions Security Pipeline

.github/workflows/security.yml
name: Security Pipeline
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

permissions:
  contents: read
  security-events: write

# Third-party actions are pinned by commit SHA (with the release tag in a
# comment) so a moved tag cannot change what runs in your pipeline.
jobs:
  secrets-scan:
    name: Secret Detection
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1  # v7.0.1
        with:
          fetch-depth: 0  # Full history for git-based scanning
      - uses: trufflesecurity/trufflehog@363923b901c911a9164f50b6c423f47c15372b1c  # v3.97.4
        with:
          extra_args: --only-verified

  sast:
    name: Static Analysis
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1  # v7.0.1
      - name: Run Semgrep (writes semgrep.sarif)
        run: |
          docker run --rm -v "$PWD:/src" -w /src semgrep/semgrep \
            semgrep scan --sarif --output semgrep.sarif --error \
            --config p/owasp-top-ten --config p/cwe-top-25 --config p/security-audit
      - name: Upload SARIF
        uses: github/codeql-action/upload-sarif@b96794f015dfd88f77b49b1c93e0fa7110f94c63  # v4.38.0
        with:
          sarif_file: semgrep.sarif

  dependency-check:
    name: Dependency Scan
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1  # v7.0.1
      - name: Run Snyk
        uses: snyk/actions/node@9adf32b1121593767fc3c057af55b55db032dc04  # v1.0.0
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        with:
          args: --severity-threshold=high

  container-scan:
    name: Container Security
    runs-on: ubuntu-latest
    needs: [sast]
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1  # v7.0.1
      - name: Build image
        run: docker build -t app:test .
      - name: Run Trivy
        uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25  # v0.36.0
        with:
          image-ref: app:test
          severity: CRITICAL,HIGH
          exit-code: 1  # Fail on critical/high

  iac-scan:
    name: IaC Security
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1  # v7.0.1
      - name: Run Checkov
        uses: bridgecrewio/checkov-action@a8664e3a0549367977f0cda990a34311835c87c0  # v12.3123.0
        with:
          directory: terraform/
          soft_fail: false
          framework: terraform

SDLC Maturity Models

Maturity models give a program a way to measure itself against a known baseline instead of guessing. They are diagnostic, not certification: the point is to find the practices you have not adopted and to prioritize the next one, not to collect a score.

OWASP SAMM 2.0

Open framework — see owaspsamm.org. 5 business functions, 15 practices, 3 maturity levels each.

  • • Governance: Strategy, Policy, Education
  • • Design: Threat Assessment, Security Requirements, Architecture
  • • Implementation: Secure Build, Secure Deploy, Defect Management
  • • Verification: Architecture Assessment, Requirements Testing, Security Testing
  • • Operations: Incident Management, Environment Management, Operational Management

BSIMM (Building Security In)

Data-driven model measuring what organizations actually do (not aspirational).

  • • Based on observations from 100+ organizations
  • • 4 domains, 12 practices, 128 activities
  • • Useful for benchmarking against industry peers
  • • Annual report with trend data
  • • SAMM = prescriptive, BSIMM = descriptive

DevSecOps Toolchain

Phase Tools What They Catch
Pre-Commit detect-secrets, TruffleHog, GitLeaks Hardcoded secrets, API keys
SAST Semgrep, SonarQube, CodeQL Code-level vulnerabilities, injection, XSS
SCA Snyk, Dependabot, Renovate Vulnerable dependencies, license issues
Container Trivy, Grype, Snyk Container Image CVEs, misconfig, malware
IaC Checkov, tfsec, KICS Cloud misconfigurations, policy violations
DAST OWASP ZAP, Nuclei, Burp CI Runtime vulns, OWASP Top 10 in running app

Software Supply-Chain Integrity

Scanning your own code does not help if the artifact that reaches production was built somewhere else, from different inputs, or substituted in the registry. Supply-chain integrity answers three questions: was this built from the source we think, by a process we trust; is the artifact cryptographically the one that was produced; and what is actually inside it? The SLSA framework grades build provenance from level 1 (provenance exists) to level 3 (hardened, isolated builds with non-forgeable provenance) — a ladder to climb rather than a binary gate.

Signing with Sigstore and cosign binds an artifact's digest to a verified identity using short-lived certificates, so there is no long-lived private key to hold. Generate an SBOM at build time with Syft in CycloneDX or SPDX format, attach it to the artifact, and verify at admission: an admission controller (Kyverno, OPA Gatekeeper, or the Kubernetes policy engine you already run) should reject any image whose digest is unsigned or whose signature does not match an allowed builder identity.

Prefer digests to tags everywhere — image:tag is mutable and a re-push silently replaces what production runs, whereas image@sha256:… cannot change. The common failure is signing as a formality without verifying: a signature that nothing checks stops no attack. Wire verification into admission and treat an unsigned image as un-deployable by default; page 12 — Reference Architectures shows how this fits with the rest of the build pipeline.

Security Champions Program

Scale Security

Security teams can't review every line of code. Security champions in each development team multiply your security capacity.

Champion Responsibilities

  • • First point of contact for security questions
  • • Participate in threat modeling sessions
  • • Review code changes for security issues
  • • Triage security scanner findings
  • • Evangelize security best practices

Champion Training

  • • OWASP Top 10 deep dive
  • • Threat modeling certification
  • • Secure code review techniques
  • • Security tool training
  • • Regular security updates and CTFs

Metrics & KPIs

Process Metrics

  • • % of projects with threat models
  • • Security training completion rate
  • • Time from vulnerability to patch
  • • Security gate pass rate

Outcome Metrics

  • • Vulnerabilities found in production
  • • Critical/High findings per release
  • • Mean time to remediate (MTTR)
  • • Security incidents per quarter

Framework Alignment

NIST CSF 2.0: PR.PS (Platform Security), ID.RA (Risk Assessment)
ISO 27002:2022: A.8.25 (Secure Development Lifecycle), A.8.28 (Secure Coding), A.8.29 (Security Testing)
OWASP SAMM 2.0: Entire framework maps to SDLC security activities
CIS Controls v8.1: 16 (Application Software Security), 7 (Continuous Vulnerability Management)
Supply chain: SLSA, Sigstore, CycloneDX
Related: Security Frameworks →

Secure SDLC Labs

Wire the security gates into a real pipeline and run threat modeling as code.

Build the Pipeline Gates Custom Lab medium
Add a pre-commit hook that blocks secrets (detect-secrets or TruffleHog)Add a SAST gate (Semgrep) and a dependency gate (Snyk) that fail the buildAdd an IaC scan (Checkov) and a container scan (Trivy) before deployPin every third-party action to a commit SHAIntroduce a known vulnerability on a branch and confirm the pipeline stops it
Threat Model as Code in CI Custom Lab hard
Commit a Threagile YAML model next to the codeRun the Threagile container in a CI job on every changeParse the risk report and fail the build on an unmitigated high or critical riskAdd an explicit, reviewed risk acceptance for one finding and confirm it passesConfirm a new unauthenticated data flow appears as a diff in the model