Threat Modeling11 min read

Security in Design Reviews: Building Security into Architecture from Day One

Integrating security analysis into design reviews through threat modeling, architecture patterns, and collaborative review processes that prevent vulnerabilities before code is written.

DR

Security Architecture Team

Design & Architecture

Introduction

The most cost-effective time to fix a security vulnerability is before it's coded. Security design reviews integrate threat modeling and security architecture principles into the software design process, catching issues when they're just diagrams instead of deployed code. This guide shows how to run effective security design reviews that build security in from the start.

1. When to Conduct Security Design Reviews

Trigger Criteria

Mandatory Security Design Review for:

  • New applications or major features
  • Changes to authentication/authorization
  • New data storage or processing systems
  • External integrations or APIs
  • Architecture changes affecting security boundaries
  • Handling of sensitive data (PII, PHI, PCI)
  • Public-facing services or APIs
  • Privilege elevation mechanisms

Review Process Integration

// Design review checklist template
interface DesignReviewRequest {
  title: string;
  type: 'new-feature' | 'architecture-change' | 'integration' | 'security-control';
  submitter: string;
  architectureDiagram: string;  // URL to diagram
  dataFlowDiagram: string;
  threatModel: string;          // Completed threat model document
  securityControls: string[];
  sensitiveData: {
    types: string[];
    storage: string;
    encryption: boolean;
    retention: string;
  };
  externalDependencies: string[];
  complianceRequirements: string[];
  securityReviewer: string;
}

// Automated workflow
const designReviewWorkflow = {
  steps: [
    { name: 'Submit Design', owner: 'Engineer' },
    { name: 'Completeness Check', owner: 'Tech Lead', automatable: true },
    { name: 'Security Review', owner: 'Security Architect' },
    { name: 'Threat Modeling Session', owner: 'Team + Security' },
    { name: 'Mitigation Planning', owner: 'Engineer' },
    { name: 'Approval', owner: 'Security Architect' },
    { name: 'Implementation Tracking', owner: 'Engineer' }
  ]
};

2. Security Design Review Framework

Architecture Assessment

// Security architecture questionnaire
const securityQuestions = {
  authentication: [
    'How do users/services authenticate?',
    'Is MFA enforced for sensitive operations?',
    'How are credentials stored and transmitted?',
    'What is the session management strategy?',
    'How do you handle password resets?'
  ],
  
  authorization: [
    'What authorization model is used (RBAC, ABAC)?',
    'How are permissions checked?',
    'Where is authorization enforced (client, gateway, service)?',
    'How do you prevent privilege escalation?',
    'Are there admin/super-user accounts?'
  ],
  
  dataProtection: [
    'What sensitive data is processed?',
    'Is data encrypted at rest and in transit?',
    'How long is data retained?',
    'Who has access to production data?',
    'Are there data backup and recovery procedures?'
  ],
  
  inputValidation: [
    'Where is user input validated?',
    'How do you prevent injection attacks?',
    'Is there output encoding/escaping?',
    'What file upload restrictions exist?',
    'How do you handle malformed data?'
  ],
  
  logging: [
    'What security events are logged?',
    'Are logs tamper-proof?',
    'Where are logs stored and for how long?',
    'Who has access to logs?',
    'Is PII excluded from logs?'
  ],
  
  errorHandling: [
    'How are errors handled?',
    'Do error messages leak sensitive info?',
    'Is there monitoring for unusual errors?',
    'What happens on system failures?'
  ],
  
  dependencies: [
    'What third-party libraries are used?',
    'How are dependencies kept up-to-date?',
    'Are there supply chain security controls?',
    'What external services are integrated?'
  ],
  
  deployment: [
    'What is the deployment model (cloud, on-prem)?',
    'How is the application isolated?',
    'What network controls exist?',
    'How are secrets managed?',
    'Is there a rollback procedure?'
  ]
};

// Scoring mechanism
function scoreDesign(answers: Record<string, any>): {score: number, findings: string[]} {
  let score = 100;
  const findings = [];
  
  if (!answers.authentication.mfa) {
    score -= 15;
    findings.push('MFA not enforced - HIGH RISK');
  }
  
  if (!answers.dataProtection.encryptionAtRest) {
    score -= 20;
    findings.push('No encryption at rest for sensitive data - CRITICAL');
  }
  
  if (answers.authorization.clientSide) {
    score -= 25;
    findings.push('Client-side authorization checks - CRITICAL');
  }
  
  return { score, findings };
}

Common Security Anti-Patterns

// Anti-pattern detection
const securityAntiPatterns = {
  authentication: {
    'Rolling your own crypto': {
      severity: 'CRITICAL',
      description: 'Custom authentication instead of proven libraries',
      remediation: 'Use established libraries like Passport.js, Spring Security, or managed services'
    },
    'Client-side secrets': {
      severity: 'CRITICAL',
      description: 'API keys or secrets in client-side code',
      remediation: 'Move secrets to backend, use backend-for-frontend pattern'
    }
  },
  
  authorization: {
    'IDOR vulnerabilities': {
      severity: 'HIGH',
      description: 'Direct object references without ownership checks',
      example: '/api/users/123 accessible without checking if user owns resource',
      remediation: 'Always verify ownership/permissions before accessing resources'
    },
    'Role confusion': {
      severity: 'HIGH',
      description: 'Multiple authorization mechanisms creating gaps',
      remediation: 'Centralize authorization logic, use policy engine'
    }
  },
  
  dataHandling: {
    'PII in logs': {
      severity: 'HIGH',
      description: 'Logging sensitive user data',
      remediation: 'Implement log scrubbing, use structured logging with PII filtering'
    },
    'Unencrypted backups': {
      severity: 'CRITICAL',
      description: 'Database backups without encryption',
      remediation: 'Enable backup encryption, encrypt before backup'
    }
  },
  
  network: {
    'Flat network': {
      severity: 'MEDIUM',
      description: 'All services in same network with full connectivity',
      remediation: 'Implement network segmentation, use service mesh'
    },
    'Database internet-accessible': {
      severity: 'CRITICAL',
      description: 'Production database with public IP',
      remediation: 'Move to private subnet, remove public IP, use VPN/bastion'
    }
  }
};

// Automated anti-pattern detection
function detectAntiPatterns(design: DesignDocument): Finding[] {
  const findings = [];
  
  // Check architecture diagram
  if (design.diagram.includes('database') && design.diagram.includes('internet')) {
    findings.push({
      antiPattern: 'Database internet-accessible',
      severity: 'CRITICAL',
      location: 'Architecture diagram'
    });
  }
  
  // Check for client-side auth
  if (design.clientCode.includes('API_KEY') || design.clientCode.includes('SECRET')) {
    findings.push({
      antiPattern: 'Client-side secrets',
      severity: 'CRITICAL',
      location: 'Client implementation'
    });
  }
  
  return findings;
}

3. Threat Modeling in Design Review

STRIDE Analysis Template

// Structured threat modeling
interface ThreatModel {
  component: string;
  dataFlow: string;
  threats: Threat[];
}

interface Threat {
  category: 'Spoofing' | 'Tampering' | 'Repudiation' | 'InfoDisclosure' | 'DoS' | 'Elevation';
  description: string;
  likelihood: 'Low' | 'Medium' | 'High';
  impact: 'Low' | 'Medium' | 'High';
  risk: number;  // likelihood * impact
  mitigation: string;
  status: 'Identified' | 'Mitigated' | 'Accepted' | 'Transferred';
}

// Example: API Gateway threat model
const apiGatewayThreats: ThreatModel = {
  component: 'API Gateway',
  dataFlow: 'Internet -> API Gateway -> Backend Services',
  threats: [
    {
      category: 'Spoofing',
      description: 'Attacker impersonates legitimate user',
      likelihood: 'High',
      impact: 'High',
      risk: 9,
      mitigation: 'Implement OAuth 2.0 with PKCE, require MFA for sensitive operations',
      status: 'Mitigated'
    },
    {
      category: 'Tampering',
      description: 'Request payload modified in transit',
      likelihood: 'Medium',
      impact: 'High',
      risk: 6,
      mitigation: 'Enforce TLS 1.3, implement request signing',
      status: 'Mitigated'
    },
    {
      category: 'Repudiation',
      description: 'User denies making API request',
      likelihood: 'Low',
      impact: 'Medium',
      risk: 2,
      mitigation: 'Comprehensive audit logging with request IDs, non-repudiable logs',
      status: 'Mitigated'
    },
    {
      category: 'InfoDisclosure',
      description: 'Error messages leak implementation details',
      likelihood: 'Medium',
      impact: 'Medium',
      risk: 4,
      mitigation: 'Generic error messages in production, detailed logging server-side only',
      status: 'Mitigated'
    },
    {
      category: 'DoS',
      description: 'API overwhelmed with requests',
      likelihood: 'High',
      impact: 'High',
      risk: 9,
      mitigation: 'Rate limiting (100 req/min per user), CAPTCHA for public endpoints, DDoS protection',
      status: 'Mitigated'
    },
    {
      category: 'Elevation',
      description: 'Attacker gains admin privileges',
      likelihood: 'Low',
      impact: 'High',
      risk: 5,
      mitigation: 'Strict RBAC, no privilege escalation paths, separate admin API with additional auth',
      status: 'Mitigated'
    }
  ]
};

// Generate threat model report
function generateThreatReport(model: ThreatModel): string {
  const highRiskThreats = model.threats.filter(t => t.risk >= 6);
  const unmitigatedThreats = model.threats.filter(t => t.status === 'Identified');
  
  return `
# Threat Model: ${model.component}

## Data Flow
${model.dataFlow}

## High Risk Threats (${highRiskThreats.length})
${highRiskThreats.map(t => `
- **[${t.category}]** ${t.description}
  - Risk: ${t.risk}/9 (${t.likelihood} likelihood, ${t.impact} impact)
  - Mitigation: ${t.mitigation}
  - Status: ${t.status}
`).join('')}

## Action Items
${unmitigatedThreats.length > 0 ? 
  `⚠️ ${unmitigatedThreats.length} threats require mitigation before implementation` :
  '✅ All identified threats have mitigations'}
  `;
}

4. Secure Design Patterns

Defense in Depth

// Layered security architecture
const secureArchitecture = {
  layers: [
    {
      name: 'Edge Layer',
      controls: [
        'WAF (Web Application Firewall)',
        'DDoS protection',
        'Rate limiting',
        'Geographic restrictions'
      ]
    },
    {
      name: 'API Gateway',
      controls: [
        'OAuth 2.0 authentication',
        'API key validation',
        'Request validation',
        'Rate limiting per client',
        'Response filtering'
      ]
    },
    {
      name: 'Application Layer',
      controls: [
        'Session management',
        'RBAC authorization',
        'Input validation',
        'Output encoding',
        'CSRF protection'
      ]
    },
    {
      name: 'Data Layer',
      controls: [
        'Encryption at rest',
        'Database access controls',
        'Query parameterization',
        'Data masking',
        'Audit logging'
      ]
    },
    {
      name: 'Infrastructure Layer',
      controls: [
        'Network segmentation',
        'Security groups',
        'Private subnets',
        'VPC endpoints',
        'Encryption in transit'
      ]
    }
  ]
};

// Each layer should independently enforce security
// Failure in one layer shouldn't compromise entire system

Zero Trust Architecture

// Zero trust principles in design
const zeroTrustDesign = {
  principles: [
    'Never trust, always verify',
    'Assume breach',
    'Explicit verification',
    'Least privilege access',
    'Microsegmentation',
    'End-to-end encryption'
  ],
  
  implementation: {
    serviceToService: {
      authentication: 'mTLS certificates',
      authorization: 'Service mesh policies',
      encryption: 'TLS 1.3 always',
      networkPolicy: 'Deny-by-default, explicit allow'
    },
    
    userToService: {
      authentication: 'OAuth 2.0 + MFA',
      authorization: 'Attribute-based access control (ABAC)',
      deviceTrust: 'Device posture checks',
      contextual: 'IP, location, time-based policies'
    },
    
    dataAccess: {
      encryption: 'Field-level encryption for sensitive data',
      tokenization: 'Tokenize PCI/PHI data',
      accessLogging: 'Log all data access with context',
      dataClassification: 'Automatic classification and protection'
    }
  }
};

// Example: Service-to-service authorization policy
const istioAuthPolicy = `
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: frontend-to-backend
spec:
  selector:
    matchLabels:
      app: backend
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/prod/sa/frontend"]
    to:
    - operation:
        methods: ["GET", "POST"]
        paths: ["/api/public/*"]
  - from:
    - source:
        principals: ["cluster.local/ns/prod/sa/admin-service"]
    to:
    - operation:
        methods: ["*"]
        paths: ["/api/admin/*"]
`;

5. Design Review Checklist

Security Design Review Checklist:

  • ✅ Architecture diagram provided and reviewed
  • ✅ Data flow diagram shows trust boundaries
  • ✅ Threat model completed (STRIDE or similar)
  • ✅ Authentication mechanism documented and secure
  • ✅ Authorization model defined and enforced server-side
  • ✅ Sensitive data identified and protected
  • ✅ Encryption at rest and in transit specified
  • ✅ Input validation strategy defined
  • ✅ Error handling doesn't leak information
  • ✅ Logging includes security events, excludes PII
  • ✅ Dependencies assessed for security
  • ✅ Network segmentation implemented
  • ✅ Secrets management strategy defined
  • ✅ Disaster recovery plan exists
  • ✅ Compliance requirements addressed
  • ✅ No security anti-patterns detected
  • ✅ High-risk threats mitigated
  • ✅ Security controls validated in testing plan

6. Collaborative Review Process

Running the Review Session

// Design review meeting structure
const reviewAgenda = {
  duration: '60-90 minutes',
  participants: [
    'Design author (Engineer)',
    'Security architect',
    'Technical lead',
    'Operations representative',
    'Optional: Product manager, Compliance'
  ],
  
  agenda: [
    {
      section: 'Context (10 min)',
      activities: [
        'Business objectives',
        'User stories',
        'Success criteria'
      ]
    },
    {
      section: 'Architecture walkthrough (20 min)',
      activities: [
        'Present architecture diagram',
        'Explain data flows',
        'Highlight security controls',
        'Discuss trade-offs'
      ]
    },
    {
      section: 'Threat modeling (20 min)',
      activities: [
        'Identify threats (STRIDE)',
        'Assess risks',
        'Propose mitigations',
        'Document in threat model'
      ]
    },
    {
      section: 'Security Q&A (15 min)',
      activities: [
        'Address security questionnaire',
        'Identify gaps',
        'Discuss alternatives'
      ]
    },
    {
      section: 'Action items (5 min)',
      activities: [
        'Document required changes',
        'Assign owners',
        'Set timeline',
        'Schedule follow-up if needed'
      ]
    }
  ],
  
  outcomes: [
    'Approved - proceed with implementation',
    'Approved with conditions - address items before deployment',
    'Revise - significant changes needed'
  ]
};

7. Post-Review Tracking

// Track implementation of security requirements
interface SecurityRequirement {
  id: string;
  description: string;
  priority: 'Must' | 'Should' | 'Could';
  status: 'Open' | 'In Progress' | 'Done' | 'Waived';
  assignee: string;
  dueDate: Date;
  validationMethod: string;
}

const securityRequirements: SecurityRequirement[] = [
  {
    id: 'SEC-001',
    description: 'Implement OAuth 2.0 with PKCE for authentication',
    priority: 'Must',
    status: 'In Progress',
    assignee: '[email protected]',
    dueDate: new Date('2026-02-15'),
    validationMethod: 'Security test verifies PKCE flow'
  },
  {
    id: 'SEC-002',
    description: 'Enable encryption at rest for user database',
    priority: 'Must',
    status: 'Done',
    assignee: '[email protected]',
    dueDate: new Date('2026-02-01'),
    validationMethod: 'AWS RDS encryption verified'
  },
  {
    id: 'SEC-003',
    description: 'Implement rate limiting (100 req/min per user)',
    priority: 'Must',
    status: 'Open',
    assignee: '[email protected]',
    dueDate: new Date('2026-02-20'),
    validationMethod: 'Load test confirms rate limiting'
  }
];

// Gate deployment on security requirements
async function canDeploy(projectId: string): Promise<boolean> {
  const requirements = await getSecurityRequirements(projectId);
  const mustHaves = requirements.filter(r => r.priority === 'Must');
  const incomplete = mustHaves.filter(r => r.status !== 'Done');
  
  if (incomplete.length > 0) {
    console.error(`Cannot deploy: ${incomplete.length} required security controls not implemented`);
    return false;
  }
  
  return true;
}

Conclusion

Security design reviews are your first and best defense against vulnerabilities. By catching security issues at the design stage, you avoid costly rewrites, reduce technical debt, and build systems that are secure by design rather than secured by patches. Make security design reviews a standard part of your development process—your future self will thank you when you're not scrambling to fix a critical vulnerability in production.