Security by Design
OWASP Security Design Principles
Apply these during design -- retrofitting security is 10-100x more expensive.
| # |
Principle |
Architect Action |
| 1 |
Security by Design |
Include security requirements in architecture documents |
| 2 |
Security by Default |
Ship restrictive defaults; require explicit opt-in for relaxed settings |
| 3 |
Defense in Depth |
Layer controls: WAF + input validation + output encoding + parameterized queries |
| 4 |
Fail Secure |
Deny access on error; closed-by-default network policies |
| 5 |
Least Privilege |
Scoped service accounts; time-limited tokens; minimum permissions |
| 6 |
Compartmentalize |
Network segmentation; separate databases per trust level |
| 7 |
Separation of Duties |
Separate deployment approval from code authorship |
| 8 |
Economy of Mechanism |
Minimize attack surface; simple, auditable security code |
| 9 |
Complete Mediation |
Check authorization on every request; no cached auth decisions |
| 10 |
Open Design |
Use published, peer-reviewed algorithms; no security-through-obscurity |
| 11 |
Least Common Mechanism |
Separate admin and user interfaces |
| 12 |
Psychological Acceptability |
Make the secure path the easy path; minimize user friction |
STRIDE Threat Modeling
Apply STRIDE to every component in a Data Flow Diagram (DFD). Four questions drive every session:
- What are we working on? (system model)
- What can go wrong? (threat identification)
- What are we going to do about it? (mitigation)
- Did we do a good enough job? (review)
STRIDE Reference
| Threat |
Violated Property |
Architectural Mitigation |
| Spoofing |
Authentication |
MFA, mutual TLS, certificate pinning, OAuth2+PKCE |
| Tampering |
Integrity |
Input validation, HMAC, parameterized queries, immutable infra |
| Repudiation |
Non-repudiation |
Tamper-evident logging (append-only), digital signatures, SIEM |
| Info Disclosure |
Confidentiality |
Encryption at rest+transit, least privilege, generic error messages |
| Denial of Service |
Availability |
Rate limiting, circuit breakers, auto-scaling, query complexity limits |
| Elevation of Privilege |
Authorization |
Least privilege, RBAC/ABAC, signed tokens verified server-side |
STRIDE per DFD Element
| DFD Element |
Most Relevant Threats |
| External Entity |
Spoofing |
| Process |
All six STRIDE threats |
| Data Store |
Tampering, Info Disclosure, Repudiation, DoS |
| Data Flow |
Tampering, Info Disclosure, DoS |
| Trust Boundary |
Spoofing, Tampering, Elevation of Privilege |
Risk Response Options
| Response |
When |
Example |
| Mitigate |
Probable and impactful; controls feasible |
Add MFA for spoofing on admin login |
| Eliminate |
Remove feature/component entirely |
Remove unused admin API endpoint |
| Transfer |
Better managed by another party |
Use managed IdP (Auth0, Cognito) |
| Accept |
Low risk; mitigation cost exceeds impact |
Accept DoS risk on internal status page |
OWASP Top 10 -- Architectural Prevention
Focus on what the architect decides at design time, not implementation details.
A01: Broken Access Control (61% of breaches)
- Deny by default -- no endpoint open unless explicitly granted
- Centralized authorization service (OPA, Casbin, Cedar), not scattered checks
- Resource-level ownership -- queries scoped to authenticated user
- ABAC over simple RBAC for complex multi-tenant systems
- CORS with explicit origin allowlists -- never wildcards with credentials
A02/A05: Security Misconfiguration (rose to #2 in 2025)
- Infrastructure as Code with security scanning (tfsec, checkov) in CI/CD
- Hardened base images -- minimal containers with security baked in
- Configuration drift detection with automated alerting
- Environment parity -- same hardening across dev/staging/prod
A03: Injection (SQL #2 in CWE Top 25 2025)
- Parameterized queries everywhere -- reject PRs with string concatenation in SQL
- Treat ALL database-sourced data as potentially tainted (second-order injection)
- Allowlisting for dynamic query elements (table names, sort columns)
- Template sandboxing -- user input as DATA, never as template source
A04: Insecure Design (new in 2021)
- Mandate STRIDE analysis as gate for architecture reviews
- Abuse cases alongside every user story ("As an attacker, I want to...")
- State machines with explicit transitions for business logic
- Rate limiting built into architecture from day one
A06/Supply Chain (expanded in 2025)
- SCA scanning on every commit (Snyk, Dependabot)
- SBOM generation as build artifact
- Private package registry; block direct public pulls in production builds
- Lock files committed with integrity hash verification
A07: Authentication Failures
- Centralized IdP (Keycloak, Auth0, Cognito) -- no custom auth per service
- MFA required for sensitive data access and admin functions
- Progressive delays on failed attempts (exponential backoff, not permanent lockout)
- Session ID regeneration on every authentication state change
Secure Architecture Patterns
Zero Trust
Core: "Never trust, always verify" -- no implicit trust from network location.
| Component |
Implementation |
| Identity verification |
OAuth2/OIDC for users; mTLS for services |
| Transport security |
mTLS everywhere; service mesh (Istio, Linkerd) |
| Micro-segmentation |
Network policies limiting service-to-service |
| Continuous verification |
Re-authenticate and re-authorize every request |
| Least privilege access |
Scoped tokens; just-in-time access |
Input Validation Pipeline
User Input
-> Validation (allowlist, type, length, format)
-> Business Logic (parameterized queries, ORM)
-> Output Encoding (context-aware: HTML, JS, URL, CSS)
-> Client
Key: input validation is complementary, not primary defense. Output encoding prevents XSS. Parameterized queries prevent SQLi. Validation adds defense in depth.
Secrets Management
| Pattern |
Implementation |
| Centralized vault |
HashiCorp Vault, AWS Secrets Manager, Azure Key Vault |
| Sidecar injection |
Vault agent injects secrets into pods at runtime |
| Encrypted in repo |
SOPS + KMS for GitOps workflows |
| Pre-commit scanning |
gitleaks or TruffleHog blocks secrets before they reach git |
Rules: never in source code | never in container images | rotate automatically | separate per environment | audit all access.
Required HTTP Security Headers
| Header |
Value |
Purpose |
| Content-Security-Policy |
Strict nonce-based |
Prevent XSS |
| Strict-Transport-Security |
max-age=63072000; includeSubDomains; preload |
Force HTTPS |
| X-Content-Type-Options |
nosniff |
Prevent MIME sniffing |
| X-Frame-Options |
DENY or SAMEORIGIN |
Prevent clickjacking |
| Referrer-Policy |
strict-origin-when-cross-origin |
Control referrer |
| Permissions-Policy |
Feature-specific |
Limit browser APIs |
Security Testing in CI/CD
| Type |
Tests |
Pipeline Stage |
Tools |
| SAST |
Source code vulnerabilities |
Every commit/PR |
Semgrep, CodeQL, SonarQube |
| SCA |
Dependency CVEs |
Build stage |
Snyk, Dependabot, Trivy |
| DAST |
Running application |
Staging |
OWASP ZAP, Burp Suite |
| Secrets |
Leaked credentials |
Pre-commit + CI |
gitleaks, TruffleHog |
Strategy: SAST pre-commit (fast) -> SCA at build -> container scan -> DAST on staging -> block on critical/high findings.
API Security Checklist (OWASP API Top 10)
| # |
Threat |
Architect Decision |
| API1 |
BOLA (~40% of API attacks) |
Object-level authorization in service layer, not just routes |
| API4 |
Unrestricted resource consumption |
Rate limiting per-object, not just per-endpoint |
| API5 |
BFLA |
Separate admin and user API surfaces |
| API6 |
Sensitive business flow abuse |
State machine enforcement, idempotency keys |
| API9 |
Improper inventory management |
API versioning with sunset policies; deprecate old versions |
| API10 |
Unsafe API consumption |
Never trust third-party API responses; validate and sanitize |
GraphQL-Specific
- Disable introspection in production
- Set maximum query depth (10 levels) and complexity limits
- Limit batch size; exclude sensitive operations from batching
- Field-level authorization in resolvers
Defensive Coding Patterns (Cross-Reference for Crafters)
| Risk |
Vulnerable Pattern |
Secure Alternative |
| SQL Injection |
f"SELECT * FROM users WHERE name = '{name}'" |
Parameterized: cursor.execute("... WHERE name = %s", (name,)) |
| Deserialization |
pickle.loads(untrusted) |
json.loads(untrusted) or Pydantic schema validation |
| Command Injection |
os.system(f"cmd {input}") |
subprocess.run(["cmd", input], shell=False) |
| SSTI |
Template(user_input) |
env.from_string(trusted).render(data=user_input) |
| Mass Assignment |
User(**request.json()) |
DTO with explicit fields, server-set for sensitive |
| TOCTOU Race |
Read-check-write in separate steps |
Atomic conditional update (UPDATE ... WHERE condition) |
| Prototype Pollution (JS) |
Object.assign(target, untrusted) |
Map, null-prototype objects, strict schema validation |
Source: nWave-ai/nWave → nWave/skills/nw-security-by-design/SKILL.md
Also appears in: nWave-ai/nWave/plugins/nw/skills/nw-security-by-design/SKILL.md
1---2name: nw-security-by-design3description: Security design principles, STRIDE threat modeling, OWASP Top 10 architectural mitigations, and secure patterns. Load when designing systems or reviewing architecture for security.4---567# Security by Design89## OWASP Security Design Principles1011Apply these during design -- retrofitting security is 10-100x more expensive.1213| # | Principle | Architect Action |14|---|-----------|-----------------|15| 1 | Security by Design | Include security requirements in architecture documents |16| 2 | Security by Default | Ship restrictive defaults; require explicit opt-in for relaxed settings |17| 3 | Defense in Depth | Layer controls: WAF + input validation + output encoding + parameterized queries |18| 4 | Fail Secure | Deny access on error; closed-by-default network policies |19| 5 | Least Privilege | Scoped service accounts; time-limited tokens; minimum permissions |20| 6 | Compartmentalize | Network segmentation; separate databases per trust level |21| 7 | Separation of Duties | Separate deployment approval from code authorship |22| 8 | Economy of Mechanism | Minimize attack surface; simple, auditable security code |23| 9 | Complete Mediation | Check authorization on every request; no cached auth decisions |24| 10 | Open Design | Use published, peer-reviewed algorithms; no security-through-obscurity |25| 11 | Least Common Mechanism | Separate admin and user interfaces |26| 12 | Psychological Acceptability | Make the secure path the easy path; minimize user friction |2728## STRIDE Threat Modeling2930Apply STRIDE to every component in a Data Flow Diagram (DFD). Four questions drive every session:311. What are we working on? (system model)322. What can go wrong? (threat identification)333. What are we going to do about it? (mitigation)344. Did we do a good enough job? (review)3536### STRIDE Reference3738| Threat | Violated Property | Architectural Mitigation |39|--------|-------------------|--------------------------|40| **Spoofing** | Authentication | MFA, mutual TLS, certificate pinning, OAuth2+PKCE |41| **Tampering** | Integrity | Input validation, HMAC, parameterized queries, immutable infra |42| **Repudiation** | Non-repudiation | Tamper-evident logging (append-only), digital signatures, SIEM |43| **Info Disclosure** | Confidentiality | Encryption at rest+transit, least privilege, generic error messages |44| **Denial of Service** | Availability | Rate limiting, circuit breakers, auto-scaling, query complexity limits |45| **Elevation of Privilege** | Authorization | Least privilege, RBAC/ABAC, signed tokens verified server-side |4647### STRIDE per DFD Element4849| DFD Element | Most Relevant Threats |50|-------------|----------------------|51| External Entity | Spoofing |52| Process | All six STRIDE threats |53| Data Store | Tampering, Info Disclosure, Repudiation, DoS |54| Data Flow | Tampering, Info Disclosure, DoS |55| Trust Boundary | Spoofing, Tampering, Elevation of Privilege |5657### Risk Response Options5859| Response | When | Example |60|----------|------|---------|61| Mitigate | Probable and impactful; controls feasible | Add MFA for spoofing on admin login |62| Eliminate | Remove feature/component entirely | Remove unused admin API endpoint |63| Transfer | Better managed by another party | Use managed IdP (Auth0, Cognito) |64| Accept | Low risk; mitigation cost exceeds impact | Accept DoS risk on internal status page |6566## OWASP Top 10 -- Architectural Prevention6768Focus on what the architect decides at design time, not implementation details.6970### A01: Broken Access Control (61% of breaches)7172- Deny by default -- no endpoint open unless explicitly granted73- Centralized authorization service (OPA, Casbin, Cedar), not scattered checks74- Resource-level ownership -- queries scoped to authenticated user75- ABAC over simple RBAC for complex multi-tenant systems76- CORS with explicit origin allowlists -- never wildcards with credentials7778### A02/A05: Security Misconfiguration (rose to #2 in 2025)7980- Infrastructure as Code with security scanning (tfsec, checkov) in CI/CD81- Hardened base images -- minimal containers with security baked in82- Configuration drift detection with automated alerting83- Environment parity -- same hardening across dev/staging/prod8485### A03: Injection (SQL #2 in CWE Top 25 2025)8687- Parameterized queries everywhere -- reject PRs with string concatenation in SQL88- Treat ALL database-sourced data as potentially tainted (second-order injection)89- Allowlisting for dynamic query elements (table names, sort columns)90- Template sandboxing -- user input as DATA, never as template source9192### A04: Insecure Design (new in 2021)9394- Mandate STRIDE analysis as gate for architecture reviews95- Abuse cases alongside every user story ("As an attacker, I want to...")96- State machines with explicit transitions for business logic97- Rate limiting built into architecture from day one9899### A06/Supply Chain (expanded in 2025)100101- SCA scanning on every commit (Snyk, Dependabot)102- SBOM generation as build artifact103- Private package registry; block direct public pulls in production builds104- Lock files committed with integrity hash verification105106### A07: Authentication Failures107108- Centralized IdP (Keycloak, Auth0, Cognito) -- no custom auth per service109- MFA required for sensitive data access and admin functions110- Progressive delays on failed attempts (exponential backoff, not permanent lockout)111- Session ID regeneration on every authentication state change112113## Secure Architecture Patterns114115### Zero Trust116117Core: "Never trust, always verify" -- no implicit trust from network location.118119| Component | Implementation |120|-----------|---------------|121| Identity verification | OAuth2/OIDC for users; mTLS for services |122| Transport security | mTLS everywhere; service mesh (Istio, Linkerd) |123| Micro-segmentation | Network policies limiting service-to-service |124| Continuous verification | Re-authenticate and re-authorize every request |125| Least privilege access | Scoped tokens; just-in-time access |126127### Input Validation Pipeline128129```130User Input131 -> Validation (allowlist, type, length, format)132 -> Business Logic (parameterized queries, ORM)133 -> Output Encoding (context-aware: HTML, JS, URL, CSS)134 -> Client135```136137Key: input validation is complementary, not primary defense. Output encoding prevents XSS. Parameterized queries prevent SQLi. Validation adds defense in depth.138139### Secrets Management140141| Pattern | Implementation |142|---------|---------------|143| Centralized vault | HashiCorp Vault, AWS Secrets Manager, Azure Key Vault |144| Sidecar injection | Vault agent injects secrets into pods at runtime |145| Encrypted in repo | SOPS + KMS for GitOps workflows |146| Pre-commit scanning | gitleaks or TruffleHog blocks secrets before they reach git |147148Rules: never in source code | never in container images | rotate automatically | separate per environment | audit all access.149150### Required HTTP Security Headers151152| Header | Value | Purpose |153|--------|-------|---------|154| Content-Security-Policy | Strict nonce-based | Prevent XSS |155| Strict-Transport-Security | `max-age=63072000; includeSubDomains; preload` | Force HTTPS |156| X-Content-Type-Options | `nosniff` | Prevent MIME sniffing |157| X-Frame-Options | `DENY` or `SAMEORIGIN` | Prevent clickjacking |158| Referrer-Policy | `strict-origin-when-cross-origin` | Control referrer |159| Permissions-Policy | Feature-specific | Limit browser APIs |160161## Security Testing in CI/CD162163| Type | Tests | Pipeline Stage | Tools |164|------|-------|---------------|-------|165| SAST | Source code vulnerabilities | Every commit/PR | Semgrep, CodeQL, SonarQube |166| SCA | Dependency CVEs | Build stage | Snyk, Dependabot, Trivy |167| DAST | Running application | Staging | OWASP ZAP, Burp Suite |168| Secrets | Leaked credentials | Pre-commit + CI | gitleaks, TruffleHog |169170Strategy: SAST pre-commit (fast) -> SCA at build -> container scan -> DAST on staging -> block on critical/high findings.171172## API Security Checklist (OWASP API Top 10)173174| # | Threat | Architect Decision |175|---|--------|--------------------|176| API1 | BOLA (~40% of API attacks) | Object-level authorization in service layer, not just routes |177| API4 | Unrestricted resource consumption | Rate limiting per-object, not just per-endpoint |178| API5 | BFLA | Separate admin and user API surfaces |179| API6 | Sensitive business flow abuse | State machine enforcement, idempotency keys |180| API9 | Improper inventory management | API versioning with sunset policies; deprecate old versions |181| API10 | Unsafe API consumption | Never trust third-party API responses; validate and sanitize |182183### GraphQL-Specific184185- Disable introspection in production186- Set maximum query depth (10 levels) and complexity limits187- Limit batch size; exclude sensitive operations from batching188- Field-level authorization in resolvers189190## Defensive Coding Patterns (Cross-Reference for Crafters)191192| Risk | Vulnerable Pattern | Secure Alternative |193|------|-------------------|-------------------|194| SQL Injection | `f"SELECT * FROM users WHERE name = '{name}'"` | Parameterized: `cursor.execute("... WHERE name = %s", (name,))` |195| Deserialization | `pickle.loads(untrusted)` | `json.loads(untrusted)` or Pydantic schema validation |196| Command Injection | `os.system(f"cmd {input}")` | `subprocess.run(["cmd", input], shell=False)` |197| SSTI | `Template(user_input)` | `env.from_string(trusted).render(data=user_input)` |198| Mass Assignment | `User(**request.json())` | DTO with explicit fields, server-set for sensitive |199| TOCTOU Race | Read-check-write in separate steps | Atomic conditional update (`UPDATE ... WHERE condition`) |200| Prototype Pollution (JS) | `Object.assign(target, untrusted)` | `Map`, null-prototype objects, strict schema validation |201202---203204**Source:** [`nWave-ai/nWave`](https://github.com/nWave-ai/nWave) → `nWave/skills/nw-security-by-design/SKILL.md`205206**Also appears in:** `nWave-ai/nWave/plugins/nw/skills/nw-security-by-design/SKILL.md`