Safeguard
Supply Chain Security•

End of Life Data Formats: OpenEoX and Common Lifecycle Enumeration

OpenEoX (OASIS) and CLE (ECMA-428) are machine-readable formats for end of support and end of life dates. Here is what each covers and how to use them.

Safeguard Security Team
52 min read

OpenEoX and Common Lifecycle Enumeration (CLE) are the two machine-readable formats for saying when a product or component stops getting fixes. OpenEoX is an OASIS effort whose Core Schema 1.0 reached Committee Specification Draft 01 on 13 July 2026; it records four milestones (general availability, end of sales, end of security support, end of life). CLE is Ecma standard ECMA-428, published on 10 December 2025, and records a component's lifecycle as an append-only list of events keyed to a Package URL.

Neither format replaces an SBOM or a VEX document. An SBOM says what is inside your software; VEX says whether a known vulnerability affects it. Lifecycle data answers a third question that both leave open: will anyone fix the next vulnerability in this component, and until when? Under the EU Cyber Resilience Act, under US federal rules for unsupported edge devices, and in ordinary procurement, that third question now has a date attached to it.

Key takeaways

  • SBOM and VEX are silent on support status. The 2026 Minimum Elements for an SBOM, published by CISA and partners on 29 July 2026, list component name, version, producer, identifiers, hashes, license and dependency relationships, but no support or end of life field. A component with no open CVEs and no maintainer looks identical to a healthy one.
  • OpenEoX is the vendor-side format. Its Core Schema is deliberately tiny: end_of_life, end_of_security_support and last_updated are required; general_availability and end_of_sales are optional; any date may be the literal string tba. Product identity is handled by a separate draft "Shell" that borrows CSAF's product identification helper (purl, CPE, hashes, serial numbers and more).
  • CLE is the event-stream format. An ECMA-428 document names a component by purl and lists events such as released, endOfDevelopment, endOfSupport, endOfLife and componentRenamed. Events are never edited; a mistake is corrected by publishing a withdrawn event and a new one.
  • The two formats overlap but are not rivals. OpenEoX answers "what are the dates for this product version" in one small object. CLE answers "what has happened to this component over time", including renames and supersession, with version ranges in the vers syntax.
  • The links to the rest of your stack are purl, CPE and CSAF. CSAF advisories already carry a no_fix_planned remediation category for end of life products. CycloneDX 1.7 has no native end of life field, so CLE documents travel alongside it, for example through the Transparency Exchange API. SPDX 3.0 has supportLevel and validUntilTime on every artifact.
  • Most real lifecycle data is still on web pages. Upstream projects publish schedules (Python's developer guide, Node.js's schedule.json), distributions publish tables, and community datasets such as endoflife.date normalise them into an API. Treat each as a source with an owner and a freshness date, not as ground truth.
  • Lifecycle data only matters if it changes a decision. For every component that is near or past end of security support, pick one of four actions: upgrade, extend (paid or community extended support, or a maintained fork), isolate, or retire. Write the choice down with a review date.

This post goes one level deeper than our earlier lifecycle posts. For the plain meaning of each date, see end of sale, end of support, end of life: what each date means. For why a clean scan of an end of life component is not good news, see end of life software and scan results: no advisory is not safe. For the advisory format that lifecycle data plugs into, see the CSAF 2.0 guide, and for the vulnerability side of the BOM family, see VDR and BOV explained.

Why SBOM and VEX do not say when fixes stop

An SBOM is an inventory taken at a moment in time. CISA's 2026 Minimum Elements for an SBOM, released with the NSA, the FBI and international partners and replacing the NTIA minimum elements from 2021, defines the baseline data fields: component name, version, producer, identifiers, hashes, license, dependency relationships, and metadata about the SBOM itself (author, signature, format, timestamp, generation context and tool). Every one of those fields describes what a component is. None describes what will happen to it. The guidance is explicit that its scope is the minimum, and that organisations can map SBOM data to "other sources, such as security advisories" to drive vulnerability management. Lifecycle data is one of those other sources.

VEX narrows the question further. A VEX statement says whether a product is affected by a specific, already known vulnerability. It is reactive by design: no CVE, no VEX statement. For a component whose maintainer has stopped working, that produces exactly the wrong signal. The next vulnerability will be found, but nobody will issue an advisory with a fixed version, and the VEX for your product will say "affected" with no remediation, or nothing at all. Our post on scan results for end of life software walks through why "no known vulnerabilities" is a weak statement about abandoned code.

So there are three different questions about any component:

QuestionArtifact that answers itChanges when
What is in this software?SBOM (CycloneDX, SPDX)You rebuild or change dependencies
Is this software affected by known vulnerability X?VEX, CSAF advisory, VDRA vulnerability is published or analysed
Will anyone fix the next vulnerability, and until when?Lifecycle data (OpenEoX, CLE, vendor and project schedules)The supplier announces or reaches a milestone

The third row is the one most programmes have handled with spreadsheets and calendar reminders. Two developments have made that harder to defend.

What the EU Cyber Resilience Act requires about support periods

The Cyber Resilience Act, Regulation (EU) 2024/2847, entered into force on 10 December 2024. According to the European Commission's CRA page, reporting obligations apply from 11 September 2026 and the main obligations apply from 11 December 2027. Several articles turn "support period" from a marketing phrase into a legal duty:

  • Article 13(8) requires manufacturers to determine a support period. The text says the support period "shall be at least five years", unless the product is expected to be in use for less than five years, in which case it matches the expected use time.
  • Article 13(9) requires each security update issued during the support period to remain available for at least 10 years after it was issued, or for the rest of the support period, whichever is longer.
  • Article 13(19) requires the end date of the support period, "including at least the month and the year", to be clearly specified at the time of purchase, and, where technically feasible, a notification to users when the product reaches the end of its support period.
  • Annex I, Part II, point 1 requires manufacturers to identify and document the components in the product, "including by drawing up a software bill of materials in a commonly used and machine-readable format covering at the very least the top-level dependencies".
  • Annex II lists the information that must accompany the product, including the end date of the support period. The Commission's summary of the legislative text puts it plainly: during the support period, the manufacturer ensures vulnerabilities, including those in its components, "are handled effectively".

Read together, those provisions create a chain. A manufacturer must publish its own end of support date. To honour it, the manufacturer must handle vulnerabilities in the components listed in its SBOM for that whole period. A component whose upstream support ends before the product's support period ends becomes the manufacturer's problem: it must upgrade, backport, replace or fork. That is only manageable if component lifecycle dates are machine readable and joined to the SBOM, which is precisely the gap OpenEoX and CLE target.

Why procurement teams care

Buyers feel the same pressure from the other side. On 5 February 2026 CISA issued Binding Operational Directive 26-02, Mitigating Risk From End-of-Support Edge Devices. It requires US federal civilian agencies to update supported edge devices running end of support software, inventory devices on a CISA list within three months, decommission listed devices whose end of support date falls within twelve months, decommission all identified end of support edge devices within eighteen months, and, within twenty-four months, run continuous discovery and keep an inventory of devices that are, or will within twelve months become, end of support. CISA says its initial list will include "the IT product name, version number, and end of support date", and that it will evaluate ways to allow automated, machine-readable submissions.

That is a lifecycle data problem stated as policy. A buyer who must decommission devices on or before their end of support date needs those dates per product and per version, in a form a tool can read, and needs to know when a vendor changes them. Procurement teams that used to ask "do you have an SBOM?" now also need to ask "until when will you fix what is in it?"

The vocabulary: four dates that people confuse

Before comparing formats, it helps to pin down the terms, because the formats do not use identical words for identical ideas. The OpenEoX definitions taxonomy gives the clearest vendor-side definitions:

  • End-of-Sales (EoS) is the last day a product may be ordered from the vendor's sales channels. Support may continue for existing customers.
  • End-of-Security-Support (EoSSec) is the last day the vendor has committed to providing security remediations.
  • End-of-Life (EoL) is the last day the product is officially supported in any way. After it, no development, updates or support should be expected.
  • General Availability (GA) is the first day the product is officially launched and available.

The awkward detail is that "EoS" is overloaded across the industry: some suppliers use it for end of sales and others for end of support. OpenEoX resolves that by reserving EoS for sales and giving security support its own abbreviation, EoSSec. CLE avoids abbreviations and uses event names: endOfMarketing, endOfDistribution, endOfDevelopment, endOfSupport and endOfLife.

IdeaOpenEoX Core fieldCLE 1.0 eventSPDX 3.0CSAF
First availablegeneral_availabilityreleased (per version)releaseTime on the artifactn/a
Stop selling or promotingend_of_salesendOfMarketing, endOfDistributionn/an/a
No new features, fixes continuen/aendOfDevelopmentn/an/a
Security fixes stopend_of_security_supportendOfSupport (security and bug fixes, for a named support policy)supportLevel set to endOfSupport plus validUntilTimeno_fix_planned per vulnerability
All work stopsend_of_lifeendOfLifesupportLevel set to noSupportno_fix_planned per vulnerability
Name changesn/a (identity is outside Core)componentRenamedn/an/a
Replaced by a newer versionn/asupersededByn/an/a

The mapping is approximate, and that is the first practical lesson: a converter between formats has to make choices. CLE's endOfSupport ends "Security Fixes and Bug Fixes" together for a named support policy, while OpenEoX's end_of_security_support is specifically about security remediations. SPDX's endOfSupport value means "there is a defined end of support", not that it has passed.

OpenEoX: what it is and who runs it

OpenEoX is an OASIS Open technical committee. Its charter states the purpose as standardising "a unified machine-readable approach to managing and sharing End-of-Life (EOL) and End-of-Support (EOS) information for commercial and open source software and hardware". The original call for participation was posted to the OASIS members list in September 2023. The charter names two deliverables: the OpenEoX Standard and an OpenEoX Implementation Guide. The audience listed in the charter includes software and hardware vendors, open source maintainers, government organisations and regulators.

The committee is co-chaired by a CISA representative and an industry representative, and the Core Schema editors include a representative of Germany's BSI, which helps explain why OpenEoX borrows CSAF's conventions for identifiers and dates.

Where OpenEoX stands as of October 2026

DateMilestoneSource
September 2023OASIS call for participation for the OpenEoX TCOpenEoX charter page
24 April 2025"OpenEoX: A Standardized Framework for Managing End of Life and other Product Lifecycle Information" technical reportdocs.oasis-open.org/openeox/standardization-framework
13 July 2026OpenEoX Core Schema Version 1.0, Committee Specification Draft 01, with JSON schemaseox-core v1.0 CSD01
In progressOpenEoX Shell (product binding) and OpenEoX API drafts in the TC repositorygithub.com/oasis-tcs/openeox

A Committee Specification Draft is an early OASIS stage. It is published for review and can change before it becomes a Committee Specification and, later, an OASIS Standard. The TC's overview page on oasis-open.org still says it "has not yet produced any technical work", so go to docs.oasis-open.org for the CSD01 files rather than relying on that page. Build tooling against it now if you want, but pin the schema version and expect changes.

The Core Schema, field by field

The scope section of the CSD describes the Core Schema as "a minimal, machine-readable JSON format" for four lifecycle milestones, designed "to be imported by or integrated into other standards". It is a JSON Schema 2020-12 object with six properties and no others allowed:

PropertyRequiredTypeMeaning
$schemaYesconstant URIhttps://docs.oasis-open.org/openeox/eox-core/v1.0/schema/core.json
end_of_lifeYeseox_timestamp_tLast day the product is officially supported in any way
end_of_security_supportYeseox_timestamp_tLast day the vendor has committed to security remediations
last_updatedYesdate-timeWhen this record last changed
general_availabilityNoeox_timestamp_tFirst day the product is officially available
end_of_salesNoeox_timestamp_tLast day the product can be ordered from the vendor

The eox_timestamp_t type is the interesting part. It is either an RFC 3339 date-time string or the constant tba. The specification says a consumer "MUST treat tba as a date greater than the maximum date" and must interpret it as "not yet announced". That one rule removes a common source of bugs, where a missing end of life date is read as "already ended" by one tool and "never ends" by another. In OpenEoX, "not announced" is explicit and sorts last.

The date rules are strict and worth knowing before you generate records. The T separator and Z suffix must be upper case, an empty time zone is not allowed, fractional seconds use a full stop, and leap seconds "MUST NOT be used" because, as the draft explains, most libraries cannot handle them. Notice that OpenEoX stores a timestamp, not a calendar date. "End of life on 1 October 2026" has to become a specific instant, and the TC's own examples include one dedicated to time zones. Pick a convention (for example, 23:59:59 UTC on the stated day, or the start of the next day) and apply it consistently.

The CSD also defines special cases that encode facts no simple date pair can:

  • If general_availability equals end_of_security_support, the product "is not supported" for security, though it may not yet be at end of life.
  • If general_availability equals end_of_life, the product "was published but is not maintained at all". The draft gives the example of source code released as open source with no intent to maintain it, and notes that saying so clearly lets others take over development and assess the risk.
  • If a product is cancelled before general availability, the record keeps only the end of life entry.

The TC's examples folder shows the shapes. The minimal record is four lines:

{
  "$schema": "https://docs.oasis-open.org/openeox/eox-core/v1.0/schema/core.json",
  "end_of_life": "2025-12-31T12:00:00Z",
  "end_of_security_support": "2025-11-19T16:00:00Z",
  "last_updated": "2025-11-19T16:00:00Z"
}

And a record where security support has no announced end uses tba:

{
  "$schema": "https://docs.oasis-open.org/openeox/eox-core/v1.0/schema/core.json",
  "end_of_life": "2025-12-31T12:00:00Z",
  "end_of_security_support": "tba",
  "last_updated": "2025-11-19T16:00:00Z"
}

What the Core Schema leaves out on purpose

You will notice that the Core record does not say which product it describes. That is intentional. The scope section says product identification "is addressed by complementary specifications such as OpenEoX Shell and is therefore out of scope". In the TC repository, the draft Shell schema wraps a list of statements, each with three required parts: a core object, a product object (hardware, software, or hardware with software, each with vendor name, product name and version), and a product_identification_helper that references CSAF 2.1's definition. A second draft, shell_csaf.json, lets statements point at a reduced CSAF product tree with branches, product groups and relationships, so a vendor that already publishes CSAF advisories can reuse the same product IDs for lifecycle statements.

Those Shell schemas still carry placeholder URIs containing tbd in the repository, so treat them as a direction of travel, not a published format. The practical upshot is that today you can produce standards-shaped OpenEoX Core objects, but the binding of those objects to products is either your own wrapper or the draft Shell.

Common Lifecycle Enumeration: ECMA-428

Common Lifecycle Enumeration comes from the other big standards stream in the BOM family. Ecma International's TC54 is the committee that standardises CycloneDX (ECMA-424) and Package URL (ECMA-427). Its programme of work covers CycloneDX, the Transparency Exchange API, BOM merging algorithms and "further direction of standards in the software transparency space". CLE was developed in TC54's Task Group 3 with the OWASP community.

Status, number and date

ItemValueSource
Standard numberECMA-428Ecma: ECMA-428
Edition1st edition, December 2025Ecma standard page and PDF
Specification versionCLE 1.0.0ECMA-428 clause 1
Publication date10 December 2025tc54.org CLE page
Adopted byEcma General Assembly, December 2025ECMA-428 foreword
Developed inTC54, Task Group 3 (TC54-TG3), with the OWASP communityECMA-428 introduction
JSON Schemahttps://tc54.org/schemas/cle/cle-1.0.0.schema.jsontc54.org
Sibling standardsECMA-424 CycloneDX (2nd edition, December 2025, CycloneDX 1.7), ECMA-427 PURL (1st edition, December 2025)ECMA-424, ECMA-427

Unlike OpenEoX Core, CLE is a finished first edition of a published standard. The scope clause is short: CLE "provides a standardized format for communicating software component lifecycle events in a machine-readable format", and the standard defines the JSON Schema and the requirements for CLE documents. A conforming implementation "must provide and consume objects that conform to the JSON Schema".

One editorial wrinkle is worth knowing. The PDF's schema clause shows a placeholder meta-schema location on an example domain, and the informative example in Annex B uses https://TODO/cle.v1.0.0.json as its $schema. The actual schema is published at the tc54.org address in the table above, and that is what you should put in documents and point validators at.

How a CLE document is built

A CLE document describes one component. Its required top-level fields are:

FieldTypeMeaning
$schemastringThe CLE schema URI, which also signals the CLE version
identifierstring or array of stringsThe component's Package URL; an array lists aliases that "identify the exact same bits" distributed differently
updatedAtstringISO 8601 timestamp of the last update
eventsarrayEvent objects, ordered newest first by ID

Optional fields are definitions (reusable support policies), plus index and next for pagination. Every event has four common fields: an integer id, a type, an effective timestamp (when the event takes effect) and a published timestamp (when it was first announced), both in UTC. The split between effective and published matters: an end of support announced in January for December is one event with two different dates, and a consumer can tell how much notice it was given.

Support policies live in definitions.support. Each has an id, a human-readable description and an optional url. The standard says support policies are immutable: "the semantics and meaning of a support policy must not change over time for a given support policy ID". That lets a supplier define, say, a standard policy and an extended policy once, and then end each one separately for a version range.

The nine event types

ECMA-428 defines nine event types in three categories:

EventCategoryRequired extra fieldsWhat it says
releasedVersionversion (optional license)A version was released and is available
endOfDevelopmentVersionversions, supportIdNo more substantial modifications; security and bug fixes continue until endOfSupport
endOfSupportVersionversions, supportIdSecurity fixes and bug fixes stop for that support policy
endOfLifeVersionversionsAll work stops, including distribution and documentation; the component is retired
endOfDistributionVersionversionsThe supplier stops distributing those versions (only where it controls distribution)
endOfMarketingVersionversionsThe supplier stops promoting those versions; support may continue
supersededByVersionsupersededByVersion (optional versions)A version is replaced by another, for components where progression is not implicit
componentRenamedComponentidentifiers (optional description, references)The component has new identifiers, for example a new purl
withdrawnMetaeventId (optional reason, references)A previously published event should be ignored

The standard grounds these in six "types of work": marketing, substantial modifications, bug fixes, security fixes, distribution and documentation. Each event stops one or more of them. That is a cleaner model than a single "end of life" date, because real projects wind down in stages.

Version ranges with vers

Version events do not name single versions; they carry an array of objects with a range property in the Version Range Specifier syntax, which ECMA-428 inlines as normative Annex A "pending standardization". A range starts with vers:, then a versioning scheme, then a pipe-separated list of constraints. The scheme normally matches the purl type, so npm packages use vers:npm/... and Python packages use vers:pypi/... with PEP 440 rules. The annex also lists generic schemes for special cases, including intdot for plain dotted integers, none and all. The Annex B example ends support for every 1.x release of an npm package with vers:npm/>=1.0.0|<2.0.0.

Annex A explains why it does not reuse ecosystem-specific range notations: a lifecycle format has to work across all ecosystems.

The prepend-only event model

CLE's processing rules are its most distinctive design choice:

  1. Immutability. Once published, an event cannot be modified. Corrections are new events.
  2. Ordering. Events are stored newest first, by ID.
  3. ID assignment. IDs are auto-incrementing integers in the order events are added, not by effective date.
  4. Processing order. Consumers process events oldest to newest by ID to build current state.
  5. Withdrawal. A withdrawn event makes consumers ignore the referenced event "as if it never existed", while the withdrawn event itself remains for audit, and anything derived from it should be recalculated.

The Annex B example shows the pattern. Event 2 announced an end of support date; event 4 announced a different one; event 5 withdrew event 2 with the reason "The endOfSupport date was incorrect." A consumer that processes all five ends up with the corrected date and an audit trail of the change. For anyone who has had a supplier quietly edit a lifecycle web page, that history is the main attraction.

Pagination handles long histories. A single CLE page "must not exceed 100,000 events"; pages link with next, an optional index file lists pages with their first and last event IDs, and event IDs stay globally unique across pages so a withdrawal can reference an event on any page.

What CLE 1.0 leaves for later

Clause 11 lists the use cases version 1.0.0 supports: general availability, end of support and end of life, and component renaming. It also lists what is deferred to future versions: complex license changes, bundling and unbundling, acquisitions, third-party extended support, third-party claims, forks, export restrictions, and security status changes such as a component being marked compromised. Two of those gaps matter for security teams today. First, CLE 1.0 is a first-party format: there is no way yet for someone other than the supplier to assert lifecycle events. Second, extended support from a third party, which is how many organisations survive a missed upgrade, cannot be expressed yet.

How the two formats got here: a dated timeline

DateEventWhy it matters for lifecycle data
18 November 2022CSAF 2.0 approved as an OASIS StandardAdds the no_fix_planned remediation category, "often the case when a product has been orphaned, declared end-of-life"
September 2023OASIS call for participation for the OpenEoX TCVendor-side lifecycle standardisation starts formally
June 2024ECMA-424 1st edition (CycloneDX)TC54 begins standardising the BOM family at Ecma
10 December 2024EU Cyber Resilience Act enters into forceSupport periods become a legal duty for manufacturers
24 April 2025OpenEoX standardization framework technical reportCore concepts and taxonomy published
10 December 2025ECMA-428 CLE 1.0.0 published, alongside ECMA-427 PURL and ECMA-424 2nd edition (CycloneDX 1.7)Lifecycle events get a standard keyed to purl
5 February 2026CISA BOD 26-02 on end of support edge devicesUS federal agencies must inventory and retire end of support devices on deadlines
13 July 2026OpenEoX Core Schema 1.0 CSD01First public OASIS draft of the OpenEoX JSON schema
29 July 2026CISA and partners publish 2026 Minimum Elements for an SBOMBaseline SBOM fields still contain no lifecycle field
11 September 2026CRA reporting obligations applyManufacturers must report actively exploited vulnerabilities and severe incidents
21 October 2026CSAF 2.1 Committee Specification Draft 04Adds a fix_planned category next to no_fix_planned
11 December 2027CRA main obligations applyPublished support end dates and component vulnerability handling become enforceable

How lifecycle formats link to identity, advisories and SBOMs

Lifecycle data is only useful if you can join it to what you actually run. Four links do that work.

Package URL and CPE: the join keys

Package URL is now an Ecma standard itself. ECMA-427 describes a purl as "a valid URL and URI composed of seven components" and lists its uses in SBOMs, vulnerability databases, advisories and exploitability reports. CLE makes purl mandatory: the identifier field is "in the PURL format", and ECMA-427 is CLE's first normative reference. Because CLE events carry version ranges rather than a version in the purl, a CLE document is normally keyed to a versionless purl such as pkg:npm/example-component, and you match your SBOM's versioned purl by stripping the version and testing it against each event's vers range.

OpenEoX takes the CSAF route. The draft Shell's product_identification_helper comes from CSAF, where, in CSAF 2.0, at least one of eight properties is required: cpe, hashes, model_numbers, purl, sbom_urls, serial_numbers, skus and x_generic_uris. That breadth is what hardware needs: a router's lifecycle is keyed to a model number or SKU, not to a package. It also means OpenEoX can carry a purl for a software component, a CPE for a commercial product, and a serial number range for a device, in the same structure.

In practice you will need both keys. Open source components in your SBOM have purls. Commercial products, appliances and operating systems in your asset inventory are more often identified by CPE or by vendor, product and version strings.

CSAF: lifecycle facts inside advisories

CSAF already expresses one lifecycle fact, per vulnerability. In CSAF 2.0 the remediation category no_fix_planned "indicates that there is no fix for the vulnerability and it is not planned to provide one at any time", and the standard says this "is often the case when a product has been orphaned, declared end-of-life, or otherwise deprecated". The draft CSAF 2.1 (Committee Specification Draft 04, 21 October 2026) adds fix_planned for a fix that exists in plan but is not ready, and its examples include remediation details such as "These products are end-of-life. Therefore, no fix will be provided."

The difference from OpenEoX and CLE is timing. A CSAF no_fix_planned remediation tells you, after a vulnerability is published, that this product will not be fixed. A lifecycle record tells you before any vulnerability exists that nothing will be fixed after a date. You want both: the lifecycle record to plan, the advisory to confirm. The OpenEoX Shell's CSAF variant is designed so the same product IDs appear in both.

CycloneDX: no native field, so CLE travels alongside

CycloneDX 1.7, the version standardised as ECMA-424 2nd edition, has a metadata.lifecycles array, but the CycloneDX 1.7 JSON reference defines it as the stage "in which data in the BOM was captured" (design, pre-build, build, post-build and so on), not a component's support status. The component object has no end of support or end of life field, and the external reference type list has no lifecycle-specific type. The available hooks are externalReferences (with a type such as support, release-notes or other) and free-form properties, which the specification describes as a way to include "data not officially supported in the standard".

TC54's answer is to deliver CLE through the Transparency Exchange API (TEA), which is in beta 2 and being standardised in TC54 Task Group 1. The TEA documentation says product lifecycle events "are communicated through the ECMA-428 Common Lifecycle Enumeration standard", including rebranding, repackaging, mergers and acquisitions, end of life and end of support. TEA's CLE endpoints return a projection of CLE content, not a full CLE 1.0.0 document; publishers that need the exact document publish it as a TEA artifact of type OTHER "until a dedicated type exists". CLE can be attached at four levels: product, component, product release and component release. TEA also describes CLE and VEX as "dynamic artifact types", which is the right mental model: an SBOM for a release is fixed, while its lifecycle and vulnerability status keep changing.

SPDX 3.0: support level on every artifact

SPDX 3.0 took a different approach and built a small lifecycle vocabulary into its core model. Every Artifact can carry supportLevel and validUntilTime. The SupportType vocabulary in SPDX 3.0.1 has seven values: deployed, development, endOfSupport, limitedSupport, noAssertion (the default), noSupport and support. Its definition of endOfSupport is "there is a defined end of support for the artifact from the supplier", which "may also be referred to as end of life", with the date carried in a separate property. One small inconsistency: the vocabulary text calls that property validUntilDate, while the property itself is named validUntilTime and is defined as "until when the artifact can be used before its usage needs to be reassessed". Use validUntilTime in documents.

SPDX's model is simpler than either OpenEoX or CLE: one support level and one date per artifact, with no separation of security support from general support and no event history. It is a reasonable summary to embed in an SBOM, provided you remember that an SBOM is a snapshot and the date inside it can go stale.

Where lifecycle data comes from today, and how reliable it is

Very few suppliers publish OpenEoX or CLE documents yet. The lifecycle data most teams rely on in October 2026 comes from four kinds of source.

Upstream project schedules

Many open source projects publish their own schedules, and they are the authority for their own dates. Two examples:

  • Python. The Python developer guide's versions page lists every branch with its first release, end of life and status. As of this writing it shows Python 3.10 as end of life on 2026-10-01, 3.11 to 3.13 in security-only status with end of life in October 2027, 2028 and 2029, and 3.14 and 3.15 in bugfix status. The guide notes that "Dates shown in italic are scheduled and can be adjusted", so a future date is a plan, not a promise. Each branch's release schedule PEP adds detail: PEP 619 records that 3.10.11 on 2023-04-05 was the final regular bugfix release with binary installers, that source-only security releases followed "on an 'as-needed' basis until October 2026", and that 3.10.22 shipped on 2026-10-01.
  • Node.js. The Node.js release working group publishes a machine-readable schedule.json with start, lts, maintenance and end dates for every major line. It shows Node.js 20 ending on 2026-04-30, Node.js 22 on 2027-04-30 and Node.js 24 on 2028-04-30.

Project schedules are accurate but heterogeneous. Python has five phases (feature, prerelease, bugfix, security, end of life); Node.js has current, active LTS and maintenance; other projects support only the latest release. Mapping them onto OpenEoX's two required dates or CLE's events is a modelling decision you make once per project and then keep consistent.

Distribution tables

Linux distributions and other platform suppliers publish their own lifecycle tables, and they frequently differ from upstream. A distribution can keep shipping security fixes for a language runtime long after upstream's end of life by backporting patches, or drop a package earlier than upstream. If your container base image is a distribution, the distribution's date is the one that governs the packages it ships, not the upstream project's date. We covered the mechanics in detail for Debian and for Linux kernel longterm branches on an embedded fleet.

Community datasets

endoflife.date is a community-maintained dataset that normalises hundreds of products' release cycles into one schema and exposes it through a versioned API. The v1 product endpoint returns, for each release cycle, fields including releaseDate, isLts, isEoas and eoasFrom (end of active support), isEol and eolFrom, isMaintained and the latest patch version. For Python, the response we fetched on 23 October 2026 lists 3.10 with eolFrom 2026-10-01 and latest version 3.10.22, matching the developer guide. The dataset also maps products to identifiers: the /api/v1/identifiers/purl/ endpoint returned 977 purl identifiers, and the Python product alone lists purls for the GitHub repository, Debian, Ubuntu, Fedora and container image packages, plus CPEs.

Community datasets are the fastest way to get broad coverage, and the identifier mapping is exactly what an SBOM join needs. Their limits are structural: they are maintained by volunteers from public pages, they can lag a supplier's change, they cover popular products rather than the long tail of libraries in a typical dependency tree, and they record what the supplier published rather than what the supplier contracted with you.

Vendor lifecycle pages

Commercial suppliers publish lifecycle tables on their support sites as HTML, PDF or spreadsheets. They are authoritative for the supplier's own products and the hardest source to automate: layouts change, terms differ, and dates are sometimes edited without notice. This is the problem OpenEoX was created to solve.

How reliable is any of this?

Three rules make lifecycle data trustworthy enough to act on:

  1. Prefer the party that does the fixing. For an upstream library, that is the project. For a distribution package, that is the distribution. For a commercial product, that is the supplier, and the contract can override the public page.
  2. Record where each date came from and when you fetched it. OpenEoX's required last_updated and CLE's updatedAt and per-event published timestamps exist for this reason. A date without provenance cannot be audited.
  3. Treat "scheduled" and "announced" differently from "happened". Python's italic dates, OpenEoX's tba, and CLE's separation of published from effective all encode the same idea. Plan against announced dates, but confirm on the day.

Comparison: lifecycle sources side by side

SourceOwnerCoverageIdentity keyMachine readableHistory of changesMaturity (October 2026)
OpenEoX Core 1.0OASIS OpenEoX TCAny software or hardware product whose supplier publishes itOutside Core; draft Shell uses CSAF identification helper (purl, CPE, SKU, serial, model)Yes, JSON SchemaOnly last_updatedCommittee Specification Draft 01 (13 July 2026); Shell and API in draft
CLE 1.0.0 (ECMA-428)Ecma TC54Any component whose supplier publishes itpurl (mandatory), with aliasesYes, JSON SchemaFull, append-only event log with withdrawalsPublished Ecma standard, 1st edition (December 2025)
CSAF remediation categoriesOASIS CSAF TCProducts named in advisoriesCSAF product tree and identification helperYesPer advisory revision historyCSAF 2.0 OASIS Standard; 2.1 in draft
SPDX 3.0 supportLevelSPDX projectArtifacts inside an SPDX documentSPDX element IDs, purl and other identifiersYesNone; snapshot in the SBOMPart of SPDX 3.0.1
Upstream project schedulesEach projectThat project's own releasesProject and branch namesVaries: JSON for some, HTML tables for othersVaries; usually version control historyMature, but every project differs
Community datasets (endoflife.date)Volunteer communityHundreds of popular productsProduct slug, mapped to purls and CPEsYes, versioned APIRepository historyWidely used; not authoritative
Vendor lifecycle pagesEach supplierThat supplier's productsVendor naming, sometimes SKUsRarelyRarely visibleAuthoritative but hard to automate

In short: use the formats where suppliers publish them, fill open source gaps from upstream schedules and community datasets, and keep vendor pages and contracts as the authority for commercial products, all stored in one internal shape.

Walkthrough: build a lifecycle record for one component and attach it to an SBOM

This walkthrough uses CPython 3.10, which reached end of life on 1 October 2026, as the component. It is a real, recent case, it has a clear primary source, and Python runtimes appear in a great many container images. The commands use curl, jq and Python's check-jsonschema validator. Nothing here changes a system; every step writes files in a working directory.

Step 1: identify the component and its purl

Start from your SBOM, not from the lifecycle source. If you build container images, the runtime will usually appear as a distribution package or as the container image itself. List the purls that mention Python:

jq -r '.components[] | select(.name | test("python"; "i")) | .purl' app-image.cdx.json

For this example we model upstream CPython itself, keyed by its source repository purl pkg:github/python/cpython, which is also one of the identifiers endoflife.date maps to Python. If your SBOM shows pkg:deb/debian/python3.11@... instead, the governing lifecycle is the distribution's, not upstream's, and you should model that product instead.

Step 2: collect dates from the primary source, then cross-check

Read the authority first. The Python developer guide and PEP 619 give: first release 2021-10-04, final regular bugfix release 3.10.11 on 2023-04-05, end of life 2026-10-01, last release 3.10.22 on 2026-10-01. Then cross-check against the community dataset:

curl -s https://endoflife.date/api/v1/products/python/ \
  | jq '.result.releases[] | select(.name=="3.10")
        | {name, releaseDate, eoasFrom, eolFrom, isMaintained, latest: .latest.name}'

If the two disagree, the primary source wins and you note the discrepancy. Record the fetch time; you will need it for last_updated and updatedAt.

Step 3: write the OpenEoX Core record

Choose a timestamp convention for calendar dates. Here we use the end of the stated day in UTC. Python's security support and all support end on the same day, so the two required fields are equal:

{
  "$schema": "https://docs.oasis-open.org/openeox/eox-core/v1.0/schema/core.json",
  "general_availability": "2021-10-04T00:00:00Z",
  "end_of_security_support": "2026-10-01T23:59:59Z",
  "end_of_life": "2026-10-01T23:59:59Z",
  "last_updated": "2026-10-23T09:00:00Z"
}

Save it as cpython-3.10.eox.json. There is no end_of_sales, because nothing is sold; the field is optional, so leave it out rather than inventing a value. Because the Core record has no product field, keep the binding in your own wrapper or file name until the Shell format is published.

Step 4: validate it against the published schema

python3 -m pip install --user check-jsonschema
check-jsonschema \
  --schemafile https://docs.oasis-open.org/openeox/eox-core/v1.0/csd01/schema/core.json \
  cpython-3.10.eox.json

The Core schema forbids extra properties, so a typo such as end_of_support fails validation, which is what you want. Keep format checking switched on: the timestamp type is a oneOf between a date-time string and the constant tba, and in our test a validator that ignores formats rejected the TC's own tba example because tba then matches both branches. check-jsonschema checks formats by default; with its formats disabled, the same file fails. The schema itself declares an OASIS meta-schema; if your validator cannot resolve it, download core.json and meta.json from the CSD01 directory and validate locally.

Step 5: write the CLE document

CLE expresses the same facts as events and can say more. Python's model has two phases worth separating: bug fixes and security fixes ended at different times. CLE's support policies let you model that directly: define one policy for regular bugfix support and one for security support, then end each with its own endOfSupport event. The intdot scheme from ECMA-428 Annex A suits CPython's dotted integer versions.

{
  "$schema": "https://tc54.org/schemas/cle/cle-1.0.0.schema.json",
  "identifier": "pkg:github/python/cpython",
  "updatedAt": "2026-10-23T09:00:00Z",
  "definitions": {
    "support": [
      {
        "id": "bugfix",
        "description": "Regular bugfix releases with binary installers",
        "url": "https://peps.python.org/pep-0619/"
      },
      {
        "id": "security",
        "description": "Source-only security fix releases",
        "url": "https://devguide.python.org/versions/"
      }
    ]
  },
  "events": [
    {
      "id": 4,
      "type": "endOfLife",
      "effective": "2026-10-01T23:59:59Z",
      "published": "2026-10-23T09:00:00Z",
      "versions": [ { "range": "vers:intdot/>=3.10.0|<3.11.0" } ]
    },
    {
      "id": 3,
      "type": "endOfSupport",
      "effective": "2026-10-01T23:59:59Z",
      "published": "2026-10-23T09:00:00Z",
      "versions": [ { "range": "vers:intdot/>=3.10.0|<3.11.0" } ],
      "supportId": "security"
    },
    {
      "id": 2,
      "type": "endOfSupport",
      "effective": "2023-04-05T23:59:59Z",
      "published": "2026-10-23T09:00:00Z",
      "versions": [ { "range": "vers:intdot/>=3.10.0|<3.11.0" } ],
      "supportId": "bugfix"
    },
    {
      "id": 1,
      "type": "released",
      "effective": "2021-10-04T00:00:00Z",
      "published": "2026-10-23T09:00:00Z",
      "version": "3.10.0"
    }
  ]
}

Two honest caveats. First, ECMA-428 says endOfSupport means bug fixes and security fixes stop for the referenced policy; ending the bugfix policy in 2023 is a fair reading of that, but it is a modelling choice, and a supplier writing its own document might choose differently. Second, this is a third-party record: you are describing CPython, not the CPython project. CLE 1.0 lists third-party claims as a future use case, so mark such files clearly as your own and set published to the time you wrote them, as above. Validate it the same way:

check-jsonschema \
  --schemafile https://tc54.org/schemas/cle/cle-1.0.0.schema.json \
  cpython.cle.json

If you later learn a date was wrong, do not edit event 3. Append event 5 of type withdrawn with eventId 3 and a reason, then append event 6 with the corrected date. Your history now shows what you believed and when.

Step 6: attach the record to a CycloneDX SBOM

CycloneDX 1.7 has no lifecycle field, so attach the CLE document as an external reference and, if you want a quick-look value for dashboards, add a namespaced property. Use your own namespace prefix for the property name, since it is not part of the standard:

jq '(.components[] | select(.purl? // "" | startswith("pkg:github/python/cpython")))
     |= (.externalReferences += [{
           "type": "other",
           "url": "https://example.internal/lifecycle/cpython.cle.json",
           "comment": "Lifecycle events, CLE 1.0.0 (ECMA-428)"
         }]
         | .properties += [{
           "name": "example:lifecycle:end_of_security_support",
           "value": "2026-10-01"
         }])' app-image.cdx.json > app-image.with-lifecycle.cdx.json

Keep the CLE file at a stable URL that you control, because the SBOM is a snapshot and the lifecycle document will keep changing. The property is a convenience copy, so record its source in the CLE document and regenerate it whenever you rebuild the SBOM. If you publish to customers through the Transparency Exchange API, publish the CLE document as a TEA artifact instead.

Step 7: or record it in SPDX 3.0

In an SPDX 3.0 document, set the two core properties on the package element:

{
  "type": "software_Package",
  "spdxId": "https://example.internal/spdx/cpython-3.10",
  "name": "cpython",
  "software_packageVersion": "3.10.22",
  "supportLevel": "endOfSupport",
  "validUntilTime": "2026-10-01T23:59:59Z"
}

After the date has passed, a strict reading of the SPDX vocabulary would move the value to noSupport. Whichever you choose, document the convention so that consumers of your SBOM interpret it the same way.

Step 8: check a whole SBOM against lifecycle data

One record is a learning exercise. The useful version runs over every component. A minimal approach with the community dataset's purl mapping:

# 1. purls in the SBOM, without version qualifiers
jq -r '.components[].purl // empty | sub("@.*$"; "")' app-image.cdx.json | sort -u > sbom-purls.txt

# 2. purl to product mapping from the community dataset
curl -s https://endoflife.date/api/v1/identifiers/purl/ \
  | jq -r '.result[] | "\(.identifier)\t\(.product.name)"' > eol-purls.tsv

# 3. components with a known lifecycle product
awk -F'\t' 'NR==FNR {p[$1]=$2; next} ($0 in p) {print $0 "\t" p[$0]}' eol-purls.tsv sbom-purls.txt

For each match, fetch the product's release cycles and decide which cycle your version belongs to. That last step needs the ecosystem's version rules (which is what vers is for), and it is where most homegrown scripts go wrong, so test it on versions you can check by hand. Components with no match are not "fine"; they are unknown, and they need a primary source or a decision.

How a team should act on lifecycle data

A lifecycle date only earns its keep when it triggers a decision. For every component within, say, twelve months of end of security support, or already past it, choose one of four actions and record the choice, the owner and a review date.

SituationActionWhat it involvesWhen it fits
A supported newer version exists and the upgrade is tractableUpgradeMove to a supported major line; rebuild and redeploy everything that embeds the old oneDefault choice for open source libraries and runtimes
The upgrade is large and the date is closeExtendBuy extended support, use a distribution that backports fixes, or adopt a maintained fork; record whose dates now applyRuntimes and platforms with paid or distribution support; time-boxed only
You cannot upgrade or extend yetIsolateReduce exposure: remove network reachability, restrict inputs, put the component behind a gateway, monitor itAppliances, embedded devices, legacy systems awaiting replacement
The function is no longer needed, or nothing else worksRetireRemove the component or system; for devices, decommission on or before the end of support dateAbandoned dependencies, unused features, BOD 26-02 style edge devices

A few practical points make the table work:

  • Extension changes whose dates apply. If you move from upstream Python to a distribution package with its own support policy, your lifecycle record should switch to the distribution's dates. Otherwise your dashboard keeps flagging a component that is in fact covered.
  • Isolation is a compensating control, not a fix. It belongs in your risk register with an end date. The CRA's model, where a manufacturer handles vulnerabilities in components for the whole support period, assumes you will eventually get back to a supported component.
  • Retirement needs proof. For a device, that is a decommission record. For a dependency, it is a rebuilt artifact whose SBOM no longer lists the component.

Where Safeguard fits, honestly

Safeguard's part in this is the inventory and the fix, not the lifecycle data itself. This post does not claim that Safeguard reads OpenEoX or CLE documents. What Safeguard does is build and import the SBOMs that lifecycle data has to be joined to: it scans repositories, container images and SBOM files (safeguard scan --dir ., --image <name>, --sbom <file>), shows which projects contain a given component and version, accepts CSAF and VEX uploads, and evaluates policies and gates in the platform. When you decide to upgrade, its autonomous remediation can open fix pull requests (switched off by default), and the Safeguard CLI's assistant can make the change with your approval. Lifecycle dates for commercial appliances, operating system runtimes you do not build and hardware still have to come from their suppliers.

Common mistakes

  1. Treating "no known vulnerabilities" as "supported". An end of life component accumulates unfixed vulnerabilities silently. Absence of advisories is weak evidence when nobody is looking. Check support status separately from vulnerability status.
  2. Using the upstream date for a distribution package. Distributions backport fixes and set their own dates. The package in your container is governed by the distribution's lifecycle, not upstream's.
  3. Reading "EoS" without checking which EoS. End of sales and end of support are different events. OpenEoX's EoS means sales; security support is EoSSec. Normalise terms when you ingest data.
  4. Collapsing every milestone into one "EOL" date. Bug fixes, security fixes and all support often end at different times. Python 3.10 stopped regular bugfix releases in April 2023 and security releases in October 2026. One date hides three years of difference.
  5. Treating a missing date as a past date, or as never. OpenEoX's tba exists so that "not announced" is explicit and sorts last. Map missing data to tba or "unknown", not to an arbitrary default.
  6. Editing lifecycle records in place. If a date was wrong, keep the history. CLE's withdrawn event is the model; do the same in internal records.
  7. Embedding lifecycle dates only inside the SBOM. The SBOM is a snapshot of a build; lifecycle status changes after the build. Keep the authoritative record outside and reference it.
  8. Using calendar dates where the format wants timestamps. OpenEoX requires RFC 3339 date-time with upper case T and Z. Decide how a day maps to an instant and apply it everywhere.
  9. Writing third-party records as if you were the supplier. CLE 1.0 is a first-party format. If you model someone else's component, label the file as yours and keep the source URL.

FAQ

What is OpenEoX?

OpenEoX is an OASIS technical committee and its specification for machine-readable end of life and end of support information for software and hardware. Its Core Schema 1.0 reached Committee Specification Draft 01 on 13 July 2026. The Core record holds general availability, end of sales, end of security support, end of life and a last updated timestamp; product identification is handled by a separate draft Shell format.

What is Common Lifecycle Enumeration (CLE)?

CLE is Ecma International standard ECMA-428, first edition, published 10 December 2025 by TC54. It defines a JSON format for a component's lifecycle events, keyed to a Package URL, with nine event types including released, endOfSupport, endOfLife, componentRenamed and withdrawn.

Is ECMA-428 the same as CycloneDX?

No. CycloneDX is ECMA-424 and Package URL is ECMA-427. All three come from the same Ecma committee, TC54. CLE is a separate document type that complements an SBOM; CycloneDX 1.7 itself has no end of life field.

What is the difference between OpenEoX and CLE?

OpenEoX Core is a small object of milestone dates for one product version, designed to be embedded in other formats and to borrow CSAF's product identification. CLE is an append-only history of events for one component, using purl and vers version ranges, with support for renames, supersession and corrections. OpenEoX is still a draft; CLE 1.0 is a published standard.

Does an SBOM include end of life dates?

Not by default. The 2026 Minimum Elements for an SBOM include no lifecycle field. SPDX 3.0 can record supportLevel and validUntilTime on an artifact, and CycloneDX can reference an external lifecycle document, but both are optional and both go stale once the SBOM is published.

Does the EU Cyber Resilience Act require an end of support date?

Yes, for manufacturers of products with digital elements. Article 13 requires a support period of at least five years unless the product is expected to be in use for less, and requires the end date, with at least month and year, to be clearly specified at the time of purchase. The main obligations apply from 11 December 2027.

How do I check if a dependency is end of life?

Find its purl in your SBOM, look up the project's own release schedule or the distribution's table, and cross-check with a community dataset such as endoflife.date, which exposes a purl to product mapping through its API. Then decide which release cycle your version belongs to and compare today's date with that cycle's end of security support.

What does no_fix_planned mean in a CSAF advisory?

It means the supplier will not fix that vulnerability for that product at any time. CSAF 2.0 notes this is often because the product is orphaned, end of life or deprecated. It is a per-vulnerability statement after the fact; lifecycle formats state the same thing in advance for all future vulnerabilities.

What should I do with a component that is past end of life?

Pick one of four actions and record it: upgrade to a supported version, extend support through a paid offering, a distribution or a maintained fork, isolate it to reduce exposure, or retire it. Give each decision an owner and a review date, and rebuild so that your SBOM reflects the change.

Lifecycle data tells you when upstream will stop fixing a component; it does not fix anything on its own. The open source libraries and container images that you build into your products are where most end of life exposure sits, and that is where the steps below apply.

Fix it without waiting for upstream

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.

3. Gold Registry: start from components that are already fixed

registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingThe Gold scan GitHub Action in CI, plus Safeguard policies and gates
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch (early access)
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

The first demo sets up the local runner on your own machine, approves it with its device code, then scans from the terminal. That scan produces the inventory that lifecycle data has to be joined to: run it on a repository or a container image and you have the component list, with purls, that the walkthrough above starts from.

Click through it at your own pace, or open it full screen.

The second demo is a real Safeguard CLI session: asked to fix a lodash CVE, the assistant reads the finding and advisory, asks before each command, edits package.json to lodash 4.17.21, runs npm install and npm test with your approval, prints a summary and pushes nothing. The same approval-gated flow fits the "upgrade" action from the decision table, when a component is nearing end of security support and a supported version exists.

Click through it at your own pace, or open it full screen.

The third demo connects Claude to the Safeguard MCP server with OAuth and chooses which tools Claude can use. Once your projects are in Safeguard, that connection lets you ask which of them contain a given component and version, which is the question to answer the day a runtime such as Python 3.10 reaches end of life.

Click through it at your own pace, or open it full screen.

To try the CLI, download Safeguard and follow the CLI documentation.

Quick check

An OpenEoX record has "end_of_security_support": "tba". How should a tool sort it against a record that ends in 2030?

The tba record sorts later. The OpenEoX Core draft says consumers must treat tba as a date greater than the maximum date and interpret it as not yet announced, so it is neither expired nor permanently supported.

A supplier published a CLE endOfSupport event with the wrong date. How should it correct it?

By appending a withdrawn event that references the wrong event's ID, then appending a new endOfSupport event with the right date. ECMA-428 forbids modifying published events; consumers ignore the withdrawn one but keep it for audit.

Your SBOM lists a Python package from a Debian base image. Whose end of life date applies?

Debian's. A distribution sets its own support period and may backport security fixes after upstream's end of life, so the distribution's lifecycle governs the package it ships.

Sources

Last reviewed: 23 October 2026. OpenEoX Core is a committee draft and CSAF 2.1 is in draft; check the OASIS and Ecma pages for the current stage before building tooling against either.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.