18 min read

Secure by Design: Embedding Cybersecurity in Every Phase of the SDLC

A comprehensive guide to building security into software from the ground up, covering CISA's Secure by Design principles, UK PSTI Act compliance, ETSI EN 303 645 standards, and practical strategies for integrating security throughout the software development lifecycle.

Secure by Design - Security architecture diagram showing security integrated throughout the software development lifecycle

Building security in, not bolting it on

Key Takeaways

  • The UK PSTI Act 2022 mandates three core security requirements for IoT devices: no default passwords, vulnerability disclosure policies, and transparent security update periods.
  • CISA's Secure by Design principles emphasise manufacturer responsibility, radical transparency, and executive leadership commitment to security.
  • Security must be integrated into every SDLC phase: requirements, design, implementation, testing, deployment, and maintenance.
  • ETSI EN 303 645 provides 13 baseline security provisions that form the foundation for IoT and connected product security standards globally.

Introduction: The Shift Left Movement

In the rapidly evolving digital landscape, cybersecurity can no longer be an afterthought. The traditional approach of “bolt-on security”—where security controls are added after development is complete—has proven inadequate against sophisticated modern threats. This realisation has driven the Secure by Design movement, which advocates for embedding security into every phase of the software development lifecycle (SDLC).

Secure SDLC showing security activities integrated into each phase: Requirements, Design, Implementation, Testing, Deployment, and Maintenance
Secure Software Development Lifecycle: Security activities integrated at each phase from requirements gathering through maintenance, with feedback loops for continuous improvement

The cost of fixing security vulnerabilities increases exponentially the later they are discovered. Research from IBM and the Ponemon Institute shows that vulnerabilities found in production cost approximately 30 times more to remediate than those identified during the design phase. Beyond financial implications, late-stage security fixes often require architectural changes that compromise system integrity and delay critical releases.

“Security is not a feature to be added; it's a property of the system that must be designed in from the beginning.”

— CISA Secure by Design Guidance

In 2023 and 2024, regulatory bodies worldwide have formalised these principles into law. The UK's Product Security and Telecommunications Infrastructure (PSTI) Act 2022, which came into force in April 2024, represents one of the most significant steps towards mandating secure-by-design practices. Combined with CISA's influential guidelines and ETSI's technical standards, organisations now have a comprehensive framework for building security into their products and services from inception.

CISA's Secure by Design Principles

In October 2023, the Cybersecurity and Infrastructure Security Agency (CISA), alongside 17 international partners, released the updated “Shifting the Balance of Cybersecurity Risk” guidance. This landmark document establishes three core principles that software manufacturers should embrace to create genuinely secure products.

Principle 1: Take Ownership of Customer Security Outcomes

Software manufacturers must take responsibility for the security of their products, not just provide tools for customers to secure themselves.

Principle 2: Embrace Radical Transparency and Accountability

Publicly share security practices, vulnerability disclosure policies, and security metrics to build trust with customers.

Principle 3: Lead From the Top

Executive leadership must prioritise security as a core business requirement, not just a technical afterthought.

Demonstrating Commitment

CISA's guidance emphasises that software manufacturers must demonstrate their commitment to these principles through concrete actions:

  • Secure defaults: Products should be secure out of the box, with security features enabled by default rather than requiring manual configuration.
  • Eliminate default credentials: No product should ship with universal default passwords or credentials.
  • Secure development practices: Implement formal secure development lifecycle practices, including code review, testing, and vulnerability management.
  • Transparency: Publish vulnerability disclosure policies, security advisories, and product security documentation.

UK Product Security (PSTI) Act 2022

The Product Security and Telecommunications Infrastructure Act 2022 represents the UK's legislative response to the growing threat of insecure connected products. Coming into force on 29 April 2024, it establishes mandatory security requirements for manufacturers, importers, and distributors of consumer connectable products sold in the UK market.

Regulatory Impact

Non-compliance with the PSTI Act can result in enforcement notices, compliance notices, stop notices, and financial penalties of up to £10 million or 4% of qualifying worldwide revenue, whichever is greater.

Core Requirements

No Default Passwords

Products must not use universal default passwords. Each device must have a unique password, or require users to set one on first use.

Impact: Eliminates one of the most common attack vectors used in IoT botnets like Mirai.

Vulnerability Disclosure Policy

Manufacturers must provide a public point of contact for reporting security vulnerabilities and respond to reports in a timely manner.

Impact: Ensures security researchers can responsibly disclose vulnerabilities without legal concerns.

Security Update Period

Manufacturers must be transparent about the minimum period during which security updates will be provided.

Impact: Gives consumers clarity on product longevity and security support expectations.

Products in Scope

The PSTI Act applies to a wide range of consumer connectable products, including:

  • Smart home devices and appliances
  • Wearable technology
  • Smart TVs and streaming devices
  • Connected cameras and doorbells
  • Baby monitors
  • Smart speakers and voice assistants
  • Connected toys
  • Routers and network equipment

ETSI EN 303 645 Standards

ETSI EN 303 645 “Cyber Security for Consumer Internet of Things: Baseline Requirements” provides the technical foundation for IoT security standards globally. Published by the European Telecommunications Standards Institute, this standard has been adopted as the baseline for numerous regulatory frameworks, including the UK PSTI Act.

The 13 Baseline Provisions

  1. 1No universal default passwords
  2. 2Implement a means to manage reports of vulnerabilities
  3. 3Keep software updated
  4. 4Securely store sensitive security parameters
  5. 5Communicate securely
  6. 6Minimise exposed attack surfaces
  7. 7Ensure software integrity
  8. 8Ensure personal data is secure
  9. 9Make systems resilient to outages
  10. 10Examine system telemetry data
  11. 11Make it easy for users to delete user data
  12. 12Make installation and maintenance of devices easy
  13. 13Validate input data

These provisions form a comprehensive baseline that addresses the most critical security concerns in IoT devices. By implementing these standards, manufacturers can significantly reduce the attack surface of their products whilst demonstrating compliance with emerging regulatory requirements across multiple jurisdictions.

Security in Every SDLC Phase

Implementing secure-by-design principles requires integrating security activities into every phase of the software development lifecycle. Below is a comprehensive breakdown of security activities for each phase:

Phase 1: Requirements

  • Security requirements gathering
  • Threat modelling sessions
  • Risk assessment and classification
  • Compliance requirement mapping
  • Attack surface analysis

Phase 2: Design

  • Security architecture review
  • Data flow diagrams with trust boundaries
  • Cryptographic design decisions
  • Authentication and authorisation patterns
  • Secure API design principles

Phase 3: Implementation

  • Secure coding standards enforcement
  • Static Application Security Testing (SAST)
  • Code review with security focus
  • Dependency scanning (SCA)
  • Secrets management

Phase 4: Testing

  • Dynamic Application Security Testing (DAST)
  • Penetration testing
  • Interactive Application Security Testing (IAST)
  • Fuzz testing
  • Security regression testing

Phase 5: Deployment

  • Infrastructure as Code security scanning
  • Container image scanning
  • Configuration hardening verification
  • Secrets rotation
  • Security monitoring setup

Phase 6: Maintenance

  • Continuous vulnerability monitoring
  • Patch management
  • Incident response procedures
  • Security metrics and reporting
  • Regular security assessments

Threat Modelling Methodologies

Threat modelling is a structured approach to identifying, quantifying, and addressing security threats to a system. It should be conducted early in the design phase and revisited throughout the development lifecycle as the system evolves.

STRIDE Framework

Developed by Microsoft, STRIDE categorises threats into six categories:

Spoofing

Impersonating something or someone

Tampering

Modifying data or code

Repudiation

Denying having performed an action

Information Disclosure

Exposing data to unauthorised users

Denial of Service

Making a system unavailable

Elevation of Privilege

Gaining unauthorised capabilities

PASTA (Process for Attack Simulation and Threat Analysis)

PASTA is a seven-stage, risk-centric threat modelling methodology that aligns business objectives with technical requirements:

  1. 1Define business objectives
  2. 2Define technical scope
  3. 3Application decomposition
  4. 4Threat analysis
  5. 5Vulnerability and weakness analysis
  6. 6Attack modelling and simulation
  7. 7Risk analysis and countermeasure development

Secure Coding Practices

Secure coding is the practice of writing software in a way that protects against the introduction of security vulnerabilities. Following established secure coding standards significantly reduces the attack surface of applications.

OWASP Secure Coding Principles

Input Validation

Always validate input on a trusted system (server-side). Use a centralised input validation routine for the entire application. Specify proper character sets and validate data for type, length, format, and range.

input-validation.tstypescript
// Example: Comprehensive input validation in TypeScript// Define validation schema with Zod// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Server-side validation function// Express middleware example// Express middleware example// Express middleware example// Express middleware example// Express middleware example// Express middleware example// Express middleware example// Express middleware example Express middleware example
app.post('/api/register', (req, res, next) => {
  try {
    const validatedData = validateUserInput(req.body);
    // Process validated data...
  } catch (error) {
    if (error instanceof ValidationError) {
      return res.status(400).json({ errors: error.details });
    }
    next(error);
  }
});

Output Encoding

Encode all output based on the context in which it will be rendered. Use context-specific encoding for HTML, JavaScript, CSS, and URL contexts to prevent cross-site scripting (XSS) attacks.

output-encoding.tstypescript
// Context-specific output encoding examples// HTML context - escape special characters// HTML context - escape special characters// JavaScript context - JSON encode// JavaScript context - JSON encode// JavaScript context - JSON encode// JavaScript context - JSON encode// JavaScript context - JSON encode// URL context - URI encode// URL context - URI encode// URL context - URI encode// URL context - URI encode// Sanitise HTML when rich text is required// Sanitise HTML when rich text is required// Sanitise HTML when rich text is required// React automatically escapes - but beware dangerouslySetInnerHTML// React automatically escapes - but beware dangerouslySetInnerHTML// React automatically escapes - but beware dangerouslySetInnerHTML// React automatically escapes - but beware dangerouslySetInnerHTML// BAD: <div dangerouslySetInnerHTML={{ __html: userInput }} />// GOOD: <div>{userInput}</div>/ GOOD: <div>{userInput}</div>

Authentication and Session Management

Require authentication for all pages and resources except those specifically intended to be public. Use strong, well-tested authentication mechanisms. Implement proper session management with secure session IDs, appropriate timeouts, and secure cookie attributes.

session-auth.tstypescript
// Secure session configuration (Express.js example)// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// CSRF protection// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2// Password hashing with Argon2 hashing with Argon2
import argon2 from 'argon2';

async function hashPassword(password: string): Promise<string> {
  return argon2.hash(password, {
    type: argon2.argon2id,
    memoryCost: 65536,    // 64 MB
    timeCost: 3,          // 3 iterations
    parallelism: 4,       // 4 parallel threads
  });
}

async function verifyPassword(hash: string, password: string): Promise<boolean> {
  return argon2.verify(hash, password);
}

Cryptographic Practices

Use established cryptographic algorithms and libraries. Never implement your own cryptography. Use appropriate key lengths (minimum 2048-bit for RSA, 256-bit for AES). Properly manage cryptographic keys and secrets.

cryptography.tstypescript
// Secure cryptography examples (Node.js)// AES-256-GCM encryption (authenticated encryption)// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// Secure random token generation// HMAC for data integrity// HMAC for data integrity// HMAC for data integrity// HMAC for data integrity// HMAC for data integrity// HMAC for data integrityata integrity
function createHMAC(data: string, key: Buffer): string {
  return crypto.createHmac('sha256', key).update(data).digest('hex');
}

SQL Injection Prevention

Always use parameterised queries or prepared statements. Never concatenate user input directly into SQL queries.

sql-injection-prevention.tstypescript
// VULNERABLE - Never do this!// SAFE - Parameterised query with Prisma// SAFE - Parameterised query with Prisma// SAFE - Parameterised query with raw SQL// SAFE - Parameterised query with raw SQL// SAFE - Parameterised query with raw SQL// SAFE - Using pg library with parameters// SAFE - Using pg library with parameters// SAFE - Using pg library with parameters// SAFE - TypeORM query builder// SAFE - TypeORM query builder// SAFE - TypeORM query builder// SAFE - TypeORM query builder// SAFE - TypeORM query builderder
const user = await userRepository
  .createQueryBuilder('user')
  .where('user.email = :email', { email: userEmail })
  .getOne();

Troubleshooting Common Security Issues

Issue: Security Headers Missing

Browser security features are not enabled, leaving the application vulnerable to XSS, clickjacking, and other attacks.

Solution:
next.config.jsjavascript
// Next.js - next.config.js
const securityHeaders = [
  { key: 'X-DNS-Prefetch-Control', value: 'on' },
  { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },
  { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
  { key: 'X-Content-Type-Options', value: 'nosniff' },
  { key: 'X-XSS-Protection', value: '1; mode=block' },
  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
  { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
  { 
    key: 'Content-Security-Policy', 
    value: "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"
  },
];

module.exports = {
  async headers() {
    return [{ source: '/:path*', headers: securityHeaders }];
  },
};

Issue: Secrets Exposed in Code

API keys, database credentials, or other secrets are hardcoded in source code or committed to git.

Solution:
YAML
# 1. Set up pre-commit hooks with gitleaks# .pre-commit-config.yaml# 2. Use environment variables# 2. Use environment variables# 2. Use environment variables# 2. Use environment variables# .env.local (git ignored)# 3. For production, use a secrets manager//user:pass@host:5432/db# 3. For production, use a secrets manager# AWS Secrets Manager example# AWS Secrets Manager example# 4. Rotate any exposed secrets immediately!# 4. Rotate any exposed secrets immediately!# 4. Rotate any exposed secrets immediately!# 4. Rotate any exposed secrets immediately!# 4. Rotate any exposed secrets immediately!# 4. Rotate any exposed secrets immediately!# 4. Rotate any exposed secrets immediately!# 4. Rotate any exposed secrets immediately!# 4. Rotate any exposed secrets immediately!crets immediately!

Issue: Vulnerable Dependencies

Third-party packages contain known security vulnerabilities (CVEs).

Solution:
dependabot.ymlyaml
# Scan for vulnerabilities# Use Snyk for deeper analysis# Automate with Dependabot (.github/dependabot.yml)# Automate with Dependabot (.github/dependabot.yml)bot.yml)
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10
    groups:
      security:
        applies-to: security-updates
      dependencies:
        applies-to: version-updates
        patterns:
          - "*"

Secure-by-Design Checklist

Use this checklist to verify secure-by-design compliance in your projects:

Authentication & Access

Data Protection

Code Security

Operations

Implementation Roadmap

Transitioning to a secure-by-design approach requires organisational commitment and a structured implementation plan. The following roadmap provides a phased approach to embedding security throughout your development process:

Phase 1: Foundation (Months 1-3)

  • • Establish security governance and executive sponsorship
  • • Conduct security maturity assessment
  • • Define security policies and standards
  • • Train development teams on secure coding practices
  • • Implement basic security tooling (SAST, SCA)

Phase 2: Integration (Months 4-6)

  • • Integrate security tools into CI/CD pipelines
  • • Establish threat modelling practices
  • • Implement security requirements in user stories
  • • Deploy DAST and container security scanning
  • • Create security champions programme

Phase 3: Optimisation (Months 7-12)

  • • Implement continuous security monitoring
  • • Establish vulnerability management programme
  • • Conduct regular penetration testing
  • • Measure and report security metrics
  • • Continuous improvement based on lessons learned

Measuring Security Success

Effective security programmes require measurable outcomes. The following metrics help organisations track their progress towards secure-by-design maturity:

Mean Time to Remediation (MTTR)

Average time to fix identified vulnerabilities from discovery to deployment

Vulnerability Density

Number of vulnerabilities per thousand lines of code (KLOC)

Security Debt Ratio

Proportion of known security issues to total resolved issues

Code Coverage for Security Tests

Percentage of code covered by security-focused test cases

Conclusion

Secure by Design is no longer optional—it's a regulatory requirement and competitive necessity. The convergence of CISA guidelines, UK PSTI Act requirements, and ETSI standards has created a comprehensive framework for building security into products from inception.

Organisations that embrace secure-by-design principles will benefit from reduced remediation costs, improved customer trust, regulatory compliance, and stronger market positioning. The investment in upfront security pays dividends throughout the product lifecycle and beyond.

The journey towards secure-by-design maturity requires commitment, investment, and cultural change. However, with the right approach, tools, and mindset, organisations can build security into their DNA and deliver products that customers can trust.

Frequently Asked Questions

Secure by design is an approach to software development where security is embedded into every phase of the software development lifecycle (SDLC) from the very beginning, rather than being added as an afterthought. It means building products with security as a core requirement, including secure defaults, elimination of default credentials, and transparent security practices. This approach is now mandated by regulations like the UK PSTI Act and guided by frameworks from CISA and ETSI.
Security should be integrated into each SDLC phase: Requirements (security requirements gathering, threat modelling, risk assessment), Design (security architecture review, data flow diagrams with trust boundaries), Implementation (secure coding standards, SAST, code review, dependency scanning), Testing (DAST, penetration testing, fuzz testing), Deployment (IaC security scanning, container image scanning, configuration hardening), and Maintenance (continuous vulnerability monitoring, patch management, incident response). This 'shift left' approach catches vulnerabilities earlier when they're cheaper to fix.
Threat modelling is a structured approach to identifying, quantifying, and addressing security threats to a system. It should be conducted early in the design phase and revisited as the system evolves. Popular methodologies include STRIDE (Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege) developed by Microsoft, and PASTA (Process for Attack Simulation and Threat Analysis), a seven-stage risk-centric methodology that aligns business objectives with technical requirements.
Security requirements are specifications that define how a system should protect against threats and vulnerabilities. They include authentication and authorisation requirements (MFA, least privilege access), data protection requirements (encryption at rest and in transit, PII handling), input validation and output encoding requirements, logging and monitoring requirements, and compliance requirements (such as UK PSTI Act, ETSI EN 303 645). These should be gathered during the requirements phase and integrated into user stories.
Security testing in CI/CD involves integrating automated security tools into your pipeline: Static Application Security Testing (SAST) to analyse source code for vulnerabilities, Software Composition Analysis (SCA) to scan dependencies for known CVEs, Dynamic Application Security Testing (DAST) to test running applications, container image scanning for vulnerabilities in Docker images, Infrastructure as Code (IaC) security scanning, and secrets detection to prevent credential leaks. These tools should fail builds when critical vulnerabilities are detected.
Secure by design is a holistic approach that embeds security throughout the entire SDLC, from requirements gathering through to maintenance. Security testing is just one component of this approach, typically occurring during the testing and deployment phases. While security testing (SAST, DAST, penetration testing) helps identify vulnerabilities, secure by design prevents them from being introduced in the first place through threat modelling, secure architecture decisions, secure coding practices, and security requirements. The key difference is proactive prevention versus reactive detection.

References & Further Reading

Related Articles

Ayodele Ajayi

Senior DevOps Engineer based in Kent, UK. Specialising in cloud infrastructure, DevSecOps, and platform engineering. Passionate about building secure, scalable systems and sharing knowledge through technical writing.