2026-04-16·12 min read·

NIS2 Art.21(1): Proportionality Framework — What "Appropriate" Cybersecurity Measures Actually Means for SaaS Developers (2026)

NIS2 Directive Art.21(2) mandates ten specific cybersecurity risk-management measures — from risk analysis to multi-factor authentication. But before those measures apply, Art.21(1) establishes the governing principle that determines how and at what level each measure must be implemented:

"Member States shall ensure that essential and important entities take appropriate and proportionate technical, operational and organisational measures to manage the risks posed to the security of network and information systems which those entities use for their operations or for the provision of their services."

"Appropriate and proportionate" is not a vague aspiration. The Directive specifies exactly what proportionality means — and NCA auditors starting June 2026 will test whether your security posture can be justified against it.

This guide decodes the Art.21(1) proportionality framework, shows how SaaS development teams apply it in practice, and provides a Python assessment tool for audit-ready proportionality documentation.


1. The Four-Factor Proportionality Test

Art.21(1) defines proportionality through four explicit factors. Every security measure you implement — and every gap you document as accepted risk — must be defensible against all four.

Factor 1: State of the Art

Your controls must reflect current best practice, not 2018 standards. "State of the art" in 2026 means:

Audit implication: If you are still running TLS 1.2 or password-only admin access, "state of the art" will be used against you, regardless of your size or risk profile.

Factor 2: Applicable Standards and Specifications

ENISA and ETSI publish reference standards. The key ones for SaaS under NIS2:

StandardScopeNIS2 Relevance
ETSI EN 319 401Electronic signature infrastructureArt.21(2)(h) cryptography
ISO/IEC 27001:2022ISMS frameworkArt.21(2)(a) risk analysis
NIST SP 800-53 Rev.5Security controls catalogGeneral controls mapping
ENISA Good Practices for NIS2EU-specific guidanceDirect NIS2 alignment
SOC 2 Type IISaaS trust principlesAcceptable for audit evidence

You do not need to certify against all of these. But you must demonstrate awareness and intentional selection — "we reviewed ISO 27001 and implemented equivalent controls because full certification is disproportionate to our entity size" is a valid documented position.

Factor 3: Cost of Implementation

Proportionality explicitly allows you to not implement measures where the cost exceeds the risk benefit — but this must be documented.

The formula NCAs use informally: justified cost ceiling = (likelihood × impact × asset value) × some multiplier.

If implementing HSM-backed key management costs €40,000/year and your entire annual revenue is €80,000, you can document this as disproportionate and implement software-based key management with compensating controls. If your revenue is €4M, the same argument fails.

Factor 4: Likelihood and Severity of Incidents

This is where your Art.21(2)(a) Risk Register feeds into Art.21(1). Each measure's implementation level must correspond to assessed likelihood and severity:


2. Entity Size Tiers and What They Mean in Practice

NIS2 distinguishes Essential Entities (EE) from Important Entities (IE), and within those, applies different expectations based on entity size. While the Directive does not create explicit "size brackets" for Art.21(1), ENISA guidance and early NCA enforcement signals indicate:

Entity TypeRevenue/SizeExpected Proportionality Level
Essential Entity, large>€250M / >250 employeesFull ISO 27001 or equivalent, formal ISMS
Essential Entity, medium€50-250M / 50-250 employeesDocumented ISMS, most controls certified
Important Entity, medium€10-50M / 10-50 employeesRisk-based controls, documented gaps acceptable
Important Entity, small<€10M / <10 employeesLightweight ISMS, proportionality defense critical

SaaS teams in the €1-10M ARR range (typical sota.io customers) are usually Important Entities if they serve other businesses in critical sectors. The proportionality defense is strongest here — you can implement lean security with documented reasoning.


3. Proportionality in Practice: The Three-Step Documentation Method

When an NCA auditor reviews your NIS2 compliance posture, they are not checking boxes — they are evaluating whether you have thought through your security posture systematically. Art.21(1) is satisfied by demonstrating this thought process.

Step 1: Asset-Risk Matrix

Map assets to their risk exposure. For a typical SaaS application:

Asset: Customer authentication tokens
Likelihood of breach: HIGH (credential stuffing is commodity)
Severity: HIGH (account takeover → service disruption, data breach)
→ Proportionate measure: MFA mandatory + rate limiting + breach detection
→ Investment level: HIGH — disproportionate cost defense NOT applicable

Asset: Internal deployment logs
Likelihood of breach: LOW (not externally exposed)
Severity: MEDIUM (operational data, not personal data)
→ Proportionate measure: access control + 90-day retention
→ Investment level: LOW — SOC2 log access controls sufficient

Step 2: Control Selection Justification

For each Art.21(2) sub-measure, document:

This is not bureaucratic overhead — it is your audit defense. A one-page justification per measure is sufficient for Important Entities with fewer than 50 employees.

Step 3: Gap Register

Document measures you have not implemented at the "state of the art" level, with your proportionality reasoning. An honest gap register is stronger audit evidence than a control list that cannot be demonstrated.

Gap: HSM-backed key management (Art.21(2)(h))
Current state: Software-based key management in cloud KMS
State of art: Hardware Security Module
Proportionality reasoning: Cost €35,000/year. Annual revenue €600,000.
Risk exposure: Encryption keys for data at rest. No regulatory requirement
for HSM at this entity size per ENISA guidance (2024).
Compensating controls: Cloud KMS audit logs, key rotation every 90 days,
access restricted to two operators with MFA.
Accepted residual risk: MEDIUM. Reviewed and accepted by CISO [date].

4. Python NIS2ProportionalityAssessor

This tool generates audit-ready proportionality documentation for each Art.21(2) measure.

#!/usr/bin/env python3
"""
NIS2 Art.21(1) Proportionality Assessor
Generates documented proportionality justifications for NCA audit.
"""

from dataclasses import dataclass, field
from enum import Enum
from typing import Optional
import json
from datetime import date

class RiskLevel(Enum):
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"

class ImplementationLevel(Enum):
    MINIMAL = "minimal"
    STANDARD = "standard"
    ENHANCED = "enhanced"
    NOT_IMPLEMENTED = "not_implemented"

@dataclass
class EntityProfile:
    name: str
    annual_revenue_eur: float
    employee_count: int
    entity_type: str  # "essential" or "important"
    sector: str
    critical_services: list[str] = field(default_factory=list)

@dataclass
class ControlAssessment:
    measure_id: str  # e.g. "Art.21(2)(a)"
    measure_name: str
    likelihood: RiskLevel
    severity: RiskLevel
    implementation_level: ImplementationLevel
    current_state: str
    state_of_art: str
    implementation_cost_eur: Optional[float]
    justification: str
    compensating_controls: list[str] = field(default_factory=list)
    review_date: Optional[date] = None
    accepted_by: Optional[str] = None

    def proportionality_score(self, entity: EntityProfile) -> float:
        """Score 0-1: how defensible this assessment is under Art.21(1)."""
        risk_score = {
            RiskLevel.LOW: 0.2,
            RiskLevel.MEDIUM: 0.5,
            RiskLevel.HIGH: 0.8,
            RiskLevel.CRITICAL: 1.0
        }
        impl_score = {
            ImplementationLevel.NOT_IMPLEMENTED: 0.0,
            ImplementationLevel.MINIMAL: 0.3,
            ImplementationLevel.STANDARD: 0.7,
            ImplementationLevel.ENHANCED: 1.0
        }

        risk = max(risk_score[self.likelihood], risk_score[self.severity])
        impl = impl_score[self.implementation_level]

        # Cost factor: if cost > 5% of revenue, reduced implementation can be justified
        cost_factor = 1.0
        if self.implementation_cost_eur and entity.annual_revenue_eur > 0:
            cost_ratio = self.implementation_cost_eur / entity.annual_revenue_eur
            if cost_ratio > 0.05:
                cost_factor = 0.7  # higher cost = more proportionality defense room

        # Gap penalty: if high risk + not implemented = weak position
        if risk >= 0.8 and impl <= 0.3:
            return 0.2  # very weak — auditor will challenge

        return min(1.0, (impl + (1 - risk) * cost_factor) / 2)

class NIS2ProportionalityAssessor:
    def __init__(self, entity: EntityProfile):
        self.entity = entity
        self.assessments: list[ControlAssessment] = []

    def add_assessment(self, assessment: ControlAssessment):
        self.assessments.append(assessment)

    def generate_report(self) -> dict:
        report = {
            "entity": self.entity.name,
            "assessment_date": date.today().isoformat(),
            "entity_type": self.entity.entity_type,
            "controls": [],
            "overall_posture": "",
            "audit_readiness": 0.0
        }

        scores = []
        for a in self.assessments:
            score = a.proportionality_score(self.entity)
            scores.append(score)
            report["controls"].append({
                "measure": a.measure_id,
                "name": a.measure_name,
                "implementation": a.implementation_level.value,
                "proportionality_score": round(score, 2),
                "justification": a.justification,
                "gap_documented": a.implementation_level in [
                    ImplementationLevel.MINIMAL,
                    ImplementationLevel.NOT_IMPLEMENTED
                ]
            })

        avg = sum(scores) / len(scores) if scores else 0
        report["audit_readiness"] = round(avg, 2)
        report["overall_posture"] = (
            "STRONG" if avg >= 0.75 else
            "ACCEPTABLE" if avg >= 0.55 else
            "WEAK — remediation required before audit"
        )
        return report

    def export_gap_register(self) -> list[dict]:
        gaps = []
        for a in self.assessments:
            if a.implementation_level in [
                ImplementationLevel.MINIMAL,
                ImplementationLevel.NOT_IMPLEMENTED
            ]:
                gaps.append({
                    "measure": a.measure_id,
                    "gap": f"Below state-of-art: {a.current_state} vs {a.state_of_art}",
                    "proportionality_reasoning": a.justification,
                    "compensating_controls": a.compensating_controls,
                    "accepted_by": a.accepted_by,
                    "review_date": a.review_date.isoformat() if a.review_date else None
                })
        return gaps


# --- Example usage ---
if __name__ == "__main__":
    entity = EntityProfile(
        name="ExampleSaaS GmbH",
        annual_revenue_eur=800_000,
        employee_count=12,
        entity_type="important",
        sector="digital_infrastructure",
        critical_services=["B2B API platform", "Data processing pipeline"]
    )

    assessor = NIS2ProportionalityAssessor(entity)

    assessor.add_assessment(ControlAssessment(
        measure_id="Art.21(2)(h)",
        measure_name="Cryptography and Encryption Policy",
        likelihood=RiskLevel.MEDIUM,
        severity=RiskLevel.HIGH,
        implementation_level=ImplementationLevel.STANDARD,
        current_state="Cloud KMS (AWS/GCP), TLS 1.3, AES-256-GCM at rest",
        state_of_art="HSM-backed key management + post-quantum algorithms",
        implementation_cost_eur=35_000,
        justification=(
            "HSM cost of €35,000/year represents 4.4% of annual revenue. "
            "ENISA guidance for important entities with <50 employees allows "
            "cloud KMS as proportionate alternative with compensating controls."
        ),
        compensating_controls=[
            "Cloud KMS audit logging enabled",
            "Key rotation every 90 days automated",
            "Access restricted to 2 operators with MFA"
        ],
        review_date=date(2026, 10, 1),
        accepted_by="CISO"
    ))

    assessor.add_assessment(ControlAssessment(
        measure_id="Art.21(2)(j)",
        measure_name="Multi-Factor Authentication",
        likelihood=RiskLevel.HIGH,
        severity=RiskLevel.HIGH,
        implementation_level=ImplementationLevel.ENHANCED,
        current_state="TOTP MFA on all admin + customer accounts, WebAuthn supported",
        state_of_art="WebAuthn/FIDO2 phishing-resistant MFA across all access points",
        implementation_cost_eur=2_000,
        justification=(
            "Full WebAuthn migration in progress. TOTP is state-of-practice "
            "for important entities. Given HIGH likelihood of credential attacks, "
            "implementation at ENHANCED level is proportionate and required."
        ),
        review_date=date(2026, 7, 1),
        accepted_by="CTO"
    ))

    report = assessor.generate_report()
    print(json.dumps(report, indent=2))

    gaps = assessor.export_gap_register()
    if gaps:
        print("\n=== Gap Register ===")
        for gap in gaps:
            print(json.dumps(gap, indent=2))

5. The 20-Item Proportionality Audit Checklist

Use this before your first NCA audit or annual review:

Documentation

Risk Foundation

State of the Art

Entity Size Alignment

Ongoing


Art.21(1) is the legal architecture that makes everything else defensible. Every time a NIS2 requirement seems impossible for your team size or budget, Art.21(1) is your tool:

The teams that pass NCA audits in 2026 are not the ones with the most security tools — they are the ones with documented, coherent, proportionate security postures where every gap can be explained and every control can be justified.


Deploy Your NIS2-Compliant SaaS on EU Infrastructure

Infrastructure compliance starts at the hosting layer. sota.io provides EU-only deployment with no U.S. parent company, no CLOUD Act exposure, and encrypted storage by default — giving you a defensible infrastructure baseline for Art.21(1) documentation without the overhead of managing it yourself.

Related NIS2 Developer Guides: