The secure SDLC
The software development lifecycle always had security implications at every phase — most teams just deferred all of them to a single audit gate near the end. This page walks the SDLC phase by phase, requirements through operations, and names the concrete activity that belongs at each one. By the end you should be able to point at any stage of your own team's process and say specifically what security work is supposed to be happening there.
A building inspector doesn't show up once, at the end, and declare the house safe. They check the foundation before the framing goes up, check the wiring before the drywall closes over it, and do a final walkthrough before anyone moves in — each inspection only makes sense once the thing it's checking actually exists. You can't inspect wiring that hasn't been run yet, and you don't wait until move-in day to check the foundation. The secure SDLC works the same way: each phase gets the security check that fits what exists at that point, instead of one inspector standing at the front door on release day.
Mapping security activity onto the SDLC
A requirements document built only from user stories describes how the system should behave for a legitimate user — it says nothing about how it behaves for an attacker, because nobody wrote that case down. Abuse cases (also called misuse cases) close that gap by pairing every normal use case with its adversarial mirror: alongside "as a user, I want to reset my password via an emailed link," you write "as an attacker, I want to enumerate valid accounts by comparing the reset endpoint's response times and error text." The abuse case forces a design decision — a generic response, a fixed response time — before the flow is ever coded.
Design is where that decision gets made systematically, through threat modeling: mapping trust boundaries and data flows, then asking what could go wrong at each one. Line requirements and design up against development, testing, deployment, and operations, and a pattern falls out — every phase has a native security activity that fits what actually exists at that point in the process.
| SDLC Phase | Security Activities |
|---|---|
| Requirements | Abuse/misuse cases written alongside user stories; security requirements traced through to acceptance criteria |
| Design | Threat modeling (trust boundaries, data-flow mapping, STRIDE or attack trees); control selection per boundary |
| Development | Secure coding standards (OWASP ASVS), mandatory peer review, SAST in the IDE and pre-commit hooks |
| Testing | DAST against a running build, SCA / dependency scanning, manual penetration testing for high-risk changes |
| Deployment | Host/image hardening (CIS Benchmarks), secrets injected at deploy time, IaC security scanning before apply |
| Operations | Runtime monitoring and anomaly detection, patch management against tracked CVEs, vulnerability disclosure handling |
Don't read that table as six sequential gates on a calendar. A team shipping several times a day isn't spending a week in "requirements" and then moving on — it's running a scaled-down version of every row on nearly every change, continuously, inside the same CI/CD pipeline. Treating the SDLC as a waterfall is the mistake that turns this table into a once-per-project audit checklist instead of what it's meant to be: a description of what kind of security thinking each phase calls for, no matter how short that phase actually is.
Development: catching issues while the code is still yours
Secure coding standards give developers a concrete bar instead of a vague "write safe code" instruction. The OWASP Application Security Verification Standard (ASVS) is the reference most teams borrow from: it defines verification requirements across authentication, session management, access control, and input handling, organized into three levels of rigor — L1 for every application, L3 for the ones handling the most sensitive data. The point isn't hitting L3 everywhere; it's deciding, deliberately, which level applies to which service.
Peer review is the next layer, and it works because a second engineer looks at a diff with fresh eyes and no investment in the shortcut the author took. Making that count for security means the review checklist asks security-specific questions — does this change introduce a new external input path, and is it validated? does it touch authentication, authorization, or cryptography? — and that CODEOWNERS routes those paths to reviewers who actually know the threat model, not whoever is next in a round robin.
The earliest automated check runs where the developer is already working: SAST as an IDE plugin or a pre-commit git hook, using a fast tool like Semgrep or a language-specific linter (Bandit for Python, gosec for Go) against just the lines that changed. It catches the cheap, common mistakes — a hardcoded credential, a string-concatenated SQL query, an insecure deserialization call — before they're even committed. That's fundamentally different economics from catching the same bug in CI five minutes and a context switch later. The heavier SAST/DAST/SCA tooling that runs in the pipeline itself is covered in SAST, DAST & SCA.
Testing: verifying what actually got built
DAST (dynamic application security testing) exercises a running instance from the outside, sending real HTTP requests and watching what comes back — which means it catches classes of bug static analysis structurally cannot see: a misconfigured TLS listener, a session token that doesn't rotate on privilege change, an auth check that exists in the code but is unreachable given how routes are actually wired at runtime. Tools like OWASP ZAP or Burp Suite drive this, typically against a staging environment ahead of each release.
SCA (software composition analysis) scans dependency manifests — package-lock.json, requirements.txt, go.sum — against vulnerability feeds such as the NVD, the GitHub Advisory Database, and OSV. This matters disproportionately: repeated open-source security surveys have put third-party and open-source code at 70-90% of the code footprint in a typical application, so most of a codebase's exposure sits in dependencies nobody on the team wrote or reviewed line by line. Snyk, Dependabot, and OWASP Dependency-Check are the common tools here; see SAST, DAST & SCA for how they fit into a pipeline.
Manual penetration testing is the slowest and most expensive check in this phase — days to weeks, billed at specialist rates — so it isn't run per pull request. It's targeted at high-risk changes: a new authentication flow, a payment integration, a service newly exposed to the internet. PCI DSS, for one, requires it annually and after any significant change to in-scope systems, and most mature programs apply that same "annual plus significant change" cadence even without a compliance mandate driving it.
Deployment and operations: after the merge is not after the risk
Deployment hardens what's about to run in production. Host and container images get checked against a hardening baseline — the CIS Benchmarks are the common reference — stripping unnecessary services and default accounts before an image is ever tagged for release. Secrets are injected at deploy time from a vault (HashiCorp Vault, AWS Secrets Manager, or a cloud KMS-backed store) rather than baked into the image or committed as a config file; see secrets management for the mechanics. And the infrastructure-as-code that provisions everything gets scanned before terraform apply runs — tools like tfsec, Checkov, or Terrascan catch a publicly readable storage bucket or an unencrypted database instance while it's still a diff, not after it's live; see IaC security & policy as code.
Operations is where the SDLC stops being a project timeline and becomes an ongoing responsibility. Runtime monitoring — cloud-native anomaly detection or a container-focused tool watching syscalls — flags behavior no static check could have predicted. Patch management tracks which CVEs affect the software actually running in inventory and enforces an SLA on top of it, commonly critical vulnerabilities patched within 72 hours of a fix landing. And every production system needs a published disclosure channel and a triage process that scores incoming reports by CVSS and routes the serious ones into the same process covered in incident response & forensics.
Every phase above answers the same underlying question at a different point in time: given what exists right now — a requirements doc, a diagram, a diff, a running build, an image, a live service — what's the cheapest check that finds a real problem before the next phase makes it more expensive to fix?
Benchmarking the whole program: SAMM and BSIMM
Everything above describes activities within a single change. Two widely used models step back and ask how well an entire organization is doing this, on average, across every team and every phase. OWASP SAMM (Software Assurance Maturity Model) is prescriptive: it defines five business functions — Governance, Design, Implementation, Verification, and Operations — each broken into practices scored on a 0-3 maturity scale, meant to be used as a self-assessment that produces a roadmap ("we're at level 1 in threat assessment; here's what level 2 requires").
BSIMM (Building Security In Maturity Model) takes the opposite approach: it's descriptive, not prescriptive, built from repeated measurement of real security programs across many organizations, and it reports what those organizations actually do — which activities are common, which are rare — so a team can compare itself against real industry practice rather than an idealized target. Where SAMM tells you what "good" should look like, BSIMM tells you what your peers actually do. Neither model replaces the phase-by-phase work above; they answer a different question entirely — not "did we threat model this feature" but "how consistently, and how well, across how many teams" — and they're worth recognizing at this conceptual level even if your organization never runs a formal assessment against either one.
1. What is an abuse case, and how does it differ from a standard user story? 2. Name two security checks that happen in the Development phase before code ever reaches a CI pipeline. 3. Why is manual penetration testing usually reserved for high-risk changes instead of run on every pull request? 4. What's the practical difference between OWASP SAMM and BSIMM?
Check your answers
- An abuse case describes how a system could be misused by an attacker, written as the adversarial mirror of a normal user story — it forces a security-relevant design decision before the feature is built, rather than after an incident report.
- Secure coding standards enforced through review (such as the OWASP ASVS), mandatory peer review with security-specific checklist questions, and SAST run in the IDE or as a pre-commit hook.
- It's slow (days to weeks) and expensive (specialist hourly rates), so it doesn't scale to every change — it's targeted at high-risk changes like new auth flows or payment integrations, often on an annual-plus-significant-change cadence.
- SAMM is prescriptive — it defines maturity levels an organization should work toward. BSIMM is descriptive — it reports what real organizations actually do, based on repeated measurement, so a team can benchmark against actual industry practice rather than an idealized target.