Map Security Controls to SDLC
Learn to map security controls to the SDLC in this practical Secure development tutorial. Understand the core concept, apply it in a hands-on exercise, and connect it to the next lesson.
Focus: map security controls to the sdlc
Ever had a security reviewer block your release because "security wasn't considered early enough"? You're not alone. Security flaws are cheapest to fix when they're caught in requirements and design — but most teams bolt security on at the end, leading to costly rework and embarrassing incidents. This lesson shows you how to map security controls to the SDLC so that security is a planned, continuous activity — not a late-stage afterthought. By the end, you'll be able to identify precisely which controls to apply in each phase of your software development lifecycle (SDLC), and you'll have a working mapping table you can adapt for your own projects.
The problem this lesson solves
Most engineers I've worked with know what security controls exist (firewalls, authentication, encryption, input validation) but have no idea when to apply them. So they default to "security at the end." That's like building a house and only adding smoke detectors after a fire starts — far too late and enormously more expensive.
Studies consistently show that fixing a security defect in production costs 30 to 60 times more than fixing it during requirements or design. Whether you're following a traditional Waterfall or a modern Continuous Integration/Continuous Deployment (CI/CD) pipeline, every phase of the SDLC introduces specific security risks. If you don't map controls to those phases, you'll either over-engineer early or under-protect late — both are bad outcomes.
The pain: Without a clear mapping, security decisions become reactive. The DevSecOps movement exists because teams realized that security must be "shifted left" into the SDLC. This lesson gives you a concrete framework to do exactly that.
Core concept / mental model
Think of the SDLC as a conveyor belt that moves code from an idea to production. Each segment of that belt — plan, design, build, test, deploy, operate — has different risks. A security control is a specific measurement or activity that reduces risk at a given point on the belt.
Mapping security controls to the SDLC means you deliberately place the right control at the right phase. For example:
- Plan: Threat modeling sessions to identify risks before code is written.
- Design: Security architecture reviews and design patterns that prevent common flaws.
- Build: Static analysis, dependency scanning, and secure coding standards.
- Test: Dynamic analysis, penetration testing, and fuzzing.
- Deploy: Configuration validation, infrastructure scanning, and secret management.
- Operate: Monitoring, logging, incident response, and patch management.
Visually, you can think of a table where rows are phases and columns are control categories (preventive, detective, corrective). A complete mapping has at least one control for every phase–risk cell.
How it works step by step
1. List your SDLC phases
Start with a standard model (Waterfall or Agile) — or your own internal phases. The classic six are: Plan, Design, Build, Test, Deploy, Operate.
2. Identify likely risks per phase
For each phase, ask: "What could go wrong here that compromises confidentiality, integrity, or availability (CIA)?"
- Plan: Insufficient requirements, scope creep, wrong architecture.
- Design: Flawed threat model, insecure data flow.
- Build: Insecure code, vulnerable dependencies, hardcoded secrets.
- Test: Missed edge cases, false negatives in scanning.
- Deploy: Misconfigured infrastructure, exposed credentials.
- Operate: Unpatched servers, no monitoring, slow incident response.
3. Select controls that address those risks
Pick controls from standard frameworks like OWASP, NIST SP 800-53, or ISO 27001. For each risk, choose at least one preventive, detective, and corrective control where feasible.
4. Document the mapping in a table
Create a living document — a simple Markdown table or a spreadsheet — that maps phase → risk → control → owner → evidence. This becomes your audit trail.
5. Review and update the map at every phase gate
Before moving from one phase to the next, require that the mapped controls are executed. This enforces security at each step and makes the process measurable.
Hands-on walkthrough
Let's make this concrete. You're building a Python web application. You'll create a mapping table in YAML and a small script to validate that every phase has at least one control.
Step 1: Create the mapping file
Create sdlc_security_map.yaml:
phases:
plan:
controls:
- name: Threat modeling
type: preventive
owner: Architecture Team
- name: Security requirements review
type: detective
owner: Product Owner
design:
controls:
- name: Security architecture review
type: preventive
owner: Security Architect
- name: Data flow diagram review
type: detective
owner: Security Architect
build:
controls:
- name: Static application security testing (SAST)
type: detective
owner: Dev Team
- name: Dependency scanning
type: detective
owner: Dev Team
- name: Secure coding standards enforcement
type: preventive
owner: Dev Team
test:
controls:
- name: Dynamic application security testing (DAST)
type: detective
owner: QA
- name: Penetration testing
type: detective
owner: Security Team
- name: Fuzzing
type: detective
owner: QA
deploy:
controls:
- name: Infrastructure as Code (IaC) scanning
type: detective
owner: DevOps
- name: Secret management scan
type: detective
owner: DevOps
- name: Configuration validation
type: preventive
owner: DevOps
operate:
controls:
- name: Centralized logging & monitoring
type: detective
owner: SRE
- name: Incident response plan
type: corrective
owner: Security Team
- name: Patch management process
type: corrective
owner: Ops Team
Step 2: Validate the mapping with Python
import yaml
from pathlib import Path
required_phases = ["plan", "design", "build", "test", "deploy", "operate"]
def load_mapping(path: Path) -> dict:
return yaml.safe_load(path.read_text())
def validate_mapping(mapping: dict) -> None:
phases = mapping.get("phases", {})
missing_phases = [p for p in required_phases if p not in phases]
if missing_phases:
raise ValueError(f"Missing phases: {missing_phases}")
for phase in required_phases:
controls = phases[phase].get("controls", [])
if not controls:
print(f"[WARN] Phase '{phase}' has no controls.")
else:
types = [c.get("type") for c in controls]
if "preventive" not in types:
print(f"[WARN] Phase '{phase}' lacks a preventive control.")
if "detective" not in types:
print(f"[WARN] Phase '{phase}' lacks a detective control.")
print("Mapping validation complete.")
if __name__ == "__main__":
mapping = load_mapping(Path("sdlc_security_map.yaml"))
validate_mapping(mapping)
Expected output (if mapping is complete):
Mapping validation complete.
If a phase is missing, you'll get warnings. You can extend this script to fail on warnings in CI, enforcing at least one preventive and detective control per phase.
Step 3: Generate a Markdown report
import yaml
from pathlib import Path
def generate_report(mapping: dict) -> str:
lines = ["# SDLC Security Controls Mapping\n"]
for phase, data in mapping["phases"].items():
lines.append(f"## {phase.capitalize()}\n")
lines.append("| Control | Type | Owner |")
lines.append("|---------|------|-------|")
for c in data["controls"]:
lines.append(f"| {c['name']} | {c['type']} | {c['owner']} |")
lines.append("")
return "\n".join(lines)
mapping = yaml.safe_load(Path("sdlc_security_map.yaml").read_text())
Path("sdlc_security_report.md").write_text(generate_report(mapping))
print("Report generated: sdlc_security_report.md")
Run python generate_report.py and you'll get a clean Markdown table for your docs or internal audit.
Compare options / when to choose what
When mapping security controls, you'll often choose between different frameworks or tools. Here's a quick comparison:
| Framework / Tool | Best for | When to choose |
|---|---|---|
| OWASP ASVS | Web application security | You're building web apps and want detailed, verifiable requirements |
| NIST SP 800-53 | Enterprise compliance | You need a comprehensive catalog for regulated industries (e.g., finance, healthcare) |
| ISO 27001 | Organization-wide security management | You want an ISMS that covers people, process, and technology — not just code |
| Custom mapping | Agile teams or startups | You need something lightweight and tailored to your stack — fast to update |
Key takeaway: Start with OWASP for day-to-day development; use NIST or ISO when you need formal compliance evidence. A custom table is fine for your internal workflow, but it must be audited and updated regularly.
Troubleshooting & edge cases
Problem 1: "We have security controls, but we still got breached"
- Cause: Controls were not mapped to the specific phases where the risk lives — e.g., you have DAST in test but no input validation in build.
- Fix: Reassess per phase; don't rely on a single control type.
Problem 2: "Our map is outdated after an agile iteration"
- Cause: The mapping is a one-time artifact, not a living document.
- Fix: Update the YAML file as part of your Definition of Done for every story or sprint. Make validation part of CI.
Problem 3: "We have too many controls, we drown in process"
- Cause: Over-selecting controls without prioritizing risks.
- Fix: Use a risk matrix — focus on controls that address high-likelihood, high-impact risks. Cut redundant ones.
Problem 4: "YAML file fails to load due to missing dependency (yaml)"
pip install pyyaml
If you see ModuleNotFoundError, that's the fix.
Edge case: Legacy systems
For existing code, map controls to the operations phase first (monitoring, patching) before demanding rework. You can gradually shift left in future iterations.
What you learned & what's next
You now understand that mapping security controls to the SDLC is the act of deliberately placing appropriate controls at each phase of development to reduce risk. You learned a five-step method, created a YAML mapping, and automated validation to enforce completeness. This transforms security from a last-minute scramble into a measurable, repeatable process.
Next in this track, you'll go deeper into input validation posture — applying one of the preventive controls from the build phase to stop vulnerabilities before they hit production. You'll practice writing validation for real-world Python code, so you can see the payoff of your mapping. Let's continue.
Practice recap
Create your own sdlc_security_map.yaml for a project you're working on — list at least one control per phase and run the validation script. Then generate the Markdown report and share it with your team. Next, try adding the validation as a pre-merge check in your CI pipeline.
Common mistakes
- Trying to enforce every control in every phase — over-engineering security and slowing delivery.
- Creating the mapping once and never revisiting it — then it drifts from reality and gives false assurance.
- Forgetting to include a control for dependency management in the build phase, which is a top attack vector.
- Relying only on detective controls (like SAST) and skipping preventive ones (like secure coding standards), leaving vulnerabilities in from the start.
Variations
- Use a spreadsheet instead of YAML — simpler for non-technical stakeholders, but harder to automate.
- Adopt a formal framework like OWASP SAMM or BSIMM to benchmark your mapping against industry best practices.
- Integrate mapping validation into your CI pipeline to block merges if any phase lacks required control types.
Real-world use cases
- A fintech startup automating compliance by mapping SDLC controls to NIST SP 800-53 for audits.
- A DevOps team using a CI script to enforce that every deployment includes secret scanning and config validation.
- A product manager running threat modeling in the planning phase to avoid costly design flaws in a new microservice.
Key takeaways
- Security controls must be mapped to specific SDLC phases to reduce risk effectively and cost-efficiently.
- A simple YAML or table can document your mapping, making it audit-ready and easy to update.
- Each phase needs at least one preventive and one detective control to balance proactivity and detection.
- Automate mapping validation so security is enforced in CI, not just documented.
- Use frameworks like OWASP, NIST, or ISO as references, but tailor them to your team's context.
- Map controls for legacy systems first in the operations phase, then gradually shift left.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.