Security

Secure SDLC: Building Security Into Every Phase of Development

How to embed security into requirements, design, implementation, testing, deployment, and maintenance phases of the software development lifecycle.

March 9, 20267 min readShipSafer Team

Secure SDLC: Building Security Into Every Phase of Development

A Secure Software Development Lifecycle (SSDLC) is not a separate track that runs alongside development — it is the same track, with security activities integrated into each phase. When security is treated as a gate at the end of development, it creates friction and late-stage rework. When it is woven into daily engineering work, it becomes a natural part of how software is built.

The Microsoft Security Development Lifecycle (SDL), NIST SP 800-218 (SSDF), and OWASP SAMM all describe variations of the same core idea: security belongs in every phase, from requirements through maintenance.

Phase 1: Requirements

Security requirements are functional requirements. They describe what the system must do (and must not do) from a security perspective.

Identify security requirements during feature scoping:

  • Who can access this feature, and what is the authorization model?
  • What data does this feature process, and what classification does it carry?
  • Are there regulatory requirements (GDPR, HIPAA, PCI DSS) that apply?
  • What abuse cases exist — what would a malicious user try to do with this feature?

Abuse case analysis is the security complement to use case analysis. For every legitimate user story, write the corresponding abuse story:

User StoryAbuse Story
As a user, I can upload a profile photoAs an attacker, I upload a web shell disguised as a JPEG
As a user, I can search for orders by IDAs an attacker, I inject SQL via the order ID parameter
As an admin, I can export user dataAs a malicious insider, I exfiltrate all customer PII

These abuse cases become test cases in later phases.

Document security requirements in your ticket system as acceptance criteria. A feature is not complete if it fails its security acceptance criteria — the same as any other acceptance criterion.

Phase 2: Design

Security flaws at the design level are the most expensive to fix because they require architectural changes. Threat modeling is the primary tool for finding them early.

Threat modeling with STRIDE:

STRIDE maps threat categories to components in your system design:

  • Spoofing — Can an attacker impersonate a legitimate user or service?
  • Tampering — Can an attacker modify data in transit or at rest?
  • Repudiation — Can a user deny performing an action?
  • Information Disclosure — Can sensitive data leak to unauthorized parties?
  • Denial of Service — Can an attacker make the service unavailable?
  • Elevation of Privilege — Can a low-privilege user gain higher privileges?

For a new feature, create a simple data flow diagram (DFD) showing:

  • External actors (users, third-party systems)
  • Processes (application components)
  • Data stores (databases, caches, queues)
  • Data flows (arrows showing data movement)
  • Trust boundaries (lines crossing between different trust levels)

Apply STRIDE to each component and flow. The output is a list of potential threats. Rank them by likelihood and impact. High-ranked threats become design requirements.

Security design principles to apply:

  • Least privilege — Components get only the permissions they need
  • Defense in depth — No single control protects against all threats
  • Fail secure — Errors default to denial, not permit
  • Separation of privilege — Critical operations require multiple conditions
  • Minimize attack surface — Disable features that are not needed

Phase 3: Implementation

Implementation is where security requirements are realized in code. Key practices:

Use security-focused libraries instead of rolling your own:

  • Authentication: established identity providers (Auth0, Cognito, Clerk) or proven libraries
  • Cryptography: platform-native libraries (crypto in Node.js, cryptography in Python) — never homebrew
  • Input validation: Zod, Joi, or framework validators

Secure coding checklist for pull requests:

  • All user input is validated and sanitized before use
  • Parameterized queries or ORMs used for all database access
  • No secrets or credentials in code or comments
  • Authentication required on all non-public endpoints
  • Authorization checked before returning any data
  • Sensitive data not logged
  • Error messages do not reveal implementation details
  • File uploads validated for type, size, and content

Code review with a security lens:

Standard code review focuses on correctness and maintainability. Security-focused review additionally asks:

  • What happens if this input is malicious?
  • What are the trust assumptions, and are they valid?
  • What is the worst case if this component is compromised?

Consider adding security-focused reviewers for features involving authentication, data access, or external integrations.

Phase 4: Testing

Security testing has multiple layers:

Unit tests for security controls:

Write tests that specifically verify security properties:

describe('OrderController', () => {
  it('rejects requests from non-owners', async () => {
    const order = await createOrder({ userId: 'user-1' });
    const response = await getOrder(order.id, { userId: 'user-2' });
    expect(response.status).toBe(403);
  });

  it('sanitizes order ID to prevent injection', async () => {
    const response = await getOrder("1; DROP TABLE orders;--");
    expect(response.status).toBe(400);
  });
});

SAST in CI: Run Semgrep or CodeQL on every pull request to catch common vulnerability patterns.

DAST against staging: Run OWASP ZAP or Nuclei against your staging environment after deployment to find runtime vulnerabilities.

Penetration testing: Commission an annual penetration test from a qualified external firm, plus ad-hoc testing for major feature releases. Penetration tests find the complex, multi-step vulnerabilities that automated tools miss.

Dependency scanning: Integrate npm audit, pip-audit, or Snyk into CI. Review and resolve HIGH+ findings before merging.

Phase 5: Deployment

The deployment pipeline itself is an attack surface.

CI/CD pipeline security:

  • Store all secrets in vault systems (GitHub Actions secrets, AWS Secrets Manager), not in .env files committed to repos
  • Use OIDC-based authentication from CI to cloud providers instead of long-lived credentials
  • Sign artifacts (container images, binaries) so runtime environments can verify provenance
  • Apply the principle of least privilege to deployment IAM roles

Infrastructure configuration:

  • Scan Terraform/CloudFormation with Checkov before applying
  • Use immutable infrastructure — never SSH into production to make changes
  • Enable cloud provider security services (GuardDuty, Security Command Center, Defender for Cloud) from day one

Feature flags for gradual rollout:

High-risk features benefit from phased rollouts with kill switches. If a deployed feature exhibits unexpected behavior, a feature flag lets you disable it in seconds without a redeployment.

Pre-production security checklist:

  • DAST scan passed
  • Penetration test findings remediated (or risk-accepted with approval)
  • Security headers configured
  • TLS 1.2+ enforced, weak ciphers disabled
  • Secrets management verified (no plaintext credentials)
  • Logging and monitoring configured
  • Incident response runbook updated

Phase 6: Maintenance

Software is never done. New vulnerabilities are discovered in dependencies, configuration drift introduces weaknesses, and the threat landscape evolves.

Ongoing maintenance activities:

  • Dependency updates: Use Dependabot or Renovate for automated dependency updates. Review and merge security patches within SLA (HIGH within 30 days, CRITICAL within 7 days).
  • Security monitoring: Continuously monitor application logs, cloud audit trails, and infrastructure metrics for anomalies.
  • Access reviews: Quarterly review of who has access to what — production systems, secrets, admin dashboards, cloud consoles.
  • Patch management: Track CVEs affecting your runtime environments (OS, language runtime, web server) and apply patches within defined SLAs.
  • Security regression testing: Re-run penetration test findings as regression tests to verify they have not re-emerged.

Security debt management:

Security issues found in maintenance should be triaged and tracked in the same backlog as feature work. Assign business impact to security debt — a critical vulnerability in a payment flow carries more business risk than an informational finding in an internal tool.

A mature SSDLC does not eliminate all vulnerabilities. It reduces the rate at which they are introduced, decreases the time to detection, and ensures that when vulnerabilities are found, the team has the context and tooling to fix them quickly.

Check Your Security Score — Free

See exactly how your domain scores on DMARC, TLS, HTTP headers, and 25+ other automated security checks in under 60 seconds.