Most application vulnerabilities are design or coding mistakes, and fixing them late is expensive. Secure software development means making security a normal part of how software is specified, written, tested, shipped and maintained, rather than a penetration test bolted on at the end. This page is the defender's view; the attacker's view is in OWASP Top 10 and Application Attacks.
The short DevSecOps note in Security Controls introduces the idea of "shift left"; this page expands it.
Security in Each SDLC Phase
Requirements -> Design -> Implementation -> Testing -> Deployment -> Maintenance
| | | | | |
security threat secure coding SAST/DAST hardened patching,
& privacy modelling code review SCA, fuzz config, monitoring,
reqs arch review secrets scan pen test signed disclosure,
artifacts retirement
| Phase | Security activities |
|---|---|
| Requirements | Identify data sensitivity, regulatory needs, abuse cases ("how would someone misuse this?"), authentication/authorisation needs. See Security Requirements. |
| Design | Threat modelling (STRIDE etc.), secure architecture patterns, trust boundaries, data flow review, choose vetted libraries and frameworks. See Security Architecture Principles. |
| Implementation | Secure coding standards, peer code review, IDE linters, pre-commit secret scanning. |
| Testing | SAST, DAST, IAST, SCA, fuzzing, security unit tests, pen test before major releases. |
| Deployment | Hardened images and configuration, secrets injected at runtime, signed artifacts, least-privilege deploy identities. See System Hardening. |
| Maintenance | Dependency updates, patching, monitoring, incident handling, vulnerability disclosure, secure decommissioning. See Vulnerability and Patch Management. |
Treat changes through the process described in Change Management: reviewed, tested, reversible.
Secure Coding Principles
| Principle | What it means | Defends against |
|---|---|---|
| Validate input | Treat all input (forms, headers, files, APIs, other services) as untrusted; validate type, length, range and format with an allow-list | Injection, path traversal, file upload abuse |
| Encode output | Encode for the context it lands in (HTML, attribute, JS, URL, SQL) | Cross-site scripting |
| Parameterised queries | Keep data separate from commands; never build SQL or shell strings by concatenation | SQL injection, command injection |
| Least privilege | App accounts, database users and service tokens get only what they need | Limits blast radius of any bug |
| Fail securely, handle errors | Deny on error; show generic messages to users, log detail server-side; never leak stack traces or secrets | Information disclosure |
| Strong authn/authz | Use proven libraries; check authorisation on every request on the server side | Broken access control, IDOR |
| Secrets management | No credentials in source, images or logs; use a secrets manager and rotate | Credential leaks |
| Use vetted crypto | Standard libraries and algorithms, never home-made; see Cryptographic Solutions | Weak or broken cryptography |
| Defence in depth | Several independent controls, not one filter | Single control failure |
| Minimise attack surface | Remove unused features, endpoints, dependencies and debug modes | Reduces exposure |
Example of the most important fix:
# Vulnerable: attacker input becomes part of the SQL command
cur.execute("SELECT * FROM users WHERE name = '" + name + "'")
# Safe: parameterised, data can never change the query structure
cur.execute("SELECT * FROM users WHERE name = %s", (name,))
Security Testing Methods
| Method | How it works | Strength | Limitation |
|---|---|---|---|
| Code review | Humans read changes, ideally with a security checklist | Finds logic and design flaws | Depends on reviewer skill |
| SAST (static) | Analyses source or bytecode without running it | Early, in the IDE/CI, pinpoints the line | False positives, misses runtime/config issues |
| DAST (dynamic) | Probes the running app from outside like an attacker | Finds real exploitable issues, language-agnostic | Late, limited code coverage |
| IAST (interactive) | Agent inside the running app observes tests | Accurate, shows code path | Needs instrumentation and good test traffic |
| SCA (composition analysis) | Matches dependencies against known vulnerabilities and licences | Catches vulnerable libraries | Only known issues |
| Fuzzing | Sends malformed or random input to find crashes | Finds parser and memory bugs | Needs harness and time |
| Penetration test | Authorised manual attack, see Penetration Testing Methodology | Chains issues like a real attacker | Point-in-time, costly |
No single method is enough; combine them. Findings feed vulnerability management and are prioritised by exploitability and impact, not scanner severity alone. See Vulnerability Scanning for scanner concepts.
Software Supply Chain Security
Modern applications are mostly third-party code. An attacker who compromises a dependency, build system or update channel reaches every consumer.
| Threat | Control |
|---|---|
| Vulnerable dependency | SCA scanning, timely updates |
| Typosquatting / dependency confusion (malicious package with a similar or internal-looking name) | Verify package names, use private registry with scoped namespaces, allow-list sources |
| Malicious or hijacked maintainer release | Pin versions and use lock files with hashes; review upgrade diffs; delay adoption of brand-new releases |
| Compromised build system | Isolated, ephemeral build runners; protect pipeline credentials; two-person review on pipeline changes |
| Tampered artifact | Signed builds and provenance attestations; verify signatures at deploy |
| Unknown contents | Generate an SBOM (software bill of materials: machine-readable list of components and versions, e.g. SPDX or CycloneDX) for every release, so you can answer "are we affected?" within minutes when a new vulnerability is announced |
Regulation increasingly expects this; see Cyber Resilience Act.
CI/CD Pipeline Security and DevSecOps
DevSecOps automates security checks as gates in the pipeline so feedback arrives while the developer still has context (shift left).
commit -> pre-commit hooks -> build -> test -> package -> deploy -> run
secret scan SAST DAST sign policy monitor
lint SCA unit SBOM checks runtime
IaC scan image approval protection
scan
Typical gates:
- Block merge on secrets found, critical SAST findings or known-exploited dependency vulnerabilities (with a documented exception process).
- Scan infrastructure-as-code and container images before deploy.
- Require reviewed pull requests, protected branches and signed commits.
- Deploy with short-lived credentials (federated identity), not static keys stored in CI variables.
- Separate duties: the person who writes code cannot alone push it to production.
Tune gates to keep false positives low; a noisy gate gets bypassed. The pipeline itself is a high-value target and needs the same hardening as production (see Cloud Security).
Vulnerability Disclosure and Bug Bounty
- Security.txt / VDP: publish a security contact (
/.well-known/security.txt) and a vulnerability disclosure policy stating how to report, scope, safe-harbour for good-faith research and expected response times. - Coordinated disclosure: reporter and vendor agree a fix window (commonly 90 days) before public details.
- Bug bounty: a paid programme (often via a platform) rewarding valid reports within a defined scope and rules. Needs triage capacity; run a VDP first.
- Track reports like any vulnerability: acknowledge, reproduce, fix, release advisory, credit the reporter. Use CVE IDs where applicable.
Maturity Frameworks (named only)
- NIST SSDF (Secure Software Development Framework)
- OWASP SAMM (Software Assurance Maturity Model)
- BSIMM (Building Security In Maturity Model)
See Security Frameworks for how frameworks fit together.
Key Points
- Fix problems early: requirements and design flaws cost most when found in production.
- Core coding defences: validate input, encode output, parameterise queries, least privilege, safe error handling, no hard-coded secrets.
- Combine SAST, DAST, IAST, SCA, fuzzing, code review and periodic pen tests.
- Know what you ship: SBOM, pinned dependencies, signed builds.
- Automate security gates in CI/CD, and secure the pipeline itself.
- Give outsiders a clear way to report vulnerabilities.