2026-04-16·14 min read·

NIS2 Art.21(2)(e): Secure Development Lifecycle Requirements for SaaS Developers (2026)

Most NIS2 compliance guides focus on incident reporting timelines and board accountability. The Secure Development Lifecycle requirements embedded in Art.21(2)(e) receive far less attention — yet for SaaS companies that build and maintain network and information systems, this provision creates concrete, auditable obligations that go well beyond general "security best practices."

Art.21(2)(e) of the NIS2 Directive (Directive 2022/2555) requires essential and important entities to adopt "security in network and information systems acquisition, development and maintenance, including vulnerability handling and disclosure" as one of ten mandatory cybersecurity risk-management measures. This is not aspirational guidance. It is a legal obligation enforceable from October 2024, with NCA audit season beginning June 2026.

For SaaS developers, Art.21(2)(e) means that your software development process — how you write code, review it, test it, deploy it, and handle vulnerabilities — is now subject to regulatory scrutiny. This guide explains what that means in practice.


1. The Art.21(2) Framework: Where SDL Fits

NIS2 Art.21(2) lists ten mandatory security measures. Understanding where SDL sits within the full framework clarifies its scope.

The Ten Mandatory Measures

SubparagraphRequirementPrimary Owner
Art.21(2)(a)Risk analysis and information system security policiesCISO / Management
Art.21(2)(b)Incident handlingSOC / DevSecOps
Art.21(2)(c)Business continuity, backup management, disaster recoveryOps / SRE
Art.21(2)(d)Supply chain security (see GDPR Art.28 link)Procurement / DevSecOps
Art.21(2)(e)Security in acquisition, development and maintenance + vulnerability handlingEngineering / DevSecOps
Art.21(2)(f)Policies to assess effectiveness of cybersecurity measuresAudit / GRC
Art.21(2)(g)Basic cyber hygiene and trainingHR / Security Awareness
Art.21(2)(h)Cryptography and encryption policiesArchitecture / Engineering
Art.21(2)(i)HR security, access control, asset managementIT / HR
Art.21(2)(j)Multi-factor authentication and continuous authenticationIT / IAM

Art.21(2)(e) is the developer-facing provision. While Art.21(2)(d) addresses supply chain risk from third-party components, Art.21(2)(e) addresses how you build your own systems.

What "Acquisition, Development and Maintenance" Covers

The three-part phrase in Art.21(2)(e) maps to the full system lifecycle:


2. Vulnerability Handling and Disclosure: The Explicit Obligations

Art.21(2)(e) explicitly includes vulnerability handling and disclosure — making this the specific NIS2 provision that governs your coordinated vulnerability disclosure (CVD) program.

The Three-Layer Vulnerability Obligation

Layer 1: Internal Vulnerability Management

Entities must have documented procedures for identifying, assessing, and remediating vulnerabilities in their own systems. The key elements regulators will assess:

Layer 2: Coordinated Vulnerability Disclosure (CVD)

NIS2 Art.21(2)(e) requires vulnerability disclosure procedures, not just internal handling. This means:

The European Union Agency for Cybersecurity (ENISA) published the ENISA Good Practice Guide on Vulnerability Disclosure (2022) as the reference implementation for EU-based disclosure programs.

Layer 3: Reporting to ENISA/CSIRTs

Recital 58 of NIS2 explicitly connects Art.21 security measures with the vulnerability disclosure ecosystem under Art.12 (coordinated vulnerability disclosure at EU level). Entities covered by NIS2 are expected to participate in the EU CVD framework, which routes through national CSIRTs.

For actively exploited vulnerabilities, Art.23 reporting obligations may trigger in parallel with Art.21(2)(e) disclosure procedures — creating a dual-track requirement.

CVD Timeline Standards

The EU cybersecurity ecosystem has converged on specific timelines that NCAs will reference during audits:

PhaseStandard TimelineNIS2 Context
AcknowledgmentWithin 5 business daysExpected as minimum
Initial assessmentWithin 10 business daysSeverity determination
Patch developmentVariable (Critical: 7–30 days)Risk-proportionate
Coordinated disclosure90 days from private reportENISA recommendation
Emergency disclosure72 hours (active exploitation)Art.23 parallel trigger

3. The NIS2 Secure Development Lifecycle: What NCAs Will Assess

NCAs conducting Art.32 supervisory assessments (starting June 2026) will evaluate SDL maturity using a risk-proportionate lens. The following framework maps Art.21(2)(e) to auditable controls.

Phase 1: Requirements and Design Security

Threat Modelling (Design Phase)

Art.21(2)(a) requires risk analysis at the organisational level. Art.21(2)(e) extends this to the system level: is there a threat modelling process for new features and architectural changes?

What auditors will look for:

Minimum practice: Using STRIDE or PASTA methodology for features that handle authentication, authorisation, sensitive data, or external integrations.

Security Requirements

Are security requirements formally captured alongside functional requirements? For essential entities, implicit security requirements are insufficient — there must be documented security acceptance criteria in your development process.

Phase 2: Secure Coding and Code Review

Secure Coding Standards

Art.21(2)(e) implies that development teams operate to documented secure coding standards. The standard need not be custom-written — adopting OWASP Secure Coding Practices or CWE Top 25 by reference satisfies the documentation requirement.

Key areas NCAs reference:

Security Code Review

Mandatory for entities assessed as high-criticality. The key question: is security explicitly in scope for code review, or only for formal security audits?

Minimum practice for essential entities:

Phase 3: Testing and Verification

Security Testing Requirements

Art.21(2)(e) maintenance obligations include ongoing security testing. NCA assessments will probe:

The DAST Gap in SaaS

Many SaaS developers run excellent SAST pipelines but have minimal DAST coverage of production-equivalent environments. This is the most common Art.21(2)(e) audit finding based on ENISA's 2023 NIS baseline assessment.

The risk: SAST finds code-level vulnerabilities. DAST finds runtime misconfigurations, authentication bypasses, and business logic flaws that do not appear in static analysis.

Phase 4: Deployment and Release Security

CI/CD Pipeline Security

The software delivery pipeline is itself an attack surface. Art.21(2)(e) acquisition security extends to your build and deploy toolchain:

Software Bill of Materials (SBOM)

While SBOM is explicitly required under the CRA (Regulation 2024/2847, Art.13(3)(b)), NIS2 Art.21(2)(e) maintenance obligations implicitly require SBOM-equivalent awareness: you cannot manage vulnerabilities in components you cannot enumerate.

The NIS2–CRA connection: For entities subject to both NIS2 and CRA, SBOM satisfies both requirements simultaneously. SaaS companies that are not CRA manufacturers should still maintain SBOM-equivalent dependency inventories as NIS2 Art.21(2)(e) evidence.

Phase 5: Maintenance and Patching

Patch Management Policy

Art.21(2)(e) maintenance obligations require documented patch management. The core requirements:

Legacy System Handling

Art.21(2)(e) maintenance specifically applies to legacy systems. Entities with legacy infrastructure that cannot be patched on standard timelines must demonstrate:


4. Who Does NIS2 Art.21(2)(e) Apply To?

Essential vs. Important Entities

NIS2 Art.21(1) applies proportionality: measures must be "appropriate and proportionate to the risks posed."

Entity TypeNIS2 ScopeArt.21(2)(e) Scrutiny Level
Essential (Art.3(1))Strict supervisionFull SDL audit: threat modelling, SAST+DAST, annual pen test, CVD program
Important (Art.3(2))Risk-proportionateSDL documentation + CVD: threat modelling for high-risk features, SAST mandatory, DAST recommended
Outside NIS2 scopeNot directly in scopeNIS2 supply chain pressure via Art.21(2)(d) customer requirements

Sectors in Scope (Annex I and II)

Annex I (Essential): Energy, transport, banking, financial market infrastructure, health, drinking water, wastewater, digital infrastructure, ICT service management, public administration, space.

Annex II (Important): Postal services, waste management, chemical manufacturing, food production, general manufacturing, digital providers (online marketplaces, search engines, social networks), research organisations.

For SaaS companies specifically:


5. The Developer Checklist: Art.21(2)(e) in Practice

Python NIS2SDLAssessor

from dataclasses import dataclass, field
from typing import List, Optional
from enum import Enum


class EntityType(Enum):
    ESSENTIAL = "essential"
    IMPORTANT = "important"
    SUPPLIER_ONLY = "supplier_only"


class MaturityLevel(Enum):
    INITIAL = 1      # Ad-hoc, no documented processes
    DEVELOPING = 2   # Some documentation, inconsistent application
    DEFINED = 3      # Documented and consistently applied
    MANAGED = 4      # Measured and monitored
    OPTIMISING = 5   # Continuous improvement based on metrics


@dataclass
class SDLControl:
    id: str
    name: str
    article: str
    required_for_essential: bool
    required_for_important: bool
    current_maturity: Optional[MaturityLevel] = None
    evidence: Optional[str] = None
    gap: Optional[str] = None


@dataclass
class NIS2SDLAssessment:
    entity_name: str
    entity_type: EntityType
    assessment_date: str
    controls: List[SDLControl] = field(default_factory=list)

    def assess(self) -> dict:
        results = {
            "entity": self.entity_name,
            "type": self.entity_type.value,
            "date": self.assessment_date,
            "compliant_controls": [],
            "gaps": [],
            "critical_gaps": [],
            "recommendations": [],
            "overall_maturity": None,
        }

        maturity_scores = []
        for control in self.controls:
            required = (
                control.required_for_essential
                if self.entity_type == EntityType.ESSENTIAL
                else control.required_for_important
            )
            if not required:
                continue

            if control.current_maturity and control.current_maturity.value >= 3:
                results["compliant_controls"].append(control.id)
                maturity_scores.append(control.current_maturity.value)
            else:
                gap_entry = {
                    "control": control.id,
                    "name": control.name,
                    "current": control.current_maturity.name if control.current_maturity else "NOT_ASSESSED",
                    "gap": control.gap or "Not documented",
                }
                results["gaps"].append(gap_entry)
                if control.current_maturity is None or control.current_maturity == MaturityLevel.INITIAL:
                    results["critical_gaps"].append(control.id)
                maturity_scores.append(control.current_maturity.value if control.current_maturity else 1)

        if maturity_scores:
            avg = sum(maturity_scores) / len(maturity_scores)
            results["overall_maturity"] = round(avg, 1)

        # Generate recommendations
        if "VULN-CVD-POLICY" in results["critical_gaps"]:
            results["recommendations"].append(
                "CRITICAL: Establish public CVD policy at security@domain.com before June 2026 NCA audits"
            )
        if "DEV-SAST-CI" in results["critical_gaps"]:
            results["recommendations"].append(
                "HIGH: Integrate SAST into CI pipeline immediately (GitLab SAST or Semgrep free tier)"
            )
        if "DEV-THREAT-MODEL" in results["critical_gaps"]:
            results["recommendations"].append(
                "HIGH: Implement threat modelling for authentication and data-handling features"
            )

        return results


def build_nis2_sdl_controls() -> List[SDLControl]:
    return [
        # Vulnerability Handling Controls
        SDLControl(
            id="VULN-CVD-POLICY",
            name="Public CVD Policy and Security Contact",
            article="NIS2 Art.21(2)(e)",
            required_for_essential=True,
            required_for_important=True,
        ),
        SDLControl(
            id="VULN-INTERNAL-SCAN",
            name="Regular Vulnerability Scanning (Production + Code)",
            article="NIS2 Art.21(2)(e)",
            required_for_essential=True,
            required_for_important=True,
        ),
        SDLControl(
            id="VULN-SLA",
            name="Remediation SLAs by Severity",
            article="NIS2 Art.21(2)(e)",
            required_for_essential=True,
            required_for_important=True,
        ),
        SDLControl(
            id="VULN-TRACKING",
            name="Vulnerability Tracking System (JIRA/Linear/GitHub Security)",
            article="NIS2 Art.21(2)(e)",
            required_for_essential=True,
            required_for_important=True,
        ),
        # Acquisition Controls
        SDLControl(
            id="ACQ-DEPENDENCY-POLICY",
            name="Third-Party Dependency Approval Policy",
            article="NIS2 Art.21(2)(e)",
            required_for_essential=True,
            required_for_important=False,
        ),
        SDLControl(
            id="ACQ-SCA",
            name="Software Composition Analysis (SCA) in CI",
            article="NIS2 Art.21(2)(e)",
            required_for_essential=True,
            required_for_important=True,
        ),
        SDLControl(
            id="ACQ-SBOM",
            name="Software Bill of Materials (SBOM) Maintenance",
            article="NIS2 Art.21(2)(e) + CRA Art.13",
            required_for_essential=True,
            required_for_important=False,
        ),
        # Development Controls
        SDLControl(
            id="DEV-SECURE-CODING",
            name="Documented Secure Coding Standards (OWASP/CWE Top 25)",
            article="NIS2 Art.21(2)(e)",
            required_for_essential=True,
            required_for_important=True,
        ),
        SDLControl(
            id="DEV-THREAT-MODEL",
            name="Threat Modelling for High-Risk Features",
            article="NIS2 Art.21(2)(e)",
            required_for_essential=True,
            required_for_important=False,
        ),
        SDLControl(
            id="DEV-SAST-CI",
            name="SAST Integrated in CI/CD Pipeline",
            article="NIS2 Art.21(2)(e)",
            required_for_essential=True,
            required_for_important=True,
        ),
        SDLControl(
            id="DEV-DAST",
            name="DAST Coverage of Production-Equivalent Environment",
            article="NIS2 Art.21(2)(e)",
            required_for_essential=True,
            required_for_important=False,
        ),
        SDLControl(
            id="DEV-PENTEST",
            name="Annual Penetration Testing (or Equivalent)",
            article="NIS2 Art.21(2)(e) + Art.21(2)(f)",
            required_for_essential=True,
            required_for_important=False,
        ),
        SDLControl(
            id="DEV-SECRETS",
            name="Secrets Management (No Credentials in Code/Artifacts)",
            article="NIS2 Art.21(2)(e) + Art.21(2)(h)",
            required_for_essential=True,
            required_for_important=True,
        ),
        # Maintenance Controls
        SDLControl(
            id="MAINT-PATCH-POLICY",
            name="Documented Patch Management Policy with Severity SLAs",
            article="NIS2 Art.21(2)(e)",
            required_for_essential=True,
            required_for_important=True,
        ),
        SDLControl(
            id="MAINT-EOL-TRACKING",
            name="End-of-Life Component Tracking and Remediation Plans",
            article="NIS2 Art.21(2)(e)",
            required_for_essential=True,
            required_for_important=True,
        ),
        SDLControl(
            id="MAINT-PIPELINE-SEC",
            name="CI/CD Pipeline Security Controls (Access, Signing, Provenance)",
            article="NIS2 Art.21(2)(e)",
            required_for_essential=True,
            required_for_important=False,
        ),
    ]


# Example: Important Entity SaaS Company Assessment
if __name__ == "__main__":
    controls = build_nis2_sdl_controls()

    # Set current maturity levels (example: typical SaaS startup state)
    maturity_map = {
        "VULN-CVD-POLICY": (MaturityLevel.INITIAL, "No public security contact or CVD policy"),
        "VULN-INTERNAL-SCAN": (MaturityLevel.DEVELOPING, "Manual scans only, no scheduled cadence"),
        "VULN-SLA": (MaturityLevel.INITIAL, "No formal SLAs defined"),
        "VULN-TRACKING": (MaturityLevel.DEFINED, "GitHub Security Advisories used"),
        "ACQ-SCA": (MaturityLevel.DEVELOPING, "Dependabot enabled but no blocking policy"),
        "DEV-SECURE-CODING": (MaturityLevel.DEVELOPING, "OWASP referenced in onboarding but not enforced"),
        "DEV-SAST-CI": (MaturityLevel.DEFINED, "Semgrep in CI, alerts reviewed weekly"),
        "DEV-SECRETS": (MaturityLevel.DEFINED, "Vault used for production secrets"),
        "MAINT-PATCH-POLICY": (MaturityLevel.INITIAL, "Patches applied ad-hoc"),
        "MAINT-EOL-TRACKING": (MaturityLevel.INITIAL, "No EOL tracking process"),
    }

    for control in controls:
        if control.id in maturity_map:
            maturity, gap = maturity_map[control.id]
            control.current_maturity = maturity
            control.gap = gap

    assessment = NIS2SDLAssessment(
        entity_name="ExampleSaaS GmbH",
        entity_type=EntityType.IMPORTANT,
        assessment_date="2026-04-16",
        controls=controls,
    )

    result = assessment.assess()
    print(f"Overall Maturity: {result['overall_maturity']}/5")
    print(f"Compliant: {len(result['compliant_controls'])} controls")
    print(f"Gaps: {len(result['gaps'])} controls")
    print(f"Critical Gaps: {result['critical_gaps']}")
    print("\nRecommendations:")
    for rec in result["recommendations"]:
        print(f"  - {rec}")

6. The June 2026 NCA Audit: What to Expect

NCA Supervisory Powers Under Art.32–33

National Competent Authorities gained broad supervisory powers under NIS2:

For Art.21(2)(e) specifically, auditors will typically request:

  1. SDL policy documentation
  2. Evidence of SAST/DAST tooling integration (CI pipeline configuration)
  3. CVD policy and disclosure history
  4. Patch management records (last 12 months of vulnerability findings and resolutions)
  5. Penetration test reports (last 24 months)
  6. SBOM or dependency inventory evidence

Evidence Package for Art.21(2)(e) Compliance

DocumentPurposeMinimum Scope
SDL Policy DocumentShows formalised development security processCovers acquisition, development, maintenance phases
CVD Policy (public)Demonstrates vulnerability disclosure complianceSecurity contact + 90-day timeline
SAST Scan ReportsEvidence of automated code security testingLast 3 months minimum
DAST Scan ReportsEvidence of runtime security testingLast 12 months for essential entities
Pen Test ReportThird-party validationLast 24 months
Patch Management LogDemonstrates vulnerability remediationOpen + closed findings with resolution dates
Dependency InventorySBOM or equivalentAll production components with versions

The Proportionality Argument

Art.21(1) explicitly requires measures to be proportionate to "the risks posed, taking into account the state of the art." This provides essential entities with room to argue that lightweight controls are sufficient for lower-risk components.

The proportionality framing: Not every component in your system requires full SAST+DAST+threat-modelling coverage. The SDL should apply full scrutiny to:

Lower-risk components (internal tooling, read-only reporting systems) may satisfy Art.21(2)(e) with lighter controls — documented SAST coverage without DAST, for example.


7. NIS2 Art.21(2)(e) vs. ISO 27001 Annex A.8

Many SaaS companies hold or are pursuing ISO 27001 certification. The relationship between ISO 27001 and NIS2 Art.21(2)(e) is one of partial coverage — not full equivalence.

Coverage Mapping

NIS2 Art.21(2)(e) RequirementISO 27001:2022 ControlGap?
Secure coding standardsA.8.28 Secure codingCovered
Vulnerability scanningA.8.8 Management of technical vulnerabilitiesCovered
SAST in CIA.8.28 Secure codingPartially covered
CVD policyA.8.8 + A.5.24 (new in 2022)Partially covered
SBOMNo explicit controlGap
Patch managementA.8.8Covered
Threat modellingA.8.25 Secure development lifecycleCovered
Pipeline securityA.8.25 + A.8.9Partially covered

The key gap: ISO 27001 does not explicitly require a public CVD policy or SBOM. NIS2 Art.21(2)(e) does (for essential entities). ISO 27001 certification alone does not demonstrate NIS2 Art.21(2)(e) compliance.

The practical path: Organisations with ISO 27001 can leverage their existing controls as evidence for Art.21(2)(e), then close the CVD and SBOM gaps separately.


8. The SDL–Supply Chain Intersection

Art.21(2)(e) connects to Art.21(2)(d) (supply chain security) in a specific way that most companies miss.

Your SDL Is Your Customers' Supply Chain Control

If you are a SaaS provider serving essential entity customers, your SDL is the control they rely on under Art.21(2)(d). This creates a chain:

  1. Your customer (essential entity) must assess "the overall quality of products and cybersecurity practices" of their suppliers (Art.21(2)(d), ENISA guidelines)
  2. Your SDL maturity is what they are assessing
  3. Your CVD program is the mechanism they rely on to learn about vulnerabilities in your software

The practical implication: essential entity customers are increasingly contractually requiring:

Your Art.21(2)(e) compliance program is also your competitive differentiator with regulated customers.


9. The 25-Item NIS2 Art.21(2)(e) Compliance Checklist

Vulnerability Handling and Disclosure (Items 1–8)

Acquisition Security (Items 9–12)

Development Security (Items 13–19)

Deployment Security (Items 20–22)

Maintenance Security (Items 23–25)


10. Timeline: Getting to NIS2 SDL Compliance Before June 2026

For SaaS companies that have not yet formally addressed Art.21(2)(e), the path to NCA audit readiness follows a natural sequence:

Weeks 1–2: Foundation

Weeks 3–4: Process Documentation

Weeks 5–8: Coverage Expansion

Weeks 9–12: Evidence Package

This timeline puts an important entity at Maturity Level 3 (Defined) — the threshold for NCA audit compliance — within 90 days.


Conclusion

NIS2 Art.21(2)(e) translates regulatory security requirements into developer workflow obligations. The three pillars — acquisition security, development security, and maintenance — map directly onto software engineering practices that most SaaS teams already partially follow. The gap between what teams already do and what Art.21(2)(e) requires is primarily one of documentation and formalism: the processes exist, but they are not documented, not consistently applied, and not evidence-ready for NCA scrutiny.

The lowest-hanging fruit before June 2026 NCA audits:

  1. Publish a CVD policy — a security.txt file and a one-page disclosure policy satisfies the basic requirement
  2. Add SCA and SAST to CI — free tooling (Dependabot, Semgrep Community) satisfies the tooling requirement
  3. Write a patch management SLA document — one page defining Critical/High/Medium/Low timelines closes the most common finding

For SaaS developers serving essential entity customers, Art.21(2)(e) compliance is also a commercial requirement: regulated customers are increasingly asking for SDL evidence in procurement. The compliance program and the sales requirement are the same program.


Related posts: NIS2 Art.21 Ten Mandatory Cybersecurity Measures: Complete Developer Guide 2026 · NIS2 Art.21(2)(h): Cryptography and Encryption Policy Developer Guide · GDPR Art.28 + NIS2 Art.21(2)(d): Data Processor as NIS2 Supplier Dual Compliance · NIS2 Art.32 Proactive Supervision: Essential Entity Audit Preparation Guide