Skip to content
Stribog

Compliance

All writing

The Cyber Resilience Act Reaches Your Build Pipeline

Cyber Resilience Act reporting starts 11 September 2026. Map manufacturer and open-source steward obligations onto a self-hosted build pipeline.

Stribog13 min read

Regulation (EU) 2024/2847 is the next EU regime after NIS2 and the AI Act to put engineering obligations on software — and the first that does not care what you operate, only what you supply. What follows is a reading of the text for the engineer who builds the evidence, not legal advice; where the reasoning is inference, it says so.

Three Dates: One Already Live, One Forty Days Out, One in 2027

Article 71 sets the clock, and it is not one date: the Regulation "shall apply from 11 December 2027. However, Article 14 shall apply from 11 September 2026 and Chapter IV (Articles 35 to 51) shall apply from 11 June 2026."

Chapter IV is notified-body and conformity-assessment machinery — assessment bodies, not platform teams. Article 14, the reporting duty, starts in forty days. Everything else waits until 11 December 2027: Annex I, Article 13, technical documentation, CE marking. No manufacturer files a CRA notification today.

The mechanism is not there either. ENISA is building the Single Reporting Platform under Article 16, and the Commission's reporting page still says it "will be operational by 11 September 2026 … Functional and security testing are under way." Voluntary reporting opens only after that date. Build the internal path — detection to determination to notification — against Article 14, not a platform you cannot see.

Manufacturer, Steward, or Neither: Run the Scope Test

Article 2(1) is the hinge: the Regulation "applies to products with digital elements made available on the market" whose use "includes a direct or indirect logical or physical data connection to a device or network." Made available — not deployed, not operated, not depended upon. Article 3(22) is broader than "sold": supply "in the course of a commercial activity, whether in return for payment or free of charge." Free of charge is inside; commercial activity is the filter.

Two obligated categories follow. A manufacturer "develops or manufactures products with digital elements … and markets them under its name or trademark, whether for payment, monetisation or free of charge." A steward is "a legal person, other than a manufacturer," systematically providing "support on a sustained basis for the development of specific products … qualifying as free and open-source software and intended for commercial activities," and ensuring their viability.

A third position — neither — is where most self-hosting organisations land. That is still an answer you must show you reached, the way an ISO 27001 scope statement sets the cost of everything downstream.

The scope test as a flow. Each edge cites the article that turns it. The answers are yours to defend; the questions are not optional.

The Scope Traps: Internal Platforms, Forks, and Monetised Open Source

The internal platform. You built it and never supplied it to anyone. Out of scope, most likely — but be precise why. Recital 16's own-use carve-out is written for one kind of body: products "developed or modified by a public administration entity exclusively for its own use" are not made available. A private company is not that, so the argument runs through Article 2(1) and 3(22). A reading, not a stated exemption: write it down, date it, have counsel confirm it.

The published fork. Recital 18 is generous: software "not monetised by their manufacturers should not be considered to be a commercial activity," and "the mere presence of regular releases should not in itself" make supply commercial. The Commission's open-source page adds that the CRA "does not apply to developers who contribute with source code … not under their responsibility."

The trap is on the other side. Article 22(1): a person "other than the manufacturer … that carries out a substantial modification … and makes that product available on the market, shall be considered to be a manufacturer." Article 3(30) makes that a post-market change "which affects the compliance of the product … with the essential cybersecurity requirements set out in Part I of Annex I" or modifies its intended purpose. Fork, monetise, materially change: manufacturer, without writing a product from scratch.

The monetised distribution. Monetisation is not confined to a price on the binary: a support contract, hosted control plane or paid tier attached to what you publish starts to look like commercial supply. On 27 July 2026 the Commission published implementation guidance on exactly these questions: scope for remote data processing and open-source software, substantial modification, support periods. Guidance is a layer distinct from the statute, but this close to the line it is the first thing to hand counsel.

Annex I Part II, Mapped to Pipeline Artefacts

Inside scope as a manufacturer, Annex I Part II's numbered points touch the pipeline directly, and most describe what a disciplined pipeline already produces.

  • (1) SBOM — "in a commonly used and machine-readable format covering at the very least the top-level dependencies". Your CI SBOM step, keyed to the digest.
  • (2) Separate security updates — security updates "provided separately from functionality updates" where technically feasible. A patch line distinct from the feature line.
  • (4) Disclosure after the fix — a description, "information allowing users to identify the product … affected", impacts, severity, and "clear and accessible information helping users to remediate". An advisory, not a changelog entry.
  • (5) CVD policy — "put in place and enforce a policy on coordinated vulnerability disclosure". SECURITY.md, enforced not decorative.
  • (6) Contact address — for reports on the product "as well as in third-party components contained in that product".
  • (7) Secure distribution — securely, "and, where applicable for security updates, in an automatic manner".
  • (8) Dissemination — "without delay and … free of charge, accompanied by advisory messages".

Article 13 wraps duties around them. Article 13(5) requires due diligence over third-party components "including … free and open-source software that ha[s] not been made available on the market in the course of a commercial activity" — the free dependency gets no free pass. Article 13(6) goes further: on finding a component vulnerability you report it upstream and, where you wrote a fix, "share the relevant code or documentation with the person or entity … maintaining the component".

Correspondence, not discharge. Each row pairs something the pipeline already emits with the text of a requirement — conformity assessment, Annex VII documentation and CE marking are separate steps.
bash
#!/usr/bin/env bash
set -euo pipefail

# Versions recorded beside the evidence they produce. Three binaries on
# PATH, not two: crane is a separate install from Syft and Cosign.
SYFT_VERSION="v1.50.0"    # anchore/syft
COSIGN_VERSION="v3.1.2"   # sigstore/cosign
CRANE_VERSION="v0.21.8"   # google/go-containerregistry
COSIGN_KEY_REF="${COSIGN_KEY_REF:?set to a key file path or a KMS URI}"

IMAGE="registry.example.internal/platform/api"
TAG="2026.8.0"

# A tag is a pointer, and an SBOM attached to one describes whatever it
# moved to. Resolve once; use the digest everywhere.
DIGEST="$(crane digest "${IMAGE}:${TAG}")"
REF="${IMAGE}@${DIGEST}"
OUT="evidence/${TAG}"
mkdir -p "${OUT}"

# Annex I Part II(1). Both formats now: Article 13(24) lets the Commission
# specify one later, and re-emitting beats migrating.
syft "registry:${REF}" -o "cyclonedx-json=${OUT}/api.cdx.json" -o "spdx-json=${OUT}/api.spdx.json"

# Cosign's documented default is keyless signing against the Sigstore
# public-good Fulcio CA and Rekor log. --key opts out — the only answer
# for a pipeline with no public egress.
cosign attest --key "${COSIGN_KEY_REF}" --type cyclonedx \
  --predicate "${OUT}/api.cdx.json" --yes "${REF}"

# Record what produced the evidence, beside it.
printf '%s %s %s %s\n' "${REF}" "${SYFT_VERSION}" "${COSIGN_VERSION}" \
  "${CRANE_VERSION}" > "${OUT}/tools.txt"
Three pinned binaries — Syft v1.50.0, Cosign v3.1.2 and crane v0.21.8 from google/go-containerregistry, which resolves the tag to a digest. The interesting flag is the absent one: without --key, cosign signs keylessly against the public-good Fulcio CA and Rekor log — the wrong default for a pipeline that must run disconnected. Run this from CI on every tagged release, not by hand.

SBOM: What "Commonly Used and Machine-Readable" Pins You To

Annex I Part II(1) names no format, and Article 13(24) reserves the right to: "the Commission may … specify the format and elements of the software bill of materials." So: not "pick CycloneDX" or "pick SPDX" but pick a generator that emits both and converts between them. Syft advertises exactly that — multiple formats "including the ability to convert between SBOM formats". The format is a rendering; the artefact and its pinned dependency graph are durable.

Two details separate an SBOM that survives an audit: generate from the built artefact, not the source tree; key it to the digest, not the tag — the discipline that makes a self-hosted registry with admission verification worth operating. The SBOM and Sigstore mechanics are a subject of their own.

yaml
# .woodpecker.yml — evidence as a build output, not a reconstruction. Step
# images are mirrored and pinned; upstream crane and cosign are distroless,
# so commands: needs a /bin/sh variant.
when:
  - event: tag

steps:
  resolve:
    # Environment does not cross a step boundary; the workspace does.
    image: registry.example.internal/ci/crane:v0.21.8
    commands:
      - crane digest registry.example.internal/platform/api:$${CI_COMMIT_TAG} > .digest
      - echo "registry.example.internal/platform/api@$(cat .digest)" > .ref

  sbom:
    image: registry.example.internal/ci/syft:1.50.0
    commands:
      # The image, not dir:dist: a build directory carries no base-image
      # packages, so its SBOM describes something you never shipped.
      - syft "registry:$(cat .ref)" -o cyclonedx-json=dist/api.cdx.json -o spdx-json=dist/api.spdx.json

  attest:
    image: registry.example.internal/ci/cosign:3.1.2
    environment:
      COSIGN_KEY_PEM: { from_secret: cosign_key_pem }
      COSIGN_PASSWORD: { from_secret: cosign_password }
    commands:
      # Secrets arrive as environment; materialise the key file.
      - printf '%s' "$${COSIGN_KEY_PEM}" > /tmp/cosign.key
      - cosign attest --key /tmp/cosign.key --type cyclonedx --predicate dist/api.cdx.json --yes "$(cat .ref)"
The same steps wired into a Woodpecker pipeline, so the evidence is produced by the release rather than reconstructed for an auditor months later. One digest, resolved once: the SBOM describes the image the attestation is bound to.

The 24/72/14 Clock, and Where It Starts in Your Process

Article 14(1) is the duty: a manufacturer "shall notify any actively exploited vulnerability … that it becomes aware of simultaneously to the CSIRT designated as coordinator … and to ENISA", via the single reporting platform. Article 14(2) is the cadence — three steps, two anchors.

  1. Early warning — "without undue delay and in any event within 24 hours of the manufacturer becoming aware of it", naming the Member States where the product is available.
  2. Vulnerability notification — "within 72 hours", carrying "the general nature of the exploit and of the vulnerability concerned as well as any corrective or mitigating measures taken".
  3. Final report — "no later than 14 days after a corrective or mitigating measure is available", with severity, impact and update details.

That third anchor is the one teams get wrong. The 24- and 72-hour clocks run from awareness; the final report runs from fix availability, so a bug taking three months to remediate does not breach that deadline — it moves it. Article 14(4)'s cascade uses another anchor again: its final report is due "within one month after the submission of the incident notification" under the 72-hour limb.

The engineering question is what "becoming aware" means in your process. Not the alert firing — the point at which a human or a rule concludes that a vulnerability in your product is being actively exploited, at a timestamp your tooling either records or does not. Name that event: if your observability pipeline cannot say when the determination was made and by whom, the clock has no defensible start. Article 14(8) runs alongside: inform impacted users "in a structured, machine-readable format" where appropriate. Regulators get the notification; users get the advisory.

The steward gap the operator's FAQ smooths over

ENISA describes the SRP as a "single entry point" simplifying reporting "for manufacturers and open-source software stewards", and its FAQ presents the 24/72/final cadence with both in frame. The statute is narrower. Article 24(3) imports Article 14(1) for stewards "to the extent that they are involved in the development of the products", plus 14(3) and (8) where severe incidents "affect network and information systems provided by the open-source software stewards". Neither 14(2)'s schedule nor 14(4)'s cascade is imported.

State that gap plainly. Article 64(10) points the same direction: fines "shall not apply to … any infringement of this Regulation by open-source software stewards", and micro and small enterprises are not fined for missing the 24-hour early warning.

Advisories That Carry Remediation: Why VEX Alone Falls Short

Annex I Part II(4) enumerates what a disclosure carries: description, product identification, impacts, severity, remediation guidance. Compare VEX. The CSAF v2.0 specification — an OASIS Standard since 18 November 2022 — says of Profile 5: "the main purpose of the VEX format is to state that and why a certain product is, or is not, affected by a vulnerability."

VEX answers "does this apply to me". Part II(4) also asks "what do I do about it". Profile 4 is built for that: "this profile SHOULD be used to provide information which is related to vulnerabilities and corresponding remediations," with /document/category set to csaf_security_advisory. Our reading: a VEX statement alone does not carry the remediation guidance Part II(4) enumerates. Both have a place: VEX suppresses noise, an advisory says what to install.

json
{
  "document": {
    "category": "csaf_security_advisory",
    "csaf_version": "2.0",
    "title": "Platform API - session refresh accepts a revoked token",
    "publisher": {
      "category": "vendor",
      "name": "Example Engineering GmbH",
      "namespace": "https://example.com"
    },
    "tracking": {
      "id": "EXAMPLE-CSAF-2026-0004",
      "status": "final",
      "version": "1",
      "initial_release_date": "2026-08-02T09:00:00.000Z",
      "current_release_date": "2026-08-02T09:00:00.000Z",
      "revision_history": [
        { "date": "2026-08-02T09:00:00.000Z", "number": "1", "summary": "Published with fix." }
      ]
    }
  },
  "product_tree": {
    "branches": [
      {
        "category": "product_name",
        "name": "Platform API",
        "branches": [
          {
            "category": "product_version",
            "name": "2026.8.0",
            "product": { "product_id": "CSAFPID-0001", "name": "Platform API 2026.8.0" }
          },
          {
            "category": "product_version",
            "name": "2026.8.1",
            "product": { "product_id": "CSAFPID-0002", "name": "Platform API 2026.8.1" }
          }
        ]
      }
    ]
  },
  "vulnerabilities": [
    {
      "title": "Session refresh accepts a revoked token",
      "notes": [
        { "category": "description", "text": "A missing revocation check let a revoked session be renewed." }
      ],
      "product_status": { "known_affected": ["CSAFPID-0001"], "fixed": ["CSAFPID-0002"] },
      "scores": [
        {
          "products": ["CSAFPID-0001"],
          "cvss_v3": {
            "version": "3.1",
            "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
            "baseScore": 9.1,
            "baseSeverity": "CRITICAL"
          }
        }
      ],
      "remediations": [
        {
          "category": "vendor_fix",
          "details": "Upgrade to 2026.8.1 — patch line only, no functionality changes.",
          "product_ids": ["CSAFPID-0001"],
          "url": "https://example.com/security/EXAMPLE-CSAF-2026-0004"
        }
      ]
    }
  ]
}
The fields that answer Annex I Part II(4): the description note, product identification in product_tree, the CVSS score carrying severity and impact, and the remediations array — the last of which a VEX-only statement does not carry. Publish it at a stable, discoverable URL; a directory an operator's tooling can walk beats a blog post.

Optionality: Keep the Evidence Portable While the Standards Land

The route the CRA prefers runs through harmonised standards, which do not exist yet. The Commission's standardisation page records request "M/606, containing a set of 41 standards in support of the CRA"; CEN and CENELEC record it "officially accepted by CEN, CENELEC, and ETSI" on 3 April, delivery promised "at least one year before the CRA enters into application". Article 27(1) is unforgiving: presumption of conformity attaches to standards "the references of which have been published in the Official Journal" — published, not drafted.

That absence has a price, set by Article 32(2): where the manufacturer of an Annex III Class I important product "has not applied or has applied only in part harmonised standards … or where such harmonised standards … do not exist", the product goes through EU-type examination plus conformity to type (modules B and C), or full quality assurance (module H). Both need a notified body — hence Chapter IV eighteen months early.

Annex III's relevance to platform work is obvious once read. Class I covers identity and privileged access management, VPNs, "network management systems", PKI software and operating systems; Class II, "hypervisors and container runtime systems" and "firewalls, intrusion detection and prevention systems". Categories, not project names: important-product status turns on how a manufacturer places something on the market, not on your running it.

So keep evidence where it survives: standard formats, in the repository and registry you already operate rather than a compliance SaaS whose export button sets your exit cost — the argument that also drives ICT third-party risk under DORA and the NIS2 and AI Act overlaps. A re-emit path, not a migration.

The Long Game: A Support Period Outlives the Team

Article 13(8) sets the floor: "the support period shall be at least five years", or the expected use time where that is shorter. Article 13(9) should change how you configure a registry — each security update issued during the support period "remains available after it has been issued for a minimum of 10 years or for the remainder of the support period, whichever is longer".

Ten years is longer than most retention policies, most CI systems, and most teams — and the clock runs per update, so a fix shipped late is owed years after the product itself is done. That is a sovereign CI/CD commitment before it is a legal one: the build stays reproducible and the advisory path working after everyone who wrote the code has gone. What makes it survivable is a register, in git, of everything you place on the market.

yaml
# products.yaml - one entry per thing we place on the EU market. The scope
# determination is dated: in two years nobody remembers why.
products:
  - name: Platform API
    scope_determination:
      position: manufacturer # manufacturer | steward | neither
      basis: Supplied under our own name, commercially - Art 3(13), 3(22).
      annex_iii_class: none # none | class-i | class-ii
      decided_on: 2026-07-14
      counsel_review: 2026-07-21
    support_period:
      declared_start: 2026-08-02
      declared_end: 2031-08-02 # five-year minimum, Art 13(8)
    update_retention:
      # Art 13(9) runs per update, not per product, so there is no single
      # expiry date here. Each update stands ten years from ITS OWN issue
      # date, or to declared_end if later: a fix issued 2031-07-30 is owed
      # until 2041-07-30 — almost five years past a naive start-plus-ten.
      rule: max(issued_at + 10y, declared_end)
    disclosure:
      contact: [email protected] # Annex I Part II(6)
      policy: https://example.com/security/policy # II(5)
      advisories: https://example.com/.well-known/csaf/ # II(4)
    evidence: registry.example.internal/evidence/api # attested CycloneDX + SPDX
The cheapest artefact here, and the one most likely to be missing. It turns a scope determination into a decision with an author, and makes the trap legible: a fix shipped in year five is retained into year fifteen.

None of this is exotic. Read as engineering, the CRA asks for a bill of materials, a way to ship a fix on its own, somewhere to publish it, an address to receive reports, a signed distribution path, and a decade of keeping that up. A team running its own forge, CI, registry and disclosure produces most of it today, unlabelled. The work before December 2027 is deciding which category you are in, writing that down, and making the evidence you already have addressable, retained and reachable inside a clock you did not set.

§FAQ/Common questions

Frequently asked

When does the Cyber Resilience Act actually apply?

Article 71 phases it. Chapter IV, covering notified bodies and conformity assessment, has applied since 11 June 2026. Article 14, the obligation to report actively exploited vulnerabilities and severe incidents, applies from 11 September 2026. Everything else — Annex I's essential requirements, the Article 13 manufacturer obligations, technical documentation, conformity assessment and CE marking — applies from 11 December 2027. As of August 2026 only Chapter IV is in application, so no manufacturer is yet obliged to file a notification, and ENISA's Single Reporting Platform is still described in the future tense: the Commission's reporting page says it will be operational by 11 September 2026, with functional and security testing under way.

Does the CRA apply to software we only run internally?

Most likely not, but the reasoning matters more than the answer. The Regulation applies to products with digital elements made available on the market, and making available means supply in the course of a commercial activity, whether for payment or free of charge. An internal platform never supplied outside the organisation is not made available. Note the limit: the Regulation writes an explicit own-use carve-out only for public administration entities, in Recital 16. A private company's internal-only case has to be argued from Article 2(1) and Article 3(22) — a reading of the text, not a stated exemption. Record the determination, date it, and have counsel confirm it.

What is an open-source software steward, and how do its duties differ from a manufacturer's?

Article 3(14) defines a steward as a legal person, other than a manufacturer, whose purpose is to provide sustained systematic support for the development of specific free and open-source products intended for commercial activities, and which ensures their viability. The duties are much lighter. Article 24(1) requires a verifiably documented cybersecurity policy covering the documentation, handling and remediation of vulnerabilities; 24(2) requires cooperation with market surveillance authorities. Article 24(3) imports only Article 14(1) — the duty to notify actively exploited vulnerabilities — plus 14(3) and (8) for severe incidents affecting the steward's own development systems. It does not import Article 14(2)'s 24/72/14 schedule or 14(4)'s cascade, even though ENISA's platform FAQ presents the cadence with manufacturers and stewards in one frame. Article 64(10) also exempts stewards from administrative fines.

Which SBOM format does the Cyber Resilience Act require?

None specifically, today. Annex I Part II(1) asks for a software bill of materials in a commonly used and machine-readable format covering at the very least the top-level dependencies. Article 13(24) empowers the Commission to specify format and elements later by implementing act, so any choice made now is provisional. The practical answer: pick a generator that emits both CycloneDX and SPDX and converts between them, generate from the built artefact rather than the source tree, key the document to the image digest, and retain enough to re-emit rather than migrate once the format question is settled.

Is a VEX document enough to satisfy the CRA's disclosure requirement?

In our reading, no — not on its own. Annex I Part II(4) requires disclosure, once a security update is available, covering a description of the vulnerability, information letting users identify the affected product, the impacts, the severity, and clear and accessible remediation guidance. The CSAF v2.0 specification states that the main purpose of the VEX format is to say that and why a product is, or is not, affected — a narrower job. The CSAF Security Advisory profile, with /document/category set to csaf_security_advisory, is the one the specification describes as intended for vulnerabilities and their corresponding remediations. Both have a place: VEX suppresses noise from unreachable CVEs, the security advisory tells an operator what to install.

cyber resilience actcra compliance open source stewardcyber resilience act sbom requirementseu cra vulnerability disclosure obligationcra manufacturer obligations softwarecyber resilience act deadline 2027

Executive Briefing

Thirty minutes to clarify your infrastructure risk

Walk us through your vendor footprint and regulatory constraints. We will tell you honestly where sovereignty creates leverage — and where it does not. No pitch deck. No obligation.