2026-04-19·18 min read·

CRA Art.10: Security Obligations During the Product Lifecycle — Updates, Vulnerability Handling, and End-of-Life (Developer Guide 2026)

Post #460 in the sota.io EU Cyber Compliance Series

The EU Cyber Resilience Act (Regulation (EU) 2024/2847, "CRA") entered into force on 10 December 2024. Most developer guides focus on pre-market obligations: what you must build before releasing a product. Article 10 is different. It governs what you must keep doing after release — for the entire supported lifetime of your product.

This is the obligation that most software teams underestimate. You can complete a conformity assessment, draft an SBOM, and attach a CE marking. But Article 10 requires that you maintain a functioning security-update pipeline, respond to vulnerabilities in a coordinated way, and formally notify users when you intend to stop providing security support — and you must do this continuously, for years.

This guide explains:


Where Article 10 Fits in the CRA Structure

The CRA structures manufacturer obligations across several articles. It helps to understand where Article 10 sits before reading it in detail.

ArticleWhat It CoversWhen It Applies
Art.6Essential cybersecurity requirements (Annex I) — security-by-design, vulnerability handling processes, secure configurationBefore market placement
Art.13Manufacturer obligations — conduct risk assessment, maintain technical documentation, draw up declaration of conformity, affix CE markingBefore market placement
Art.10Ongoing security obligations after release — updates, SBOM maintenance, end-of-lifeAfter market placement, throughout supported lifetime
Art.14Reporting obligations — notify ENISA within 24h of actively exploited vulnerability discoveryOngoing, event-triggered
Art.16Coordinated vulnerability disclosure — publish a CVD policy, handle incoming vulnerability reportsOngoing

Article 10 is the post-release pillar. A product that passes its conformity assessment but lacks a functioning update pipeline is non-compliant from the moment Article 10 obligations begin to apply — which, for the update and vulnerability-handling provisions, is 11 September 2026.


Article 10 Obligations — Clause by Clause

10(1): Manufacturers Shall Make Security Updates Available

"Manufacturers shall ensure that vulnerabilities of the product with digital elements are handled effectively throughout the expected product lifetime or for a period of five years from the date when the product is placed on the market, whichever is shorter, or for a period of at least five years if the expected product lifetime is longer."

This is the core commitment. You must handle vulnerabilities and provide security updates for:

The "expected product lifetime" is determined by you at the time of conformity assessment and must be documented in your technical documentation (Art.13). If you sell software-as-a-product with a perpetual licence model and no defined end-of-life, the regulator will likely interpret this as a lifetime of at least 5 years.

Practical implication: If you release a product in September 2026, you are committing to security update support until at least September 2031. You cannot release a product and then quietly stop patching it 18 months later.

10(2): Updates Must Be Free of Charge

"Manufacturers shall ensure that security updates are provided to users free of charge."

Security updates cannot be paywalled. This applies to the security update itself — not to paid support contracts, priority response times, or feature releases. You may still charge for:

But the update that fixes the CVE in your software must be available to every user, regardless of whether they are on a free or paid tier. Gating critical security fixes behind a subscription is explicitly prohibited.

Implementation note: If your product uses a subscription model where some features are paid-tier only, you need to architect your update pipeline so that security patches are applied to all licence tiers. This affects how you structure version branches and release channels.

10(3): Security Updates Must Be Separable from Feature Updates

"Manufacturers shall ensure that security updates are provided separately from non-security updates, unless joint provision is technically necessary."

You cannot bundle security fixes exclusively into major feature releases. If a CVE is fixed in your codebase today, users must be able to receive that fix without also taking on the regression risk of every new feature you developed in the same release.

The "unless technically necessary" exception is narrow. You cannot claim technical necessity simply because your architecture makes separate releases inconvenient. The exception covers genuine technical dependencies where the security fix cannot be backported to an older stable branch.

What this means for your release process:

✓ Maintain a stable security-patch branch (e.g., v2.3.x) alongside main
✓ Backport CVE fixes to the stable branch and release independently
✓ Users on v2.3.x receive security patches without being forced to v3.x
✗ "Please upgrade to v3 to get the security fix" — non-compliant
✗ "Our next quarterly release will include the fix" — potentially non-compliant

10(4): Automatic Updates — Default On

"Manufacturers shall ensure that automatic security updates are enabled by default, unless the user has explicitly opted out, and inform the user thereof."

This is one of the most operationally challenging requirements. Your product must:

  1. Check for security updates automatically (on a schedule or via notification push)
  2. Apply security updates automatically — without requiring the user to manually initiate installation
  3. Default to this behaviour — the user does not need to opt in, they need to opt out
  4. Inform the user that automatic updates are enabled and how to disable them

The requirement to inform users covers both the initial disclosure (at installation or first use) and each time an automatic update is applied. Users must be able to see what changed.

Platform-specific implementation considerations:

PlatformMechanismChallenge
Web SaaSServer-side deployment — update is automatic by natureLower burden: update happens before user interaction
Desktop appOS-level auto-updater (Sparkle, Squirrel, Electron updater)Must be enabled by default; admin privilege complications
CLI toolPackage manager update notificationsHarder: user must invoke update; consider auto-check with prompt
Firmware / embeddedOTA update infrastructureSignificant engineering investment; connectivity assumptions
Docker imageTag pinning defeats auto-update; digest tracking requiredNotify users when a new security-patched digest is available

For server-deployed products, the auto-update requirement is most naturally met by keeping your users on a managed service where you control deployments. Self-hosted installations require an active update mechanism.

10(5): Vulnerability Handling Throughout the Lifecycle

"Manufacturers shall put in place and enforce a policy for coordinated vulnerability disclosure."

The Art.16 obligation (CVD policy) applies at market placement, but Article 10 reinforces that the CVD process must remain operational for the full supported lifetime. A CVD policy that exists in a document but is not enforced — no one monitors the security@ inbox, reports go unacknowledged — violates this provision.

Ongoing CVD obligations include:

10(6): SBOM Maintenance After Release

"Manufacturers shall document and keep up to date information necessary to assess the cybersecurity of the products with digital elements, including by maintaining a software bill of materials."

The SBOM is not a one-time document you generate at release. Every time you release a security update, your SBOM must be updated to reflect:

The SBOM must be maintained in a machine-readable format (SPDX 2.3 or CycloneDX 1.4+ are the de facto standard formats accepted by European market surveillance authorities).

Automated SBOM update pipeline:

# sbom_updater.py — called after each security release
import json
import subprocess
from datetime import datetime, timezone

def generate_updated_sbom(project_root: str, version: str) -> dict:
    """Generate updated CycloneDX SBOM after a security patch release."""
    # Run your preferred SBOM generator
    result = subprocess.run(
        ["cyclonedx-py", "environment", "--output-format", "json"],
        cwd=project_root,
        capture_output=True,
        text=True,
        check=True
    )
    sbom = json.loads(result.stdout)
    
    # Update metadata
    sbom["metadata"]["timestamp"] = datetime.now(timezone.utc).isoformat()
    sbom["metadata"]["component"]["version"] = version
    
    # Add security-patch annotation
    sbom["metadata"]["properties"] = sbom["metadata"].get("properties", [])
    sbom["metadata"]["properties"].append({
        "name": "cra:update-type",
        "value": "security-patch"
    })
    
    return sbom

def verify_sbom_completeness(sbom: dict) -> list[str]:
    """Check that all components have PURL and known-vulnerability status."""
    issues = []
    for component in sbom.get("components", []):
        if not component.get("purl"):
            issues.append(f"Missing PURL: {component.get('name', 'unknown')}")
        if not component.get("licenses"):
            issues.append(f"Missing license: {component.get('name', 'unknown')}")
    return issues

10(7): Network of CSIRTs Notification

Article 10 cross-references the Art.14 notification obligations. When you discover an actively exploited vulnerability in your product:

  1. Within 24 hours: Submit an early warning to the relevant ENISA single reporting platform
  2. Within 72 hours: Submit a vulnerability notification with severity, affected versions, and preliminary mitigation
  3. Within 14 days: Submit a final report with root cause analysis and remediation confirmation

The 24-hour clock starts when you become aware that exploitation is active — not when you become aware that a vulnerability exists. A vulnerability you discover through internal code review does not trigger the 24-hour clock until you have evidence of active exploitation.

10(8): User Notification of Updates

"Manufacturers shall inform users about security updates that are available or have been automatically applied."

Every security update must be accompanied by a notification to affected users. The notification must include:

The notification channel can be in-product (a dashboard alert, a release notes page) or out-of-band (email, RSS feed, security mailing list). The key requirement is that users have a reliable mechanism to learn about security changes without having to proactively poll your website.

Minimum viable notification template:

Subject: [SECURITY] YourProduct v2.3.7 — Critical Security Update

A security update for YourProduct has been released.

Severity: Critical (CVSS 9.1)
CVE: CVE-2026-12345
Affected versions: 2.0.0 – 2.3.6
Fixed in: 2.3.7

What was fixed: A remote code execution vulnerability in the YAML 
parser allowed unauthenticated attackers to execute arbitrary code 
via a crafted configuration file.

Update action: [automatic update has been applied / please update via...]

Full advisory: https://yourdomain.com/security/advisories/2026-001

The End-of-Life Obligation

Article 10's end-of-life provisions are among the most operationally novel requirements for software teams.

You Must Define an End of Support Date

If your product has a finite support lifetime, you must state what it is. This information must appear in:

You Must Notify Users Before EoL

"Manufacturers shall inform users, as early as possible, and no later than 14 days before the end of the support period, about the end of the support period."

Fourteen days is the legal minimum. In practice, responsible disclosure of end-of-life requires substantially more notice — at least 12 months for enterprise software, and ideally longer for products embedded in critical infrastructure or where migration is complex.

The notification must explain:

After EoL: Residual Obligations

Once the support period ends and you have notified users in advance, you are no longer obligated to provide new security updates. However:


Implementation Roadmap for Article 10 Compliance

Stage 1: Lifecycle Documentation (Complete Before September 2026)

# product-lifecycle.yaml — commit this to your compliance repository
product:
  name: "YourProduct"
  version_series: "2.x"
  initial_market_date: "2026-09-01"
  expected_product_lifetime_years: 5
  end_of_security_support_date: "2031-09-01"
  
security_update_policy:
  updates_free: true
  updates_automatic_by_default: true
  updates_separable_from_features: true
  separate_security_branch: "v2-security"
  
notification_channels:
  in_product: true
  security_mailing_list: "security-announce@yourdomain.com"
  rss_feed: "https://yourdomain.com/security/feed.xml"
  
cvd_policy_url: "https://yourdomain.com/security/cvd"
sbom_format: "CycloneDX 1.6"
sbom_location: "https://yourdomain.com/security/sbom/v2-latest.json"

Stage 2: Security Branch Infrastructure

Set up a dedicated security-patch branch in your version control:

# Establish a security-patch branch from the current stable release
git checkout -b v2-security v2.3.6

# Pin this branch — only security patches, no feature commits
# Protect with branch rules: require PR + security team review
git push origin v2-security

# Configure CI to build and release from this branch independently
# of your main development branch

Stage 3: Automated Update Distribution

Configure your update delivery pipeline so that security patches from v2-security are automatically picked up by deployed instances:

# .github/workflows/security-release.yml
name: Security Patch Release

on:
  push:
    branches: [v2-security]
    tags: ['v2.*-security*']

jobs:
  release:
    name: Build and Distribute Security Patch
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Build security-patched artifact
        run: make build-security-patch
      
      - name: Update SBOM
        run: |
          cyclonedx-py environment --output-format json > sbom-v2-latest.json
          # Validate completeness
          python3 scripts/validate_sbom.py sbom-v2-latest.json
      
      - name: Publish to update server
        run: |
          # Push to your update distribution endpoint
          # This is what auto-update clients will poll
          ./scripts/publish-security-update.sh
      
      - name: Notify users
        run: |
          # Send to security mailing list
          ./scripts/notify-security-update.sh \
            --version "${{ github.ref_name }}" \
            --advisory-url "https://yourdomain.com/security/advisories/"
      
      - name: Publish updated SBOM
        run: |
          aws s3 cp sbom-v2-latest.json \
            s3://your-bucket/security/sbom/v2-latest.json \
            --content-type application/json

Stage 4: Monitoring and Alerting

You cannot fulfil Article 10 without knowing when vulnerabilities appear in your dependencies. Set up dependency vulnerability monitoring:

# vulnerability_monitor.py — run daily in CI
import subprocess
import json

def check_dependencies_for_vulnerabilities(requirements_file: str) -> list[dict]:
    """Check if any current dependencies have known CVEs."""
    result = subprocess.run(
        ["pip-audit", "--format", "json", "-r", requirements_file],
        capture_output=True,
        text=True
    )
    
    if result.returncode != 0:
        data = json.loads(result.stdout)
        vulns = []
        for dep in data.get("dependencies", []):
            for vuln in dep.get("vulns", []):
                vulns.append({
                    "package": dep["name"],
                    "installed_version": dep["version"],
                    "vuln_id": vuln["id"],
                    "fix_versions": vuln.get("fix_versions", []),
                    "description": vuln.get("description", ""),
                })
        return vulns
    return []

def alert_if_critical(vulnerabilities: list[dict]) -> None:
    """Send PagerDuty/Slack alert for critical CVEs requiring immediate patch."""
    critical = [v for v in vulnerabilities if "CRITICAL" in v.get("description", "").upper()
                or any("critical" in str(fv).lower() for fv in v.get("fix_versions", []))]
    if critical:
        # Your alert mechanism here
        print(f"CRITICAL: {len(critical)} critical CVEs require immediate security patch")
        for v in critical:
            print(f"  {v['package']} {v['installed_version']}: {v['vuln_id']}")

Article 10 vs. Article 13: What Happens When?

A common source of confusion is the distinction between pre-market obligations (Art.13) and post-market obligations (Art.10). Here is the clearest way to think about it:

QuestionArticle 13 (Pre-Market)Article 10 (Post-Market)
When does it apply?Before you place the product on the EU marketAfter the product is on the market
What does it require?Risk assessment, technical documentation, conformity assessment, CE marking, SBOM at releaseSecurity updates, SBOM maintenance, EoL notification, ongoing vulnerability handling
Who enforces it?Notified bodies (conformity assessment) + market surveillance at point of placementMarket surveillance authorities throughout the product lifetime
What triggers enforcement?Placing the product on the market without complianceA security incident, complaint, or routine market surveillance audit
Penalty for violation?Cannot legally sell in the EUWithdrawal order, fine up to €15M or 2.5% global revenue

Both articles carry the same maximum financial penalties under Article 64. The difference is when enforcement can occur. Article 10 violations can emerge years after a product was initially compliant — if you stop maintaining it while it is still on the market.


Common Mistakes and How to Avoid Them

Mistake 1: Treating the SBOM as a Static Artifact

What happens: A team generates an SBOM at the time of their first conformity assessment, commits it to the repo, and never updates it again.

Why it's a violation: Article 10(6) requires that you "keep up to date information necessary to assess the cybersecurity of the products with digital elements." Every security update that changes component versions invalidates an unchanged SBOM.

Fix: Automate SBOM regeneration as part of your security release pipeline. Never check in a manually edited SBOM.

Mistake 2: Gating Security Patches Behind Paid Upgrades

What happens: A vulnerability is fixed in v3.0 (paid upgrade) but not backported to v2.x (the version most existing users are on).

Why it's a violation: Article 10(2) requires that security updates are provided free of charge. If fixing a CVE requires purchasing a new major version, the security update is not free.

Fix: Maintain a security-patch branch for each supported version series. Backport security fixes even when feature development has moved on.

Mistake 3: Bundling Security Fixes with Feature Updates

What happens: A team packages 60 days of feature development together with three CVE fixes in a quarterly release. Users on an older version cannot get the security fixes without taking the full feature upgrade.

Why it's a violation: Article 10(3) requires security updates to be separately available unless technically necessary.

Fix: Release security patches on the security-patch branch independently. Users on a supported version series can apply the patch without feature migration.

Mistake 4: No Formal EoL Process

What happens: A product's support quietly lapses. No announcement is made. Users continue running unsupported software believing it is still receiving patches.

Why it's a violation: Article 10 requires advance notification of the end of the support period, not less than 14 days (and in practice, responsible vendors give 12+ months notice).

Fix: Include the end-of-support date in your technical documentation from the moment the product is placed on the market. Schedule the EoL communication campaign in advance.

Mistake 5: Auto-Updates Off by Default

What happens: An installer presents the user with "Check for updates: ☐ Enable" unchecked by default.

Why it's a violation: Article 10(4) requires automatic security updates to be enabled by default. The user must explicitly opt out, not opt in.

Fix: Audit all installer defaults. Auto-update must be active from the first launch unless the user has explicitly deselected it during setup.


CRA Implementation Timeline

DateObligation
10 December 2024CRA enters into force
11 September 2026Art.14 reporting obligations apply (ENISA vulnerability notifications)
11 December 2027Full CRA application — Art.10 obligations apply to all products placed on the market
From market placementArt.10 commitments attach to each product at the moment it is placed on the EU market

Note: the "from market placement" row matters for products placed on the market after December 2027. If you sell a product from January 2028, you are immediately bound by Article 10 obligations for the supported lifetime of that product.

For products placed on the market before December 2027, the obligations apply from December 2027 — you do not get a grace period for existing products simply because they were placed on the market while the CRA was being implemented.


Enforcement and Penalties

Market surveillance authorities (MSAs) can enforce Article 10 violations through the mechanisms in Articles 54–64 of the CRA. Key enforcement tools:

Post-market surveillance is event-driven: most Article 10 investigations will begin after a security incident, a vulnerability disclosure that reveals the manufacturer had no update mechanism, or a complaint from a user who received no end-of-life notification. Proactive audits are also possible but less common in the initial enforcement phase.

MSAs share information through the EU ENISA coordination network, and a finding in one Member State can trigger coordinated action across the EU.


The sota.io Connection

Running software products on sota.io's EU-native infrastructure simplifies several Article 10 compliance patterns:


Article 10 Compliance Checklist

Pre-market (before placing on EU market):
☐ Defined expected product lifetime in technical documentation
☐ Calculated security update end date (max(5 years, expected lifetime))
☐ Established security-patch branch separate from main development
☐ Configured auto-update mechanism, enabled by default
☐ Set up security mailing list / notification channel
☐ Integrated SBOM generation into release pipeline
☐ Documented EoL communication plan

Ongoing (throughout supported lifetime):
☐ CVD policy publicly accessible and actively monitored
☐ Dependency vulnerability scanning running (daily recommended)
☐ Security patches released on security-patch branch, not bundled in features
☐ SBOM updated with each security release
☐ Users notified of each security update (in-product + out-of-band)
☐ Zero critical CVEs older than 30 days without released patch or timeline

End-of-life (before support ends):
☐ EoL date communicated to all users (≥14 days; recommend ≥12 months)
☐ Final patched version clearly identified
☐ Migration guidance published
☐ EoL date recorded in SBOM metadata
☐ Market surveillance authority notified if required by MSA

Where to Learn More


CRA Series Index

ArticleTopicPost
Art.2Scope — what products are covered#455
Art.3Definitions — manufacturer, distributor, importer#456
Art.6Essential requirements — Annex I obligations#457
Art.7Presumption of conformity via harmonised standards#458
Art.8OSS Steward obligations — foundations and maintainers#459
Art.9Due diligence for third-party components — SBOM, supply chain#463
Art.10Security obligations during product lifecycle#460 (this post)
Art.11Vulnerability handling — ban on known bugs, CVD policy#461
Art.12Authorised representative for non-EU manufacturers#462
Art.13Manufacturer obligations at market placement#400
Art.16Vulnerability reporting — ENISA notification obligations#416