[{"data":1,"prerenderedAt":11771},["ShallowReactive",2],{"blog-list":3},[4,1592,2232,3215,4329,5217,6190,8326,9338,10464,11227],{"id":5,"title":6,"body":7,"date":1575,"description":1576,"extension":1577,"image":1578,"keywords":1579,"meta":1586,"navigation":98,"path":1587,"readTime":1588,"seo":1589,"stem":1590,"__hash__":1591},"blog/blog/cra-annex-i-essential-requirements-checklist.md","CRA Annex I Checklist for Firmware Engineers",{"type":8,"value":9,"toc":1535},"minimark",[10,14,17,20,25,28,35,41,44,49,56,63,66,70,74,80,85,125,128,132,137,141,179,185,189,194,198,241,245,250,254,287,291,296,300,327,330,334,339,343,397,401,406,410,443,453,457,462,466,499,503,508,512,545,549,554,558,595,611,615,620,624,663,667,672,676,703,707,712,716,737,741,744,748,772,776,807,811,838,842,863,867,914,918,939,943,970,974,1001,1005,1009,1012,1089,1093,1096,1174,1182,1186,1200,1203,1207,1212,1370,1375,1469,1477,1480,1486,1490],[11,12,13],"p",{},"Annex I of the Cyber Resilience Act is the core of the regulation. It defines the essential cybersecurity requirements that every product with digital elements must meet before it can carry a CE mark and be placed on the EU market.",[11,15,16],{},"The problem for firmware engineers: Annex I is written in regulatory language, not engineering language. It says things like \"appropriate level of cybersecurity\" and \"designed and manufactured to ensure an appropriate level of protection\" — which doesn't tell you what to implement.",[11,18,19],{},"This post translates every Annex I requirement into concrete firmware engineering tasks. Use it as a checklist to assess your current posture and track remediation work. Each requirement links to deeper coverage in our other posts where applicable.",[21,22,24],"h2",{"id":23},"how-annex-i-is-structured","How Annex I Is Structured",[11,26,27],{},"Annex I has two parts:",[11,29,30,34],{},[31,32,33],"strong",{},"Part I — Security requirements (13 items):"," These cover the product's design, development, and delivery. They address what the product itself must do.",[11,36,37,40],{},[31,38,39],{},"Part II — Vulnerability handling requirements (8 items):"," These cover the manufacturer's processes for managing vulnerabilities after the product is shipped. They address what your organisation must do.",[11,42,43],{},"Both parts must be satisfied. A product with excellent security engineering but no vulnerability management process is non-compliant, and vice versa.",[45,46,48],"h3",{"id":47},"harmonised-standards-en-18031","Harmonised Standards: EN 18031",[11,50,51,52,55],{},"CEN/CENELEC has developed harmonised standards relevant to cybersecurity for connected products. The EN 18031 series (EN 18031-1, EN 18031-2, EN 18031-3) was originally developed for the ",[31,53,54],{},"Radio Equipment Directive (RED)"," under Delegated Regulation 2022/30/EU. The series was finalised in August 2024 and harmonised references were published in the Official Journal of the EU in January 2025.",[11,57,58,59,62],{},"While EN 18031 was not developed specifically for the CRA, it serves as a foundation upon which CRA-specific harmonised standards are being built. Implementing EN 18031 provides a strong starting baseline for CRA compliance, particularly for connected products that also fall under the RED. CEN/CENELEC is developing additional CRA-specific standards that will provide a ",[31,60,61],{},"presumption of conformity"," with Annex I requirements once published.",[11,64,65],{},"In practice: if you implement EN 18031 and can demonstrate alignment with its requirements, you establish a solid technical baseline for CRA conformity, though the CRA-specific harmonised standards may add additional requirements. The requirements below reflect both the Annex I text and the EN 18031 standards where they provide useful clarification.",[21,67,69],{"id":68},"part-i-security-requirements","Part I: Security Requirements",[45,71,73],{"id":72},"requirement-1-designed-with-an-appropriate-level-of-cybersecurity","Requirement 1 — Designed with an appropriate level of cybersecurity",[11,75,76,79],{},[31,77,78],{},"Regulation text (paraphrased):"," Products must be designed, developed, and produced to ensure an appropriate level of cybersecurity based on the risks.",[11,81,82],{},[31,83,84],{},"What this means for firmware:",[86,87,90,107,113,119],"ul",{"className":88},[89],"contains-task-list",[91,92,95,100,101,106],"li",{"className":93},[94],"task-list-item",[96,97],"input",{"disabled":98,"type":99},true,"checkbox"," Conduct a risk assessment / ",[102,103,105],"a",{"href":104},"/blog/cra-threat-modeling-embedded/","threat model"," for your product before and during development",[91,108,110,112],{"className":109},[94],[96,111],{"disabled":98,"type":99}," Document security design decisions and their rationale",[91,114,116,118],{"className":115},[94],[96,117],{"disabled":98,"type":99}," Security requirements derived from the threat model are traceable to implementation",[91,120,122,124],{"className":121},[94],[96,123],{"disabled":98,"type":99}," Security is part of the development process, not bolted on after functional development",[11,126,127],{},"This is the overarching requirement. All subsequent requirements are specific instances of it.",[45,129,131],{"id":130},"requirement-2-no-known-exploitable-vulnerabilities","Requirement 2 — No known exploitable vulnerabilities",[11,133,134,136],{},[31,135,78],{}," Products must be delivered without known exploitable vulnerabilities.",[11,138,139],{},[31,140,84],{},[86,142,144,155,161,167,173],{"className":143},[89],[91,145,147,149,150,154],{"className":146},[94],[96,148],{"disabled":98,"type":99}," Run vulnerability scanning against all third-party components before each release (use your ",[102,151,153],{"href":152},"/blog/cra-sbom-firmware/","SBOM"," as input)",[91,156,158,160],{"className":157},[94],[96,159],{"disabled":98,"type":99}," Triage all CVEs affecting components in your firmware (VEX process)",[91,162,164,166],{"className":163},[94],[96,165],{"disabled":98,"type":99}," Patch or mitigate all exploitable vulnerabilities before shipping",[91,168,170,172],{"className":169},[94],[96,171],{"disabled":98,"type":99}," Document triage decisions for CVEs you've assessed as not exploitable (retain VEX records)",[91,174,176,178],{"className":175},[94],[96,177],{"disabled":98,"type":99}," Include vulnerability scan results in your release documentation",[11,180,181,184],{},[31,182,183],{},"Note:"," \"Known\" means vulnerabilities published in CVE databases for components you ship. You're expected to be monitoring.",[45,186,188],{"id":187},"requirement-3-integrity-protection","Requirement 3 — Integrity protection",[11,190,191,193],{},[31,192,78],{}," Protect the integrity of stored, transmitted, and processed data and software, including firmware.",[11,195,196],{},[31,197,84],{},[86,199,201,212,223,229,235],{"className":200},[89],[91,202,204,206,207,211],{"className":203},[94],[96,205],{"disabled":98,"type":99}," Implement ",[102,208,210],{"href":209},"/blog/cra-secure-boot-firmware-signing/","secure boot"," to verify firmware integrity at every boot",[91,213,215,217,218,222],{"className":214},[94],[96,216],{"disabled":98,"type":99}," Sign all ",[102,219,221],{"href":220},"/blog/cra-ota-firmware-updates/","firmware updates"," and verify signatures before installation",[91,224,226,228],{"className":225},[94],[96,227],{"disabled":98,"type":99}," Use authenticated encryption or HMAC for data stored in external flash/EEPROM",[91,230,232,234],{"className":231},[94],[96,233],{"disabled":98,"type":99}," Validate all data received from external interfaces before processing (input validation)",[91,236,238,240],{"className":237},[94],[96,239],{"disabled":98,"type":99}," Protect configuration data against unauthorised modification",[45,242,244],{"id":243},"requirement-4-confidentiality-protection","Requirement 4 — Confidentiality protection",[11,246,247,249],{},[31,248,78],{}," Protect the confidentiality of stored, transmitted, and processed data, including personal data and secrets.",[11,251,252],{},[31,253,84],{},[86,255,257,263,269,275,281],{"className":256},[89],[91,258,260,262],{"className":259},[94],[96,261],{"disabled":98,"type":99}," Encrypt sensitive data at rest (credentials, keys, user data) — use AES-256 or ChaCha20",[91,264,266,268],{"className":265},[94],[96,267],{"disabled":98,"type":99}," Encrypt data in transit — TLS 1.2+ for TCP, DTLS 1.2+ for UDP/CoAP on constrained devices",[91,270,272,274],{"className":271},[94],[96,273],{"disabled":98,"type":99}," Protect cryptographic keys in secure storage (hardware keystore, TrustZone, secure element) — never in plaintext flash",[91,276,278,280],{"className":277},[94],[96,279],{"disabled":98,"type":99}," Implement secure key derivation for session keys (HKDF or similar)",[91,282,284,286],{"className":283},[94],[96,285],{"disabled":98,"type":99}," Don't log or transmit sensitive data in debug output",[45,288,290],{"id":289},"requirement-5-minimise-data-collection-and-processing","Requirement 5 — Minimise data collection and processing",[11,292,293,295],{},[31,294,78],{}," Minimise the processing of data, including personal data, to what is necessary for the intended purpose.",[11,297,298],{},[31,299,84],{},[86,301,303,309,315,321],{"className":302},[89],[91,304,306,308],{"className":305},[94],[96,307],{"disabled":98,"type":99}," Only collect data necessary for the product's function (no telemetry beyond what's needed)",[91,310,312,314],{"className":311},[94],[96,313],{"disabled":98,"type":99}," Provide users with control over optional data collection",[91,316,318,320],{"className":317},[94],[96,319],{"disabled":98,"type":99}," Implement data retention limits — don't store data indefinitely",[91,322,324,326],{"className":323},[94],[96,325],{"disabled":98,"type":99}," Document what data your device collects and why",[11,328,329],{},"This requirement aligns with GDPR principles. For firmware teams, it typically means auditing your telemetry and logging to ensure you're not overcollecting.",[45,331,333],{"id":332},"requirement-6-minimise-attack-surface","Requirement 6 — Minimise attack surface",[11,335,336,338],{},[31,337,78],{}," Minimise the attack surface, including external interfaces.",[11,340,341],{},[31,342,84],{},[86,344,346,352,358,364,370,385,391],{"className":345},[89],[91,347,349,351],{"className":348},[94],[96,350],{"disabled":98,"type":99}," Disable all unused network services and protocols in production builds",[91,353,355,357],{"className":354},[94],[96,356],{"disabled":98,"type":99}," Disable debug interfaces (JTAG/SWD) in production firmware via OTP fuses or firmware configuration",[91,359,361,363],{"className":360},[94],[96,362],{"disabled":98,"type":99}," Close or disable unused UART, SPI, I2C, and other peripheral interfaces in software",[91,365,367,369],{"className":366},[94],[96,368],{"disabled":98,"type":99}," Remove debug logging, test endpoints, and development backdoors from production builds",[91,371,373,375,376,380,381,384],{"className":372},[94],[96,374],{"disabled":98,"type":99}," Compile with hardening flags (",[377,378,379],"code",{},"-fstack-protector-strong",", ",[377,382,383],{},"-D_FORTIFY_SOURCE=2",", ASLR where supported)",[91,386,388,390],{"className":387},[94],[96,389],{"disabled":98,"type":99}," Use MPU (Memory Protection Unit) to isolate privileged and unprivileged code where the MCU supports it",[91,392,394,396],{"className":393},[94],[96,395],{"disabled":98,"type":99}," Minimise the firmware binary — strip unused features, libraries, and drivers",[45,398,400],{"id":399},"requirement-7-secure-default-configuration","Requirement 7 — Secure default configuration",[11,402,403,405],{},[31,404,78],{}," Products must be delivered with a secure default configuration, including the possibility to reset to the original secure state.",[11,407,408],{},[31,409,84],{},[86,411,413,419,425,431,437],{"className":412},[89],[91,414,416,418],{"className":415},[94],[96,417],{"disabled":98,"type":99}," No default passwords — either unique-per-device credentials or force user setup on first boot",[91,420,422,424],{"className":421},[94],[96,423],{"disabled":98,"type":99}," All security features enabled by default (encryption, authentication, secure boot)",[91,426,428,430],{"className":427},[94],[96,429],{"disabled":98,"type":99}," Unnecessary services disabled by default (don't ship with telnet or HTTP debug server enabled)",[91,432,434,436],{"className":433},[94],[96,435],{"disabled":98,"type":99}," Factory reset restores the device to a secure state (not to a state with known-default credentials)",[91,438,440,442],{"className":439},[94],[96,441],{"disabled":98,"type":99}," Configuration changes that weaken security require explicit user action and generate a warning",[11,444,445,448,449,452],{},[31,446,447],{},"The \"no default passwords\" requirement is explicit and non-negotiable."," If your product ships with ",[377,450,451],{},"admin/admin"," or a common default across all units, you're in violation.",[45,454,456],{"id":455},"requirement-8-protection-against-unauthorised-access","Requirement 8 — Protection against unauthorised access",[11,458,459,461],{},[31,460,78],{}," Products must be designed to protect against unauthorised access through appropriate control mechanisms, including authentication.",[11,463,464],{},[31,465,84],{},[86,467,469,475,481,487,493],{"className":468},[89],[91,470,472,474],{"className":471},[94],[96,473],{"disabled":98,"type":99}," All remote access interfaces require authentication",[91,476,478,480],{"className":477},[94],[96,479],{"disabled":98,"type":99}," Authentication mechanisms are resistant to brute force (rate limiting, account lockout, exponential backoff)",[91,482,484,486],{"className":483},[94],[96,485],{"disabled":98,"type":99}," Credentials stored on device are hashed/salted (not plaintext)",[91,488,490,492],{"className":489},[94],[96,491],{"disabled":98,"type":99}," Session tokens have appropriate expiry",[91,494,496,498],{"className":495},[94],[96,497],{"disabled":98,"type":99}," Privilege separation — different access levels for user vs. admin vs. maintenance operations",[45,500,502],{"id":501},"requirement-9-availability-and-resilience","Requirement 9 — Availability and resilience",[11,504,505,507],{},[31,506,78],{}," Products must be designed to ensure availability, including resilience against denial-of-service attacks.",[11,509,510],{},[31,511,84],{},[86,513,515,521,527,533,539],{"className":514},[89],[91,516,518,520],{"className":517},[94],[96,519],{"disabled":98,"type":99}," Network stack handles malformed packets gracefully (doesn't crash or hang)",[91,522,524,526],{"className":523},[94],[96,525],{"disabled":98,"type":99}," Resource limits enforced — connection limits, message rate limits, buffer size limits",[91,528,530,532],{"className":529},[94],[96,531],{"disabled":98,"type":99}," Watchdog timer configured to recover from hangs",[91,534,536,538],{"className":535},[94],[96,537],{"disabled":98,"type":99}," Critical functions remain operational under network stress",[91,540,542,544],{"className":541},[94],[96,543],{"disabled":98,"type":99}," Stack and heap overflow protection enabled",[45,546,548],{"id":547},"requirement-10-secure-communications","Requirement 10 — Secure communications",[11,550,551,553],{},[31,552,78],{}," Products must ensure secure communication, including encryption of data in transit.",[11,555,556],{},[31,557,84],{},[86,559,561,567,577,583,589],{"className":560},[89],[91,562,564,566],{"className":563},[94],[96,565],{"disabled":98,"type":99}," TLS 1.2+ (or DTLS 1.2+) for all network communications carrying sensitive data",[91,568,570,572,573,576],{"className":569},[94],[96,571],{"disabled":98,"type":99}," Server certificate verification enabled (no ",[377,574,575],{},"verify=false"," in production)",[91,578,580,582],{"className":579},[94],[96,581],{"disabled":98,"type":99}," Strong cipher suites only — disable CBC mode ciphers, prefer AEAD (AES-GCM, ChaCha20-Poly1305)",[91,584,586,588],{"className":585},[94],[96,587],{"disabled":98,"type":99}," For constrained devices: DTLS 1.2 with PSK or certificate authentication over CoAP",[91,590,592,594],{"className":591},[94],[96,593],{"disabled":98,"type":99}," Certificate or PSK provisioning during manufacturing (not hardcoded shared secrets)",[11,596,597,600,601,605,606,610],{},[31,598,599],{},"Libraries:"," Mbed TLS (part of TrustedFirmware), wolfSSL, and BearSSL are common choices for MCU-based TLS. For Zephyr projects, Mbed TLS is the default. For ESP-IDF, mbedtls is bundled. (See our ",[102,602,604],{"href":603},"/blog/cra-compliance-zephyr-rtos/","Zephyr RTOS"," and ",[102,607,609],{"href":608},"/blog/cra-compliance-freertos/","FreeRTOS"," guides for RTOS-specific implementation details.)",[45,612,614],{"id":613},"requirement-11-logging-of-security-relevant-events","Requirement 11 — Logging of security-relevant events",[11,616,617,619],{},[31,618,78],{}," Products must log security-relevant events, where technically feasible.",[11,621,622],{},[31,623,84],{},[86,625,627,633,639,645,651,657],{"className":626},[89],[91,628,630,632],{"className":629},[94],[96,631],{"disabled":98,"type":99}," Log authentication attempts (success and failure)",[91,634,636,638],{"className":635},[94],[96,637],{"disabled":98,"type":99}," Log firmware update events (download, verification, installation, rollback)",[91,640,642,644],{"className":641},[94],[96,643],{"disabled":98,"type":99}," Log security configuration changes",[91,646,648,650],{"className":647},[94],[96,649],{"disabled":98,"type":99}," Log detected attacks or anomalies (malformed packets, repeated auth failures)",[91,652,654,656],{"className":653},[94],[96,655],{"disabled":98,"type":99}," Logs are tamper-protected (integrity-checked or stored in a protected region)",[91,658,660,662],{"className":659},[94],[96,661],{"disabled":98,"type":99}," For constrained devices where persistent logging isn't feasible: document why and what alternatives you provide (e.g., event counters, syslog forwarding)",[45,664,666],{"id":665},"requirement-12-secure-deletion-of-data","Requirement 12 — Secure deletion of data",[11,668,669,671],{},[31,670,78],{}," Provide the possibility for users to securely remove personal and configuration data from the device.",[11,673,674],{},[31,675,84],{},[86,677,679,685,691,697],{"className":678},[89],[91,680,682,684],{"className":681},[94],[96,683],{"disabled":98,"type":99}," Factory reset function that overwrites (not just marks as deleted) user data, credentials, and configuration",[91,686,688,690],{"className":687},[94],[96,689],{"disabled":98,"type":99}," Secure erase of cryptographic keys during factory reset",[91,692,694,696],{"className":693},[94],[96,695],{"disabled":98,"type":99}," Factory reset accessible without requiring authentication (for when credentials are lost)",[91,698,700,702],{"className":699},[94],[96,701],{"disabled":98,"type":99}," Document the factory reset procedure in user documentation",[45,704,706],{"id":705},"requirement-13-user-notification-of-security-issues","Requirement 13 — User notification of security issues",[11,708,709,711],{},[31,710,78],{}," Products must be capable of notifying users about security issues and available updates.",[11,713,714],{},[31,715,84],{},[86,717,719,725,731],{"className":718},[89],[91,720,722,724],{"className":721},[94],[96,723],{"disabled":98,"type":99}," Mechanism to inform users when a security update is available (LED indicator, companion app notification, web dashboard alert)",[91,726,728,730],{"className":727},[94],[96,729],{"disabled":98,"type":99}," Users can check the current firmware version easily",[91,732,734,736],{"className":733},[94],[96,735],{"disabled":98,"type":99}," Security advisories are published in an accessible location (product support page, security bulletin feed)",[21,738,740],{"id":739},"part-ii-vulnerability-handling-requirements","Part II: Vulnerability Handling Requirements",[11,742,743],{},"Part II requirements apply to your organisation's processes, not to the product itself. These must be in place and documented.",[45,745,747],{"id":746},"vh-requirement-1-identify-and-document-vulnerabilities-and-components","VH Requirement 1 — Identify and document vulnerabilities and components",[86,749,751,760,766],{"className":750},[89],[91,752,754,756,757,759],{"className":753},[94],[96,755],{"disabled":98,"type":99}," Maintain a machine-readable ",[102,758,153],{"href":152}," covering all product components",[91,761,763,765],{"className":762},[94],[96,764],{"disabled":98,"type":99}," SBOM updated with each firmware release",[91,767,769,771],{"className":768},[94],[96,770],{"disabled":98,"type":99}," SBOM in SPDX or CycloneDX format with NTIA minimum elements",[45,773,775],{"id":774},"vh-requirement-2-address-vulnerabilities-with-security-updates","VH Requirement 2 — Address vulnerabilities with security updates",[86,777,779,789,795,801],{"className":778},[89],[91,780,782,784,785,788],{"className":781},[94],[96,783],{"disabled":98,"type":99}," ",[102,786,787],{"href":220},"OTA update mechanism"," operational and tested",[91,790,792,794],{"className":791},[94],[96,793],{"disabled":98,"type":99}," Security updates delivered free of charge",[91,796,798,800],{"className":797},[94],[96,799],{"disabled":98,"type":99}," Patch timeline: critical/exploited vulnerabilities addressed within days/weeks, not months",[91,802,804,806],{"className":803},[94],[96,805],{"disabled":98,"type":99}," Update process documented and tested for failure scenarios",[45,808,810],{"id":809},"vh-requirement-3-regular-testing-and-review","VH Requirement 3 — Regular testing and review",[86,812,814,820,826,832],{"className":813},[89],[91,815,817,819],{"className":816},[94],[96,818],{"disabled":98,"type":99}," Regular vulnerability scanning of firmware components (at minimum, per release)",[91,821,823,825],{"className":822},[94],[96,824],{"disabled":98,"type":99}," Periodic penetration testing (annual for default category; more frequent for Class I/II)",[91,827,829,831],{"className":828},[94],[96,830],{"disabled":98,"type":99}," Code review process for security-sensitive changes",[91,833,835,837],{"className":834},[94],[96,836],{"disabled":98,"type":99}," Test results documented and retained",[45,839,841],{"id":840},"vh-requirement-4-public-disclosure-of-fixed-vulnerabilities","VH Requirement 4 — Public disclosure of fixed vulnerabilities",[86,843,845,851,857],{"className":844},[89],[91,846,848,850],{"className":847},[94],[96,849],{"disabled":98,"type":99}," Security advisories published for fixed vulnerabilities",[91,852,854,856],{"className":853},[94],[96,855],{"disabled":98,"type":99}," Advisories include CVE IDs, affected versions, fixed versions, and mitigation guidance",[91,858,860,862],{"className":859},[94],[96,861],{"disabled":98,"type":99}," Advisories published at the same time as the security update (not delayed)",[45,864,866],{"id":865},"vh-requirement-5-coordinated-vulnerability-disclosure-policy","VH Requirement 5 — Coordinated vulnerability disclosure policy",[86,868,870,880,891,897,903],{"className":869},[89],[91,871,873,875,876,879],{"className":872},[94],[96,874],{"disabled":98,"type":99}," CVD policy published and accessible (security.txt at ",[377,877,878],{},"/.well-known/security.txt",")",[91,881,883,885,886,890],{"className":882},[94],[96,884],{"disabled":98,"type":99}," Monitored security contact (",[102,887,889],{"href":888},"mailto:security@yourcompany.com","security@yourcompany.com"," or equivalent)",[91,892,894,896],{"className":893},[94],[96,895],{"disabled":98,"type":99}," Researcher acknowledgement policy defined",[91,898,900,902],{"className":899},[94],[96,901],{"disabled":98,"type":99}," Response timeline commitments documented (e.g., acknowledge within 5 business days)",[91,904,906,908,909,913],{"className":905},[94],[96,907],{"disabled":98,"type":99}," See our ",[102,910,912],{"href":911},"/blog/cra-article-14-vulnerability-reporting/","Article 14"," post for the full PSIRT setup",[45,915,917],{"id":916},"vh-requirement-6-sharing-vulnerability-information","VH Requirement 6 — Sharing vulnerability information",[86,919,921,927,933],{"className":920},[89],[91,922,924,926],{"className":923},[94],[96,925],{"disabled":98,"type":99}," Vulnerability information shared with affected parties when necessary",[91,928,930,932],{"className":929},[94],[96,931],{"disabled":98,"type":99}," ENISA notification process established for actively exploited vulnerabilities (Article 14)",[91,934,936,938],{"className":935},[94],[96,937],{"disabled":98,"type":99}," Process for notifying downstream customers when a vulnerability affects their deployment",[45,940,942],{"id":941},"vh-requirement-7-secure-distribution-of-updates","VH Requirement 7 — Secure distribution of updates",[86,944,946,952,958,964],{"className":945},[89],[91,947,949,951],{"className":948},[94],[96,950],{"disabled":98,"type":99}," Updates cryptographically signed",[91,953,955,957],{"className":954},[94],[96,956],{"disabled":98,"type":99}," Update distribution infrastructure secured (TLS, access controls)",[91,959,961,963],{"className":960},[94],[96,962],{"disabled":98,"type":99}," Update integrity verified before installation on device",[91,965,967,969],{"className":966},[94],[96,968],{"disabled":98,"type":99}," Update distribution documented in technical documentation",[45,971,973],{"id":972},"vh-requirement-8-no-undue-delay-in-distributing-security-patches","VH Requirement 8 — No undue delay in distributing security patches",[86,975,977,983,989,995],{"className":976},[89],[91,978,980,982],{"className":979},[94],[96,981],{"disabled":98,"type":99}," Patch development and release process with defined SLAs",[91,984,986,988],{"className":985},[94],[96,987],{"disabled":98,"type":99}," No gating of security patches behind feature releases or subscription payments",[91,990,992,994],{"className":991},[94],[96,993],{"disabled":98,"type":99}," Emergency patch process for critical/exploited vulnerabilities",[91,996,998,1000],{"className":997},[94],[96,999],{"disabled":98,"type":99}," Patch deployment tracking (what percentage of devices have been updated)",[21,1002,1004],{"id":1003},"using-this-checklist","Using This Checklist",[45,1006,1008],{"id":1007},"priority-order-for-firmware-teams","Priority Order for Firmware Teams",[11,1010,1011],{},"If you're starting from zero, this is the recommended implementation order:",[1013,1014,1015,1023,1032,1041,1047,1056,1065,1071,1077,1083],"ol",{},[91,1016,1017,1019,1020,879],{},[31,1018,153],{}," (VH1) — You need to know what's in your firmware before you can secure it. (",[102,1021,1022],{"href":152},"SBOM guide",[91,1024,1025,1028,1029,879],{},[31,1026,1027],{},"Secure boot"," (Req 3) — Foundation for firmware integrity. (",[102,1030,1031],{"href":209},"Secure boot guide",[91,1033,1034,1037,1038,879],{},[31,1035,1036],{},"OTA updates"," (VH2, VH7, VH8) — Ability to deliver fixes. (",[102,1039,1040],{"href":220},"OTA guide",[91,1042,1043,1046],{},[31,1044,1045],{},"Vulnerability monitoring"," (VH1, VH3) — Know when your components have CVEs",[91,1048,1049,1052,1053,879],{},[31,1050,1051],{},"CVD policy and PSIRT"," (VH5, VH6) — Handle external vulnerability reports. (",[102,1054,1055],{"href":911},"Article 14 guide",[91,1057,1058,1061,1062,879],{},[31,1059,1060],{},"Threat model"," (Req 1) — Document your security design rationale. (",[102,1063,1064],{"href":104},"Threat modeling guide",[91,1066,1067,1070],{},[31,1068,1069],{},"Secure defaults"," (Req 7) — No default passwords, services disabled by default",[91,1072,1073,1076],{},[31,1074,1075],{},"Encryption"," (Req 4, Req 10) — Data at rest and in transit",[91,1078,1079,1082],{},[31,1080,1081],{},"Access control"," (Req 8) — Authentication and authorisation",[91,1084,1085,1088],{},[31,1086,1087],{},"Everything else"," (Req 5, 6, 9, 11, 12, 13) — Important but lower priority for initial compliance",[45,1090,1092],{"id":1091},"mapping-to-product-classification","Mapping to Product Classification",[11,1094,1095],{},"The checklist applies to all CRA-classified products, but the evidence requirements differ:",[1097,1098,1099,1118],"table",{},[1100,1101,1102],"thead",{},[1103,1104,1105,1109,1112,1115],"tr",{},[1106,1107,1108],"th",{},"Requirement area",[1106,1110,1111],{},"Default (self-declare)",[1106,1113,1114],{},"Class I (CAB audit)",[1106,1116,1117],{},"Class II (notified body)",[1119,1120,1121,1135,1149,1160],"tbody",{},[1103,1122,1123,1126,1129,1132],{},[1124,1125,1060],"td",{},[1124,1127,1128],{},"Documented, internal review",[1124,1130,1131],{},"Reviewed by CAB",[1124,1133,1134],{},"Reviewed by notified body",[1103,1136,1137,1140,1143,1146],{},[1124,1138,1139],{},"Security testing",[1124,1141,1142],{},"Self-assessed test results",[1124,1144,1145],{},"Third-party test results may be required",[1124,1147,1148],{},"Formal penetration testing required",[1103,1150,1151,1153,1156,1158],{},[1124,1152,153],{},[1124,1154,1155],{},"Generated, on file",[1124,1157,1131],{},[1124,1159,1134],{},[1103,1161,1162,1165,1168,1171],{},[1124,1163,1164],{},"Process documentation",[1124,1166,1167],{},"Written, internal",[1124,1169,1170],{},"Audited by CAB",[1124,1172,1173],{},"Audited by notified body",[11,1175,1176,1177,1181],{},"See our ",[102,1178,1180],{"href":1179},"/blog/cra-product-classification/","product classification guide"," for which tier applies to your product.",[45,1183,1185],{"id":1184},"timeline","Timeline",[86,1187,1188,1194],{},[91,1189,1190,1193],{},[31,1191,1192],{},"11 September 2026:"," Vulnerability handling requirements (Part II) must be in place — specifically Article 14 reporting",[91,1195,1196,1199],{},[31,1197,1198],{},"11 December 2027:"," All Annex I requirements (Part I and Part II) must be met for products placed on the market",[11,1201,1202],{},"Start with Part II (vulnerability handling) since that deadline comes first.",[21,1204,1206],{"id":1205},"printable-summary","Printable Summary",[11,1208,1209],{},[31,1210,1211],{},"Part I — Security Requirements:",[1097,1213,1214,1227],{},[1100,1215,1216],{},[1103,1217,1218,1221,1224],{},[1106,1219,1220],{},"#",[1106,1222,1223],{},"Requirement",[1106,1225,1226],{},"Key firmware task",[1119,1228,1229,1240,1251,1262,1273,1284,1295,1305,1315,1326,1337,1348,1359],{},[1103,1230,1231,1234,1237],{},[1124,1232,1233],{},"1",[1124,1235,1236],{},"Appropriate cybersecurity level",[1124,1238,1239],{},"Threat model, security design",[1103,1241,1242,1245,1248],{},[1124,1243,1244],{},"2",[1124,1246,1247],{},"No known exploitable vulnerabilities",[1124,1249,1250],{},"CVE scanning, VEX triage",[1103,1252,1253,1256,1259],{},[1124,1254,1255],{},"3",[1124,1257,1258],{},"Integrity protection",[1124,1260,1261],{},"Secure boot, signed updates",[1103,1263,1264,1267,1270],{},[1124,1265,1266],{},"4",[1124,1268,1269],{},"Confidentiality",[1124,1271,1272],{},"Encryption at rest and in transit",[1103,1274,1275,1278,1281],{},[1124,1276,1277],{},"5",[1124,1279,1280],{},"Data minimisation",[1124,1282,1283],{},"Audit telemetry, retention limits",[1103,1285,1286,1289,1292],{},[1124,1287,1288],{},"6",[1124,1290,1291],{},"Minimise attack surface",[1124,1293,1294],{},"Disable debug ports, unused services",[1103,1296,1297,1300,1302],{},[1124,1298,1299],{},"7",[1124,1301,1069],{},[1124,1303,1304],{},"No default passwords, secure out of box",[1103,1306,1307,1310,1312],{},[1124,1308,1309],{},"8",[1124,1311,1081],{},[1124,1313,1314],{},"Authentication, privilege separation",[1103,1316,1317,1320,1323],{},[1124,1318,1319],{},"9",[1124,1321,1322],{},"Availability / resilience",[1124,1324,1325],{},"DoS protection, watchdog, resource limits",[1103,1327,1328,1331,1334],{},[1124,1329,1330],{},"10",[1124,1332,1333],{},"Secure communications",[1124,1335,1336],{},"TLS/DTLS, certificate verification",[1103,1338,1339,1342,1345],{},[1124,1340,1341],{},"11",[1124,1343,1344],{},"Security event logging",[1124,1346,1347],{},"Auth logs, update logs, anomaly detection",[1103,1349,1350,1353,1356],{},[1124,1351,1352],{},"12",[1124,1354,1355],{},"Secure data deletion",[1124,1357,1358],{},"Factory reset with secure erase",[1103,1360,1361,1364,1367],{},[1124,1362,1363],{},"13",[1124,1365,1366],{},"User notification",[1124,1368,1369],{},"Update availability notifications",[11,1371,1372],{},[31,1373,1374],{},"Part II — Vulnerability Handling:",[1097,1376,1377,1388],{},[1100,1378,1379],{},[1103,1380,1381,1383,1385],{},[1106,1382,1220],{},[1106,1384,1223],{},[1106,1386,1387],{},"Key organisational task",[1119,1389,1390,1400,1409,1419,1429,1439,1449,1459],{},[1103,1391,1392,1394,1397],{},[1124,1393,1233],{},[1124,1395,1396],{},"Component identification (SBOM)",[1124,1398,1399],{},"Automated SBOM generation in build pipeline",[1103,1401,1402,1404,1407],{},[1124,1403,1244],{},[1124,1405,1406],{},"Security update delivery",[1124,1408,787],{},[1103,1410,1411,1413,1416],{},[1124,1412,1255],{},[1124,1414,1415],{},"Regular testing",[1124,1417,1418],{},"Vulnerability scanning, penetration testing",[1103,1420,1421,1423,1426],{},[1124,1422,1266],{},[1124,1424,1425],{},"Public disclosure",[1124,1427,1428],{},"Security advisories with CVE IDs",[1103,1430,1431,1433,1436],{},[1124,1432,1277],{},[1124,1434,1435],{},"CVD policy",[1124,1437,1438],{},"security.txt, monitored inbox, response SLAs",[1103,1440,1441,1443,1446],{},[1124,1442,1288],{},[1124,1444,1445],{},"Information sharing",[1124,1447,1448],{},"ENISA reporting, downstream notification",[1103,1450,1451,1453,1456],{},[1124,1452,1299],{},[1124,1454,1455],{},"Secure update distribution",[1124,1457,1458],{},"Signed updates, TLS delivery",[1103,1460,1461,1463,1466],{},[1124,1462,1309],{},[1124,1464,1465],{},"Timely patch delivery",[1124,1467,1468],{},"Defined SLAs, no paywall on security patches",[11,1470,1471,1472,1476],{},"Use the ",[102,1473,1475],{"href":1474},"/","Stack Canary assessment tool"," to get a personalised assessment of which requirements you've already met and where to focus your remediation effort.",[1478,1479],"hr",{},[11,1481,1482],{},[1483,1484,1485],"em",{},"Based on Regulation EU 2024/2847 Annex I Parts I and II, EN 18031 series (finalised 2024, harmonised 2025), ENISA CRA implementation guidance (2025). This does not constitute legal advice.",[21,1487,1489],{"id":1488},"sources","Sources",[86,1491,1492,1500,1507,1514,1521,1528],{},[91,1493,1494],{},[102,1495,1499],{"href":1496,"rel":1497},"https://eur-lex.europa.eu/eli/reg/2024/2847/oj/eng",[1498],"nofollow","Regulation (EU) 2024/2847 — Cyber Resilience Act (full text)",[91,1501,1502],{},[102,1503,1506],{"href":1504,"rel":1505},"https://eur-lex.europa.eu/legal-content/EN/TXT/HTML/?uri=OJ:L_202402847",[1498],"CRA full text (HTML) — navigate to Annex I",[91,1508,1509],{},[102,1510,1513],{"href":1511,"rel":1512},"https://www.sgs.com/en/news/2025/02/safeguards-02625-eu-harmonizes-en-18031-standards",[1498],"EN 18031 harmonisation — EU Official Journal (January 2025)",[91,1515,1516],{},[102,1517,1520],{"href":1518,"rel":1519},"https://www.enisa.europa.eu/publications/cyber-resilience-act-requirements-standards-mapping",[1498],"ENISA — Cyber Resilience Act Requirements Standards Mapping",[91,1522,1523],{},[102,1524,1527],{"href":1525,"rel":1526},"https://digital-strategy.ec.europa.eu/en/factpages/cyber-resilience-act-implementation",[1498],"European Commission — Cyber Resilience Act implementation",[91,1529,1530],{},[102,1531,1534],{"href":1532,"rel":1533},"https://www.cencenelec.eu/news-events/news/2025/newsletter/ots-59-cybersecurity-standards/",[1498],"CEN-CENELEC — Cybersecurity standards development",{"title":1536,"searchDepth":1537,"depth":1537,"links":1538},"",2,[1539,1543,1558,1568,1573,1574],{"id":23,"depth":1537,"text":24,"children":1540},[1541],{"id":47,"depth":1542,"text":48},3,{"id":68,"depth":1537,"text":69,"children":1544},[1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,1555,1556,1557],{"id":72,"depth":1542,"text":73},{"id":130,"depth":1542,"text":131},{"id":187,"depth":1542,"text":188},{"id":243,"depth":1542,"text":244},{"id":289,"depth":1542,"text":290},{"id":332,"depth":1542,"text":333},{"id":399,"depth":1542,"text":400},{"id":455,"depth":1542,"text":456},{"id":501,"depth":1542,"text":502},{"id":547,"depth":1542,"text":548},{"id":613,"depth":1542,"text":614},{"id":665,"depth":1542,"text":666},{"id":705,"depth":1542,"text":706},{"id":739,"depth":1537,"text":740,"children":1559},[1560,1561,1562,1563,1564,1565,1566,1567],{"id":746,"depth":1542,"text":747},{"id":774,"depth":1542,"text":775},{"id":809,"depth":1542,"text":810},{"id":840,"depth":1542,"text":841},{"id":865,"depth":1542,"text":866},{"id":916,"depth":1542,"text":917},{"id":941,"depth":1542,"text":942},{"id":972,"depth":1542,"text":973},{"id":1003,"depth":1537,"text":1004,"children":1569},[1570,1571,1572],{"id":1007,"depth":1542,"text":1008},{"id":1091,"depth":1542,"text":1092},{"id":1184,"depth":1542,"text":1185},{"id":1205,"depth":1537,"text":1206},{"id":1488,"depth":1537,"text":1489},"2026-04-02","Map all 13 CRA Annex I security requirements and 8 vulnerability handling obligations to concrete firmware engineering tasks. Embedded checklist.","md","/images/blog/previews/annex-i-checklist.svg",[1580,1581,1582,1583,1584,1585],"CRA Annex I checklist","CRA essential requirements","CRA compliance checklist firmware","CRA security requirements embedded","EN 18031 CRA","Annex I Part I",{},"/blog/cra-annex-i-essential-requirements-checklist","14 min",{"title":6,"description":1576},"blog/cra-annex-i-essential-requirements-checklist","ZzUXIYd7w3xIoXDLUbro8xdWYaGRZ0tRaTWmPSEcEBU",{"id":1593,"title":1594,"body":1595,"date":2216,"description":2217,"extension":1577,"image":2218,"keywords":2219,"meta":2226,"navigation":98,"path":2227,"readTime":2228,"seo":2229,"stem":2230,"__hash__":2231},"blog/blog/cra-article-14-vulnerability-reporting.md","CRA Article 14: Embedded Vulnerability Reporting",{"type":8,"value":1596,"toc":2196},[1597,1604,1611,1614,1618,1627,1631,1645,1648,1662,1665,1669,1680,1683,1703,1707,1718,1721,1738,1741,1745,1751,1771,1774,1777,1781,1784,1787,1792,1800,1805,1819,1829,1833,1836,1853,1858,1869,1872,1876,1883,1886,1906,1912,1916,1919,1922,1925,1933,1939,1943,1950,1953,1970,1975,1998,2001,2005,2008,2011,2015,2020,2040,2045,2056,2061,2099,2103,2106,2109,2124,2127,2131,2134,2142,2145,2148,2154,2156,2161,2163],[11,1598,1599,1600,1603],{},"Article 14 of the Cyber Resilience Act is the provision that will catch embedded product teams most off-guard. It's not the vulnerability-handling process itself (most firmware teams have some form of this, even if informal) — it's the ",[31,1601,1602],{},"mandatory external reporting chain with hard, legally-binding deadlines",".",[11,1605,1606,1607,1610],{},"The reporting obligation kicks in on ",[31,1608,1609],{},"11 September 2026",", more than a year ahead of full CRA enforcement. That means companies that are otherwise not CRA-ready still need to have their ENISA notification process working by September 2026.",[11,1612,1613],{},"This post breaks down the full Article 14 mechanism, clarifies the regulatory interpretation of \"actively exploited,\" and outlines a minimum viable PSIRT setup for small embedded teams.",[21,1615,1617],{"id":1616},"the-article-14-reporting-chain","The Article 14 Reporting Chain",[11,1619,1620,1621,605,1624,1603],{},"Article 14 establishes a multi-stage reporting obligation for two distinct event types: ",[31,1622,1623],{},"actively exploited vulnerabilities",[31,1625,1626],{},"severe incidents",[45,1628,1630],{"id":1629},"stage-1-24-hour-early-warning","Stage 1: 24-Hour Early Warning",[11,1632,1633,1634,1637,1638,1641,1642,1603],{},"Under Article 14(2)(a), upon becoming aware of an ",[31,1635,1636],{},"actively exploited vulnerability"," in their product, a manufacturer must submit an ",[31,1639,1640],{},"early warning"," to ENISA within ",[31,1643,1644],{},"24 hours",[11,1646,1647],{},"The early warning must contain:",[86,1649,1650,1653,1656,1659],{},[91,1651,1652],{},"Identification of the product (name, version)",[91,1654,1655],{},"Nature of the vulnerability (brief description)",[91,1657,1658],{},"Whether the manufacturer is aware of any malicious actors exploiting it",[91,1660,1661],{},"Whether corrective or mitigating measures are available",[11,1663,1664],{},"This is notification only—you don't need a patch ready. You need to notify.",[45,1666,1668],{"id":1667},"stage-2-72-hour-vulnerability-notification","Stage 2: 72-Hour Vulnerability Notification",[11,1670,1671,1672,1675,1676,1679],{},"Under Article 14(2)(b), within ",[31,1673,1674],{},"72 hours"," of becoming aware, the manufacturer must submit a more detailed ",[31,1677,1678],{},"vulnerability notification"," to ENISA.",[11,1681,1682],{},"This must include:",[86,1684,1685,1688,1691,1694,1697,1700],{},[91,1686,1687],{},"Product identifier",[91,1689,1690],{},"Affected versions",[91,1692,1693],{},"Nature of the vulnerability (CVSS-style severity, attack vector, conditions for exploitation)",[91,1695,1696],{},"Status of corrective measures (patch available, in development, or workaround only)",[91,1698,1699],{},"Planned timeline for patch release (if not yet available)",[91,1701,1702],{},"Any mitigating factors that reduce real-world exploitability",[45,1704,1706],{"id":1705},"stage-3-14-day-final-report","Stage 3: 14-Day Final Report",[11,1708,1709,1710,1713,1714,1717],{},"Under Article 14(2)(c), within ",[31,1711,1712],{},"14 days"," of becoming aware, the manufacturer must submit a ",[31,1715,1716],{},"final report"," (or \"vulnerability report\" in the regulation's terminology) to ENISA.",[11,1719,1720],{},"The final report must include:",[86,1722,1723,1726,1729,1732,1735],{},[91,1724,1725],{},"Full technical description of the vulnerability",[91,1727,1728],{},"CVE identifier (or request for one if not yet assigned)",[91,1730,1731],{},"Root cause analysis",[91,1733,1734],{},"Corrective measures taken or planned",[91,1736,1737],{},"Vulnerability impact assessment",[11,1739,1740],{},"After the 14-day report, ENISA may request additional information and can share relevant information with national cybersecurity authorities (CSIRTs and market surveillance authorities).",[45,1742,1744],{"id":1743},"the-severe-incident-track","The Severe Incident Track",[11,1746,1747,1748,1750],{},"Alongside the vulnerability reporting track, Article 14(3) creates a parallel requirement for ",[31,1749,1626],{},":",[86,1752,1753,1759,1765],{},[91,1754,1755,1758],{},[31,1756,1757],{},"24-hour early warning"," to ENISA upon becoming aware of a severe incident that has an impact on the security of the product",[91,1760,1761,1764],{},[31,1762,1763],{},"72-hour incident notification"," with fuller details",[91,1766,1767,1770],{},[31,1768,1769],{},"One-month final report"," following the incident",[11,1772,1773],{},"A \"severe incident\" is defined in the CRA as an incident that negatively affects the ability of a product with digital elements to protect the availability, authenticity, integrity, or confidentiality of data, or that has led or is capable of leading to the introduction of malicious code.",[11,1775,1776],{},"For most embedded firmware teams, the vulnerability reporting track (not the incident track) is the primary obligation to manage.",[21,1778,1780],{"id":1779},"what-actively-exploited-actually-means","What \"Actively Exploited\" Actually Means",[11,1782,1783],{},"This is the regulatory interpretation question that matters most for your triage process.",[11,1785,1786],{},"The CRA does not define \"actively exploited\" with precision in the text—this is an area where ENISA guidance and market surveillance practice will define the standard. Based on ENISA's published guidance (2025) and the regulation's intent, the working definition for compliance purposes is:",[11,1788,1789],{},[31,1790,1791],{},"A vulnerability is actively exploited when:",[86,1793,1794,1797],{},[91,1795,1796],{},"There is evidence that a threat actor has used the vulnerability against at least one system in the wild (not in a controlled research environment)",[91,1798,1799],{},"OR ENISA or a national CSIRT has flagged the vulnerability as actively exploited in their databases",[11,1801,1802],{},[31,1803,1804],{},"This is different from CVE \"known exploited\" standards in two important ways:",[1013,1806,1807,1813],{},[91,1808,1809,1812],{},[31,1810,1811],{},"Threat intelligence vs. public record:"," You don't need to wait for a CVE to appear on CISA's KEV list or similar databases. If your own threat intelligence, security researcher report, or customer incident report indicates exploitation in the wild, the 24-hour clock starts.",[91,1814,1815,1818],{},[31,1816,1817],{},"Your product specifically vs. the class of vulnerability:"," If a library you use has a known-exploited CVE (e.g., in CISA KEV), but that CVE is in a code path not present in your firmware build, it's likely not \"actively exploited in your product.\" However, if a CVE in a library you use has been exploited and the vulnerable code path is present in your firmware, the clock is running.",[11,1820,1821,1824,1825,1828],{},[31,1822,1823],{},"Practical implication:"," Your vulnerability triage process needs to determine within hours — not days — whether a newly disclosed CVE affects a code path that's actually present and exploitable in your firmware. This is one of the reasons VEX (Vulnerability Exploitability eXchange) documents are becoming important for CRA compliance. (See our post on ",[102,1826,1827],{"href":152},"SBOM and VEX for firmware",".)",[45,1830,1832],{"id":1831},"what-triggers-the-clock","What Triggers the Clock",[11,1834,1835],{},"Article 14(2) says the clock starts when the manufacturer \"becomes aware\" of the vulnerability. This has a specific regulatory meaning:",[86,1837,1838,1841,1844,1847,1850],{},[91,1839,1840],{},"Receipt of a vulnerability report from a security researcher",[91,1842,1843],{},"Internal discovery of a vulnerability via security testing or code review",[91,1845,1846],{},"Notification from a component vendor (e.g., a vulnerability in a chipset SDK)",[91,1848,1849],{},"Monitoring of CVE databases for software you ship",[91,1851,1852],{},"Customer incident reports indicating exploitation",[11,1854,1855],{},[31,1856,1857],{},"You cannot argue you \"weren't aware\" if:",[86,1859,1860,1863,1866],{},[91,1861,1862],{},"The vulnerability was published in a CVE database for a component you ship and you have no monitoring in place",[91,1864,1865],{},"A security researcher notified your published security contact and you didn't read it",[91,1867,1868],{},"Your vulnerability disclosure policy (VDP) inbox was unmanned",[11,1870,1871],{},"This means passive monitoring of CVE databases for all components in your firmware is a compliance requirement, not just good practice.",[21,1873,1875],{"id":1874},"the-enisa-single-reporting-platform","The ENISA Single Reporting Platform",[11,1877,1878,1879,1882],{},"Article 14(8) mandates that ENISA establish a ",[31,1880,1881],{},"single reporting platform"," for CRA vulnerability notifications. As of early 2026, ENISA has published the technical specification for this platform and is in the process of onboarding manufacturers.",[11,1884,1885],{},"Key practical points:",[86,1887,1888,1897,1900,1903],{},[91,1889,1890,1891,1896],{},"The platform will be available at a URL published by ENISA (check ",[102,1892,1895],{"href":1893,"rel":1894},"https://www.enisa.europa.eu/topics/product-security-and-certification/single-reporting-platform-srp",[1498],"ENISA's SRP page"," for registration details)",[91,1898,1899],{},"Notifications must be submitted via the platform, not via email to national CSIRTs",[91,1901,1902],{},"ENISA will route relevant information to the appropriate national CSIRT based on the manufacturer's location and the affected member states",[91,1904,1905],{},"API access will be available for automated submission (important for manufacturers with large vulnerability volumes)",[11,1907,1908,1911],{},[31,1909,1910],{},"Action item:"," Register your organisation on the ENISA reporting platform before September 2026. Don't wait until you have a vulnerability to report—the registration process takes time, and you don't want to be figuring out the platform mechanics during a 24-hour incident response window.",[21,1913,1915],{"id":1914},"article-14-and-coordinated-vulnerability-disclosure","Article 14 and Coordinated Vulnerability Disclosure",[11,1917,1918],{},"Article 14 interacts with coordinated vulnerability disclosure (CVD) in ways that create tension for security researchers and manufacturers.",[11,1920,1921],{},"Article 14(1) requires manufacturers to notify users of the affected product \"without undue delay\" after becoming aware of a vulnerability—potentially before a public disclosure or patch is available. This is different from standard CVD practice, where disclosure timing is coordinated between the researcher and vendor.",[11,1923,1924],{},"Recital 97 provides some nuance: manufacturers should coordinate with ENISA when disclosure timing affects security. In practice:",[86,1926,1927,1930],{},[91,1928,1929],{},"For vulnerabilities reported via CVD with an agreed embargo: the 24-hour ENISA notification can happen under embargo (ENISA is not required to make it public immediately)",[91,1931,1932],{},"The 14-day final report triggers ENISA information-sharing with national CSIRTs, but not necessarily public disclosure",[11,1934,1935,1938],{},[31,1936,1937],{},"For manufacturers operating a bug bounty or VDP:"," Your programme rules should explicitly mention CRA reporting obligations. Security researchers need to understand that disclosures to you trigger regulatory timelines.",[21,1940,1942],{"id":1941},"the-cvd-policy-requirement-annex-i-part-ii","The CVD Policy Requirement (Annex I, Part II)",[11,1944,1945,1946,1949],{},"Separate from but related to Article 14, Annex I Part II requires manufacturers to have a ",[31,1947,1948],{},"coordinated vulnerability disclosure policy"," as part of the essential requirements. This is distinct from the Article 14 reporting obligation.",[11,1951,1952],{},"Your CVD policy must:",[86,1954,1955,1961,1964,1967],{},[91,1956,1957,1958,1960],{},"Define a contact point for receiving vulnerability reports (e.g., ",[102,1959,889],{"href":888},", published in security.txt)",[91,1962,1963],{},"Describe the process for receiving, triaging, and handling reports",[91,1965,1966],{},"Set expectations for response timelines and researcher communication",[91,1968,1969],{},"Define your disclosure timeline and process",[11,1971,1972],{},[31,1973,1974],{},"Minimum viable CVD policy for small embedded teams:",[86,1976,1977,1983,1989,1992,1995],{},[91,1978,1979,1980,1982],{},"Publish a security.txt file at ",[377,1981,878],{}," pointing to your security contact",[91,1984,1985,1986,1988],{},"Maintain a monitored ",[102,1987,889],{"href":888}," inbox",[91,1990,1991],{},"Commit to acknowledging reports within 5 business days",[91,1993,1994],{},"Define a 90-day default disclosure timeline (aligned with industry norm)",[91,1996,1997],{},"Document the CVD policy on your product's security documentation page",[11,1999,2000],{},"The CVD policy must be published and accessible — it's part of the technical documentation reviewable by market surveillance authorities.",[21,2002,2004],{"id":2003},"setting-up-a-minimum-viable-psirt","Setting Up a Minimum Viable PSIRT",[11,2006,2007],{},"PSIRT stands for Product Security Incident Response Team. For large companies, this is a dedicated team. For small embedded product companies, it can be one or two people with defined responsibilities and documented processes.",[11,2009,2010],{},"The CRA doesn't use the term \"PSIRT,\" but the obligations in Article 14 and Annex I Part II effectively require PSIRT-equivalent capabilities.",[45,2012,2014],{"id":2013},"minimum-viable-psirt-for-a-1050-person-embedded-team","Minimum Viable PSIRT for a 10–50 Person Embedded Team",[11,2016,2017],{},[31,2018,2019],{},"Roles (can be combined):",[86,2021,2022,2028,2034],{},[91,2023,2024,2027],{},[31,2025,2026],{},"PSIRT Lead (1 person):"," Owns the vulnerability management process, makes triage decisions, signs off on ENISA notifications. This should be a senior engineer or security-aware engineering manager.",[91,2029,2030,2033],{},[31,2031,2032],{},"PSIRT Analyst (1 person):"," Monitors CVE databases, triages incoming reports, prepares notification drafts. Can be a developer with security interest.",[91,2035,2036,2039],{},[31,2037,2038],{},"Legal/Compliance contact:"," Notified for all ENISA submissions. Not necessarily a FTE—can be an external counsel relationship.",[11,2041,2042],{},[31,2043,2044],{},"Tooling (minimum):",[86,2046,2047,2050,2053],{},[91,2048,2049],{},"CVE monitoring: Subscribe to NVD feeds for all OS/library packages in your firmware. Tools like OSV-Scanner, CVSS tools, or integration into your CI pipeline.",[91,2051,2052],{},"Ticketing: A dedicated queue (Jira security project, GitHub private security advisories, or similar) for vulnerability reports—separate from general bug tracking, with appropriate access controls.",[91,2054,2055],{},"Runbooks: Written procedures for the 24-hour, 72-hour, and 14-day ENISA notifications. These should be checklists, not essays.",[11,2057,2058],{},[31,2059,2060],{},"Process (minimum):",[1013,2062,2063,2069,2075,2081,2087,2093],{},[91,2064,2065,2068],{},[31,2066,2067],{},"Inbound monitoring:"," Daily CVE feed review for all components in shipping firmware",[91,2070,2071,2074],{},[31,2072,2073],{},"Triage SLA:"," 48-hour triage decision for any new CVE affecting your firmware (affected or not, exploitable or not)",[91,2076,2077,2080],{},[31,2078,2079],{},"Escalation trigger:"," Any CVE with CVSS ≥ 8.0 or any CVE marked exploited in CISA KEV or ENISA databases triggers immediate PSIRT Lead review",[91,2082,2083,2086],{},[31,2084,2085],{},"ENISA notification trigger:"," Evidence of active exploitation → immediate 24-hour clock start",[91,2088,2089,2092],{},[31,2090,2091],{},"Patch SLA:"," Critical/actively-exploited vulnerabilities: patch within 30 days. High severity: 90 days. Medium/Low: next scheduled release.",[91,2094,2095,2098],{},[31,2096,2097],{},"Documentation:"," All triage decisions documented with rationale (needed for technical documentation file)",[45,2100,2102],{"id":2101},"the-end-of-life-security-update-obligation","The End-of-Life Security Update Obligation",[11,2104,2105],{},"Article 14(4) and Annex I Part II require manufacturers to deliver security updates for a period appropriate to the expected product lifetime. This is a standing obligation, not time-limited.",[11,2107,2108],{},"For firmware teams, \"deliver\" means:",[86,2110,2111,2118,2121],{},[91,2112,2113,2114,2117],{},"Having an OTA update mechanism (or documented manual update procedure) — see our guide on ",[102,2115,2116],{"href":220},"CRA-compliant OTA firmware updates"," for implementation details",[91,2119,2120],{},"Publishing security advisories with each security update",[91,2122,2123],{},"Maintaining a record of all security updates delivered",[11,2125,2126],{},"There is no prescribed minimum support lifetime in the CRA text itself, but market surveillance authorities will compare your stated support period against the \"expected product lifetime\" for your product category. For consumer IoT: 5 years is becoming a market norm. For industrial products: 10+ years is expected.",[21,2128,2130],{"id":2129},"article-64-fine-exposure","Article 64: Fine Exposure",[11,2132,2133],{},"Article 64 sets the penalty regime. Violations of the Article 14 vulnerability reporting obligations fall under Article 64(2), the same tier as Annex I essential requirements violations:",[86,2135,2136],{},[91,2137,2138,2141],{},[31,2139,2140],{},"Maximum fine:"," €15 million or 2.5% of worldwide annual turnover, whichever is higher",[11,2143,2144],{},"This is the highest fine tier in the CRA. Failure to notify ENISA is a discoverable, binary fact—if you didn't submit the notification, there's no ambiguity. The lower fine tier under Article 64(3) — €10 million or 2% of turnover — applies to violations of other obligations such as those in Articles 18–23, 28, and 30–33, but not to Article 14.",[11,2146,2147],{},"The September 2026 reporting deadline gives you limited time. Start building your PSIRT capability now, register on the ENISA platform before it goes live, and put your CVD policy in place this quarter.",[11,2149,2150,2151,2153],{},"The ",[102,2152,1475],{"href":1474}," will assess your current vulnerability handling practices and identify specific gaps against the Article 14 and Annex I requirements.",[1478,2155],{},[11,2157,2158],{},[1483,2159,2160],{},"Based on Regulation EU 2024/2847, Article 14, Article 64, Annex I Part II, and ENISA vulnerability reporting guidance (2025). This does not constitute legal advice. Consult qualified legal counsel for compliance decisions.",[21,2162,1489],{"id":1488},[86,2164,2165,2170,2176,2182,2189],{},[91,2166,2167],{},[102,2168,1499],{"href":1496,"rel":2169},[1498],[91,2171,2172],{},[102,2173,2175],{"href":1504,"rel":2174},[1498],"CRA full text (HTML) — see Article 14, Article 64",[91,2177,2178],{},[102,2179,2181],{"href":1893,"rel":2180},[1498],"ENISA Single Reporting Platform (SRP)",[91,2183,2184],{},[102,2185,2188],{"href":2186,"rel":2187},"https://digital-strategy.ec.europa.eu/en/policies/cra-reporting",[1498],"European Commission — CRA reporting obligations",[91,2190,2191],{},[102,2192,2195],{"href":2193,"rel":2194},"https://www.enisa.europa.eu/news/stepping-up-our-role-in-vulnerability-management-enisa-becomes-cve-root",[1498],"ENISA — Stepping up Vulnerability Management: ENISA becomes CVE Root",{"title":1536,"searchDepth":1537,"depth":1537,"links":2197},[2198,2204,2207,2208,2209,2210,2214,2215],{"id":1616,"depth":1537,"text":1617,"children":2199},[2200,2201,2202,2203],{"id":1629,"depth":1542,"text":1630},{"id":1667,"depth":1542,"text":1668},{"id":1705,"depth":1542,"text":1706},{"id":1743,"depth":1542,"text":1744},{"id":1779,"depth":1537,"text":1780,"children":2205},[2206],{"id":1831,"depth":1542,"text":1832},{"id":1874,"depth":1537,"text":1875},{"id":1914,"depth":1537,"text":1915},{"id":1941,"depth":1537,"text":1942},{"id":2003,"depth":1537,"text":2004,"children":2211},[2212,2213],{"id":2013,"depth":1542,"text":2014},{"id":2101,"depth":1542,"text":2102},{"id":2129,"depth":1537,"text":2130},{"id":1488,"depth":1537,"text":1489},"2026-03-19","CRA Article 14 vulnerability reporting: 24-hour, 72-hour, and 14-day deadlines explained, plus how to set up a minimum viable PSIRT for embedded teams.","/images/blog/previews/article-14.svg",[2220,2221,2222,2223,2224,1435,2225],"CRA Article 14","vulnerability reporting","CRA vulnerability disclosure","ENISA reporting","PSIRT","CRA compliance",{},"/blog/cra-article-14-vulnerability-reporting","10 min",{"title":1594,"description":2217},"blog/cra-article-14-vulnerability-reporting","oqIAWcOFvAyjgPiX7c7R2J45-im8i_cm5baY7bQH450",{"id":2233,"title":2234,"body":2235,"date":3199,"description":3200,"extension":1577,"image":3201,"keywords":3202,"meta":3209,"navigation":98,"path":3210,"readTime":3211,"seo":3212,"stem":3213,"__hash__":3214},"blog/blog/cra-compliance-zephyr-rtos.md","CRA Compliance for Zephyr RTOS Projects",{"type":8,"value":2236,"toc":3182},[2237,2240,2243,2249,2253,2256,2288,2291,2295,2297,2302,2315,2323,2327,2330,2338,2343,2346,2354,2357,2366,2372,2377,2385,2390,2393,2397,2416,2419,2425,2435,2440,2448,2453,2465,2470,2478,2482,2498,2503,2515,2520,2528,2533,2536,2540,2545,2552,2558,2561,2599,2608,2613,2621,2627,2632,2637,2641,2645,2648,2662,2666,2669,2673,2676,2747,2750,2754,2764,2768,2771,2782,2786,2791,2827,2832,2868,2873,2899,2904,2931,2935,2962,2966,2996,3001,3034,3038,3043,3057,3062,3076,3081,3095,3100,3120,3125,3127,3132,3134],[11,2238,2239],{},"Zephyr is the RTOS with the richest built-in security ecosystem in the embedded world. MCUboot for secure boot, Mbed TLS for cryptography and TLS, PSA Crypto API support, MPU-based memory isolation, and MCUmgr for device management — these aren't third-party add-ons; they're part of the project.",[11,2241,2242],{},"For CRA compliance, this is both an advantage and a trap. The advantage: many Annex I requirements can be met with features Zephyr already provides. The trap: having the features available doesn't mean they're configured, enabled, or documented in a way that satisfies the regulation. And there are genuine gaps where Zephyr's ecosystem doesn't cover the CRA requirement at all.",[11,2244,2245,2246,1603],{},"This post maps every relevant Annex I requirement to Zephyr features, identifies the gaps, and provides a Zephyr-specific compliance checklist. Using FreeRTOS instead? See our ",[102,2247,2248],{"href":608},"FreeRTOS CRA compliance guide",[21,2250,2252],{"id":2251},"why-zephyrs-security-posture-matters","Why Zephyr's Security Posture Matters",[11,2254,2255],{},"Zephyr has invested more in built-in security than any other MCU-class RTOS:",[86,2257,2258,2264,2270,2276,2282],{},[91,2259,2260,2263],{},[31,2261,2262],{},"MCUboot integration"," is first-class — Zephyr's build system generates MCUboot-compatible images natively",[91,2265,2266,2269],{},[31,2267,2268],{},"Mbed TLS"," is the default TLS library, with PSA Crypto API support",[91,2271,2272,2275],{},[31,2273,2274],{},"MPU support"," across Cortex-M, RISC-V, and other architectures provides hardware memory isolation",[91,2277,2278,2281],{},[31,2279,2280],{},"MCUmgr"," provides a device management protocol for firmware updates via BLE, UART, or UDP",[91,2283,2284,2287],{},[31,2285,2286],{},"West manifest"," tracks all project dependencies with exact revisions",[11,2289,2290],{},"But Zephyr is a framework, not a product. The security features need to be configured, tested, and documented for your specific product. CRA compliance is about what your product does, not what the RTOS it's built on is capable of.",[21,2292,2294],{"id":2293},"annex-i-mapping-to-zephyr-features","Annex I Mapping to Zephyr Features",[45,2296,69],{"id":68},[11,2298,2299],{},[31,2300,2301],{},"Requirement 1 — Appropriate cybersecurity level (threat model)",[11,2303,2304,2305,2310,2311,2314],{},"Zephyr doesn't provide a threat model for your product — that's your responsibility. However, Zephyr's own ",[102,2306,2309],{"href":2307,"rel":2308},"https://docs.zephyrproject.org/latest/security/",[1498],"security documentation"," and threat model can serve as a starting point for the RTOS layer of your product's threat model. See our ",[102,2312,2313],{"href":104},"CRA threat modeling guide"," for the full approach.",[86,2316,2317,2320],{},[91,2318,2319],{},"Zephyr provides: Documented security architecture, security-focused development process",[91,2321,2322],{},"You still need: Product-specific threat model, risk assessment",[11,2324,2325],{},[31,2326,131],{},[11,2328,2329],{},"Zephyr has an active CVE process and publishes security advisories. But you're responsible for monitoring and patching.",[86,2331,2332,2335],{},[91,2333,2334],{},"Zephyr provides: CVE tracking, security advisories, regular releases with fixes",[91,2336,2337],{},"You still need: CVE monitoring for your specific Zephyr version and configuration, VEX triage for all components in your build, update mechanism to deliver patches",[11,2339,2340],{},[31,2341,2342],{},"Requirement 3 — Integrity protection (secure boot, signed updates)",[11,2344,2345],{},"This is where Zephyr shines. MCUboot integration is mature and well-documented.",[86,2347,2348,2351],{},[91,2349,2350],{},"Zephyr provides: MCUboot as the default bootloader with support for Ed25519, ECDSA P-256, and RSA signing algorithms, image swap and revert, hardware key storage integration for supported platforms",[91,2352,2353],{},"You still need: Key management infrastructure (HSM/KMS for signing keys), anti-rollback configuration (MCUboot supports it but it needs platform-specific counter support), production key provisioning process",[11,2355,2356],{},"Kconfig options to enable:",[2358,2359,2364],"pre",{"className":2360,"code":2362,"language":2363},[2361],"language-text","# In your prj.conf or board overlay\nCONFIG_BOOTLOADER_MCUBOOT=y\nCONFIG_MCUBOOT_SIGNATURE_KEY_FILE=\"path/to/your/signing-key.pem\"\n\n# In MCUboot's prj.conf\nCONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y  # or ED25519, RSA\nCONFIG_BOOT_SWAP_USING_MOVE=y             # Preferred over scratch-based swap\nCONFIG_BOOT_UPGRADE_ONLY=n                # Allow revert on failure\n","text",[377,2365,2362],{"__ignoreMap":1536},[11,2367,1176,2368,2371],{},[102,2369,2370],{"href":209},"secure boot guide"," for the full pipeline.",[11,2373,2374],{},[31,2375,2376],{},"Requirement 4 — Confidentiality (encryption)",[86,2378,2379,2382],{},[91,2380,2381],{},"Zephyr provides: Mbed TLS for TLS/DTLS, PSA Crypto API for key management and cryptographic operations, hardware crypto acceleration on supported MCUs (STM32, nRF, NXP)",[91,2383,2384],{},"You still need: Secure key storage configuration (depends on your MCU — TrustZone, secure element, or software-emulated), encryption of data at rest in external flash (Zephyr doesn't provide this out of the box)",[11,2386,2387],{},[31,2388,2389],{},"Requirement 5 — Data minimisation",[11,2391,2392],{},"Not an RTOS concern — this is about your application's data collection practices.",[11,2394,2395],{},[31,2396,333],{},[86,2398,2399,2413],{},[91,2400,2401,2402,2405,2406,2409,2410,879],{},"Zephyr provides: Kconfig-based build — only compiled features are included, MPU configuration for memory isolation (",[377,2403,2404],{},"CONFIG_USERSPACE=y","), stack canaries and overflow detection (",[377,2407,2408],{},"CONFIG_STACK_SENTINEL=y"," or ",[377,2411,2412],{},"CONFIG_HW_STACK_PROTECTION=y",[91,2414,2415],{},"You still need: JTAG/SWD disable in production (board-level Kconfig or OTP configuration), audit of enabled Kconfig options to remove unnecessary features, network stack hardening (disable unused protocols)",[11,2417,2418],{},"Key Kconfig options for hardening:",[2358,2420,2423],{"className":2421,"code":2422,"language":2363},[2361],"CONFIG_HW_STACK_PROTECTION=y\nCONFIG_STACK_SENTINEL=y\nCONFIG_USERSPACE=y           # MPU-based isolation\nCONFIG_STACK_CANARIES=y\nCONFIG_FORTIFY_SOURCE=y\n",[377,2424,2422],{"__ignoreMap":1536},[11,2426,2427,2430,2431,2434],{},[31,2428,2429],{},"JTAG/SWD disable:"," This is platform-specific. For nRF devices, use ",[377,2432,2433],{},"CONFIG_NRF_APPROTECT_LOCK=y",". For STM32, RDP Level 2 is set outside Zephyr (via STM32CubeProgrammer or OTP configuration). Document which mechanism you use.",[11,2436,2437],{},[31,2438,2439],{},"Requirement 7 — Secure defaults",[86,2441,2442,2445],{},[91,2443,2444],{},"Zephyr provides: No default credentials in the RTOS itself",[91,2446,2447],{},"You still need: Ensure your application doesn't ship with default passwords or hardcoded credentials, first-boot provisioning flow that forces credential setup, disable unnecessary services by default in your application",[11,2449,2450],{},[31,2451,2452],{},"Requirement 8 — Access control",[86,2454,2455,2462],{},[91,2456,2457,2458,2461],{},"Zephyr provides: Userspace/kernel separation via MPU (",[377,2459,2460],{},"CONFIG_USERSPACE","), system call interface for controlled kernel access",[91,2463,2464],{},"You still need: Application-level authentication for remote interfaces, role-based access if your product has multiple user levels",[11,2466,2467],{},[31,2468,2469],{},"Requirement 9 — Availability / resilience",[86,2471,2472,2475],{},[91,2473,2474],{},"Zephyr provides: Hardware watchdog support, thread priority management, kernel-level resource management",[91,2476,2477],{},"You still need: Watchdog configuration in your application, network stack DoS resilience testing, resource limit configuration for connections and buffers",[11,2479,2480],{},[31,2481,548],{},[86,2483,2484,2487],{},[91,2485,2486],{},"Zephyr provides: Mbed TLS for TLS 1.2/1.3 and DTLS 1.2, CoAP library with DTLS support, Bluetooth encryption (LE Secure Connections)",[91,2488,2489,2490,2493,2494,2497],{},"You still need: TLS/DTLS configuration with strong cipher suites (disable weak ciphers), server certificate verification (don't set ",[377,2491,2492],{},"mbedtls_ssl_conf_authmode"," to ",[377,2495,2496],{},"MBEDTLS_SSL_VERIFY_NONE","), certificate or PSK provisioning for your device fleet",[11,2499,2500],{},[31,2501,2502],{},"Requirement 11 — Security event logging",[86,2504,2505,2512],{},[91,2506,2507,2508,2511],{},"Zephyr provides: Logging subsystem (",[377,2509,2510],{},"CONFIG_LOG=y",") with multiple backends (UART, RTT, flash)",[91,2513,2514],{},"You still need: Define which events are security-relevant for your product, configure log persistence (Zephyr logs are volatile by default), tamper protection for stored logs",[11,2516,2517],{},[31,2518,2519],{},"Requirement 12 — Secure data deletion",[86,2521,2522,2525],{},[91,2523,2524],{},"Zephyr provides: Flash erase APIs",[91,2526,2527],{},"You still need: Factory reset implementation that securely erases user data, keys, and configuration, verification that erase actually clears data (not just marks sectors as available)",[11,2529,2530],{},[31,2531,2532],{},"Requirement 13 — User notification",[11,2534,2535],{},"Not an RTOS feature — depends on your product's user interface (companion app, web dashboard, LED indicators).",[45,2537,2539],{"id":2538},"part-ii-vulnerability-handling","Part II: Vulnerability Handling",[11,2541,2542],{},[31,2543,2544],{},"VH1 — SBOM",[11,2546,2547,2548,2551],{},"Zephyr has a built-in SBOM generation command: ",[377,2549,2550],{},"west spdx",". Run it after any build, and it produces SPDX 2.3 documents covering the source files and libraries that were actually compiled. This is more than most RTOSes offer.",[11,2553,2554,2555,2557],{},"However, the raw ",[377,2556,2550],{}," output isn't CRA-compliant on its own. It lacks CPE/PURL identifiers (so vulnerability scanners can't match components to CVEs), rolls subsystem components like Bluetooth and MQTT into the kernel package instead of listing them individually, and can't see inside vendor HAL binary blobs.",[11,2559,2560],{},"Making the output useful requires an enrichment workflow:",[1013,2562,2563,2571,2577,2583,2593],{},[91,2564,2565,2570],{},[31,2566,2567,2568],{},"Run ",[377,2569,2550],{}," to generate the base SPDX documents from your build",[91,2572,2573,2576],{},[31,2574,2575],{},"Add CPE/PURL identifiers"," to every package so scanners can match against NVD and OSV",[91,2578,2579,2582],{},[31,2580,2581],{},"Add invisible components"," (Bluetooth stack, MQTT, cJSON) that are compiled in but not listed as discrete packages",[91,2584,2585,2588,2589,2592],{},[31,2586,2587],{},"Document binary blobs"," from vendor HALs with available version info and ",[377,2590,2591],{},"NOASSERTION"," for opaque contents",[91,2594,2595,2598],{},[31,2596,2597],{},"Merge the four SPDX files"," into a single document for submission and scanning",[11,2600,1176,2601,2605,2606,1603],{},[102,2602,2604],{"href":2603},"/blog/zephyr-sbom-cra-compliance/","step-by-step Zephyr SBOM tutorial"," for the full enrichment workflow, including scripting CPE/PURL additions, CI/CD integration, and CycloneDX conversion. For broader SBOM context, see our ",[102,2607,1022],{"href":152},[11,2609,2610],{},[31,2611,2612],{},"VH2 — Security update delivery",[86,2614,2615,2618],{},[91,2616,2617],{},"Zephyr provides: MCUmgr for BLE/UART/UDP device management including firmware upload, MCUboot for A/B updates with revert",[91,2619,2620],{},"You still need: Update server infrastructure, fleet management, staged rollout capability",[11,2622,2623,2624,1603],{},"MCUmgr provides the on-device update mechanism, but fleet-scale OTA requires additional infrastructure. See our ",[102,2625,2626],{"href":220},"OTA updates guide",[11,2628,2629],{},[31,2630,2631],{},"VH3–VH8 — Vulnerability handling processes",[11,2633,2634,2635,1603],{},"These are organisational requirements, not RTOS features. You need a PSIRT, CVD policy, ENISA registration, and patch management process regardless of your RTOS choice. See our ",[102,2636,1055],{"href":911},[21,2638,2640],{"id":2639},"gaps-in-zephyrs-cra-readiness","Gaps in Zephyr's CRA Readiness",[45,2642,2644],{"id":2643},"_1-no-built-in-fleet-management","1. No Built-In Fleet Management",[11,2646,2647],{},"MCUmgr handles the on-device side of firmware updates, but there's no Zephyr-provided server component for managing updates across a fleet of devices. You need to build or adopt:",[86,2649,2650,2653,2656,2659],{},[91,2651,2652],{},"Update server (hawkBit, custom, or cloud IoT platform)",[91,2654,2655],{},"Device registration and inventory",[91,2657,2658],{},"Update targeting and staged rollout",[91,2660,2661],{},"Update status tracking",[45,2663,2665],{"id":2664},"_2-anti-rollback-requires-platform-support","2. Anti-Rollback Requires Platform Support",[11,2667,2668],{},"MCUboot supports anti-rollback via a monotonic counter, but the actual counter implementation depends on the hardware platform. Not all Zephyr-supported boards have this configured. You need to verify that your specific MCU and board configuration supports hardware-backed monotonic counters, or implement a flash-based counter with integrity protection.",[45,2670,2672],{"id":2671},"_3-secure-storage-varies-by-platform","3. Secure Storage Varies by Platform",[11,2674,2675],{},"Zephyr's trusted storage story depends heavily on the MCU:",[1097,2677,2678,2691],{},[1100,2679,2680],{},[1103,2681,2682,2685,2688],{},[1106,2683,2684],{},"Platform",[1106,2686,2687],{},"Secure storage mechanism",[1106,2689,2690],{},"Maturity in Zephyr",[1119,2692,2693,2704,2715,2725,2736],{},[1103,2694,2695,2698,2701],{},[1124,2696,2697],{},"nRF91/nRF5340",[1124,2699,2700],{},"TrustZone + KMU",[1124,2702,2703],{},"Good — SPE/NSPE split well-supported",[1103,2705,2706,2709,2712],{},[1124,2707,2708],{},"STM32L5/U5",[1124,2710,2711],{},"TrustZone + OTFDEC",[1124,2713,2714],{},"Moderate — TF-M integration available",[1103,2716,2717,2720,2723],{},[1124,2718,2719],{},"NXP LPC55S",[1124,2721,2722],{},"TrustZone + PUF",[1124,2724,2714],{},[1103,2726,2727,2730,2733],{},[1124,2728,2729],{},"ESP32",[1124,2731,2732],{},"Flash encryption + secure boot (ESP-IDF, not Zephyr-native)",[1124,2734,2735],{},"Limited — ESP32 Zephyr support is less mature for security features",[1103,2737,2738,2741,2744],{},[1124,2739,2740],{},"Generic Cortex-M4 (no TrustZone)",[1124,2742,2743],{},"Software-only, MPU isolation",[1124,2745,2746],{},"Weak — no hardware-backed secret storage",[11,2748,2749],{},"For MCUs without TrustZone or a secure element, you may need an external secure element (ATECC608, SE050) for CRA-compliant key storage.",[45,2751,2753],{"id":2752},"_4-sbom-tooling-requires-enrichment","4. SBOM Tooling Requires Enrichment",[11,2755,2756,2757,2759,2760,2763],{},"Zephyr's ",[377,2758,2550],{}," command generates SPDX documents, but the raw output lacks the CPE/PURL identifiers and component granularity needed for CRA-compliant vulnerability scanning. The tooling exists but requires a post-processing workflow to be useful. See our ",[102,2761,2762],{"href":2603},"Zephyr SBOM tutorial"," for the full enrichment process.",[45,2765,2767],{"id":2766},"_5-debug-interface-lockdown-is-board-specific","5. Debug Interface Lockdown Is Board-Specific",[11,2769,2770],{},"Disabling JTAG/SWD must be done per-board and per-MCU. Zephyr's Kconfig doesn't provide a universal \"disable debug interface\" option. You need to:",[86,2772,2773,2776,2779],{},[91,2774,2775],{},"Identify your MCU's debug disable mechanism (OTP fuse, register lock, AP disable)",[91,2777,2778],{},"Implement it in your board configuration or manufacturing provisioning",[91,2780,2781],{},"Document it in your technical documentation",[21,2783,2785],{"id":2784},"zephyr-specific-compliance-checklist","Zephyr-Specific Compliance Checklist",[11,2787,2788],{},[31,2789,2790],{},"Secure boot (MCUboot)",[86,2792,2794,2803,2809,2815,2821],{"className":2793},[89],[91,2795,2797,2799,2800,879],{"className":2796},[94],[96,2798],{"disabled":98,"type":99}," MCUboot enabled (",[377,2801,2802],{},"CONFIG_BOOTLOADER_MCUBOOT=y",[91,2804,2806,2808],{"className":2805},[94],[96,2807],{"disabled":98,"type":99}," Signing key generated and stored in HSM/KMS",[91,2810,2812,2814],{"className":2811},[94],[96,2813],{"disabled":98,"type":99}," Production images signed with production key (not the default development key)",[91,2816,2818,2820],{"className":2817},[94],[96,2819],{"disabled":98,"type":99}," Swap-based update with revert on failure",[91,2822,2824,2826],{"className":2823},[94],[96,2825],{"disabled":98,"type":99}," Anti-rollback counter configured for your platform",[11,2828,2829],{},[31,2830,2831],{},"Cryptography and TLS",[86,2833,2835,2841,2847,2853,2859],{"className":2834},[89],[91,2836,2838,2840],{"className":2837},[94],[96,2839],{"disabled":98,"type":99}," Mbed TLS configured with strong cipher suites only",[91,2842,2844,2846],{"className":2843},[94],[96,2845],{"disabled":98,"type":99}," TLS 1.2+ or DTLS 1.2+ for all network communications",[91,2848,2850,2852],{"className":2849},[94],[96,2851],{"disabled":98,"type":99}," Server certificate verification enabled",[91,2854,2856,2858],{"className":2855},[94],[96,2857],{"disabled":98,"type":99}," PSA Crypto API used for key management where supported",[91,2860,2862,2864,2865,879],{"className":2861},[94],[96,2863],{"disabled":98,"type":99}," Hardware crypto acceleration enabled (",[377,2866,2867],{},"CONFIG_MBEDTLS_PSA_CRYPTO_C=y",[11,2869,2870],{},[31,2871,2872],{},"Memory protection",[86,2874,2876,2885,2893],{"className":2875},[89],[91,2877,2879,2881,2882,2884],{"className":2878},[94],[96,2880],{"disabled":98,"type":99}," MPU enabled (",[377,2883,2404],{},") for applications with multiple privilege levels",[91,2886,2888,2890,2891,879],{"className":2887},[94],[96,2889],{"disabled":98,"type":99}," Stack protection enabled (",[377,2892,2412],{},[91,2894,2896,2898],{"className":2895},[94],[96,2897],{"disabled":98,"type":99}," Stack canaries or sentinels enabled",[11,2900,2901],{},[31,2902,2903],{},"Attack surface reduction",[86,2905,2907,2913,2919,2925],{"className":2906},[89],[91,2908,2910,2912],{"className":2909},[94],[96,2911],{"disabled":98,"type":99}," JTAG/SWD disabled in production builds",[91,2914,2916,2918],{"className":2915},[94],[96,2917],{"disabled":98,"type":99}," Unused Kconfig features disabled",[91,2920,2922,2924],{"className":2921},[94],[96,2923],{"disabled":98,"type":99}," Debug logging disabled or secured in production",[91,2926,2928,2930],{"className":2927},[94],[96,2929],{"disabled":98,"type":99}," Unused network protocols and services disabled",[11,2932,2933],{},[31,2934,1036],{},[86,2936,2938,2944,2950,2956],{"className":2937},[89],[91,2939,2941,2943],{"className":2940},[94],[96,2942],{"disabled":98,"type":99}," MCUmgr configured for firmware upload (BLE, UART, or UDP)",[91,2945,2947,2949],{"className":2946},[94],[96,2948],{"disabled":98,"type":99}," Update server infrastructure operational",[91,2951,2953,2955],{"className":2952},[94],[96,2954],{"disabled":98,"type":99}," Rollback tested and documented",[91,2957,2959,2961],{"className":2958},[94],[96,2960],{"disabled":98,"type":99}," Update signing key matches boot signing trust chain",[11,2963,2964],{},[31,2965,153],{},[86,2967,2969,2978,2984,2990],{"className":2968},[89],[91,2970,2972,784,2974,2977],{"className":2971},[94],[96,2973],{"disabled":98,"type":99},[377,2975,2976],{},"west.yml"," manifest parsed for all dependencies",[91,2979,2981,2983],{"className":2980},[94],[96,2982],{"disabled":98,"type":99}," CMake build output analysed for actual compiled components",[91,2985,2987,2989],{"className":2986},[94],[96,2988],{"disabled":98,"type":99}," SPDX or CycloneDX document generated per release",[91,2991,2993,2995],{"className":2992},[94],[96,2994],{"disabled":98,"type":99}," Binary blobs and external components documented",[11,2997,2998],{},[31,2999,3000],{},"Vulnerability management",[86,3002,3004,3010,3016,3022],{"className":3003},[89],[91,3005,3007,3009],{"className":3006},[94],[96,3008],{"disabled":98,"type":99}," Zephyr security advisory feed monitored",[91,3011,3013,3015],{"className":3012},[94],[96,3014],{"disabled":98,"type":99}," CVE monitoring for Mbed TLS, MCUboot, and all Zephyr modules",[91,3017,3019,3021],{"className":3018},[94],[96,3020],{"disabled":98,"type":99}," Patch/update process covers Zephyr upstream updates",[91,3023,3025,3027,3028,3030,3031,576],{"className":3024},[94],[96,3026],{"disabled":98,"type":99}," Zephyr version pinned in ",[377,3029,2976],{}," (not tracking ",[377,3032,3033],{},"main",[21,3035,3037],{"id":3036},"recommended-implementation-roadmap","Recommended Implementation Roadmap",[11,3039,3040],{},[31,3041,3042],{},"Phase 1 (Month 1–2): Foundation",[1013,3044,3045,3048,3051,3054],{},[91,3046,3047],{},"Enable MCUboot with proper signing (not development keys)",[91,3049,3050],{},"Enable MPU and stack protection",[91,3052,3053],{},"Disable JTAG/SWD in production board config",[91,3055,3056],{},"Generate initial SBOM from west manifest",[11,3058,3059],{},[31,3060,3061],{},"Phase 2 (Month 2–3): Communications and Updates",[1013,3063,3064,3067,3070,3073],{},[91,3065,3066],{},"Configure Mbed TLS with CRA-appropriate cipher suites",[91,3068,3069],{},"Set up MCUmgr for OTA updates",[91,3071,3072],{},"Implement update server infrastructure",[91,3074,3075],{},"Test and document rollback behaviour",[11,3077,3078],{},[31,3079,3080],{},"Phase 3 (Month 3–4): Vulnerability Handling",[1013,3082,3083,3086,3089,3092],{},[91,3084,3085],{},"Set up CVE monitoring for all Zephyr components",[91,3087,3088],{},"Establish PSIRT process and CVD policy",[91,3090,3091],{},"Register on ENISA reporting platform",[91,3093,3094],{},"Build VEX triage workflow",[11,3096,3097],{},[31,3098,3099],{},"Phase 4 (Month 4–5): Documentation and Testing",[1013,3101,3102,3107,3114,3117],{},[91,3103,3104,3105],{},"Conduct product ",[102,3106,105],{"href":104},[91,3108,3109,3110],{},"Run security testing against ",[102,3111,3113],{"href":3112},"/blog/cra-annex-i-essential-requirements-checklist/","Annex I requirements",[91,3115,3116],{},"Prepare Annex VII technical documentation",[91,3118,3119],{},"Prepare EU Declaration of Conformity",[11,3121,2150,3122,3124],{},[102,3123,1475],{"href":1474}," will identify your specific gaps and help prioritise your remediation roadmap based on your Zephyr project's current configuration.",[1478,3126],{},[11,3128,3129],{},[1483,3130,3131],{},"Based on Regulation EU 2024/2847 Annex I, Zephyr Project documentation (v3.7+), MCUboot documentation, Mbed TLS documentation, and PSA Certified specifications. This does not constitute legal advice.",[21,3133,1489],{"id":1488},[86,3135,3136,3141,3147,3154,3161,3168,3175],{},[91,3137,3138],{},[102,3139,1499],{"href":1496,"rel":3140},[1498],[91,3142,3143],{},[102,3144,3146],{"href":2307,"rel":3145},[1498],"Zephyr Project — Security documentation",[91,3148,3149],{},[102,3150,3153],{"href":3151,"rel":3152},"https://docs.zephyrproject.org/latest/develop/west/zephyr-cmds.html",[1498],"Zephyr Project — west spdx command",[91,3155,3156],{},[102,3157,3160],{"href":3158,"rel":3159},"https://docs.mcuboot.com/design.html",[1498],"MCUboot — Design documentation",[91,3162,3163],{},[102,3164,3167],{"href":3165,"rel":3166},"https://www.trustedfirmware.org/projects/mbed-tls/",[1498],"Mbed TLS — Documentation",[91,3169,3170],{},[102,3171,3174],{"href":3172,"rel":3173},"https://www.psacertified.org/getting-started/specifications/",[1498],"PSA Certified — Specifications",[91,3176,3177],{},[102,3178,3181],{"href":3179,"rel":3180},"https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/security/index.html",[1498],"Nordic Semiconductor — nRF Connect SDK security",{"title":1536,"searchDepth":1537,"depth":1537,"links":3183},[3184,3185,3189,3196,3197,3198],{"id":2251,"depth":1537,"text":2252},{"id":2293,"depth":1537,"text":2294,"children":3186},[3187,3188],{"id":68,"depth":1542,"text":69},{"id":2538,"depth":1542,"text":2539},{"id":2639,"depth":1537,"text":2640,"children":3190},[3191,3192,3193,3194,3195],{"id":2643,"depth":1542,"text":2644},{"id":2664,"depth":1542,"text":2665},{"id":2671,"depth":1542,"text":2672},{"id":2752,"depth":1542,"text":2753},{"id":2766,"depth":1542,"text":2767},{"id":2784,"depth":1537,"text":2785},{"id":3036,"depth":1537,"text":3037},{"id":1488,"depth":1537,"text":1489},"2026-03-05","Map CRA Annex I requirements to Zephyr's security ecosystem (MCUboot, Mbed TLS, PSA Crypto, MPU) and find the gaps you still need to build.","/images/blog/previews/zephyr-rtos.svg",[3203,3204,3205,3206,3207,3208],"CRA Zephyr RTOS","Zephyr CRA compliance","Cyber Resilience Act Zephyr","Zephyr RTOS security CRA","MCUboot CRA","Zephyr security",{},"/blog/cra-compliance-zephyr-rtos","13 min",{"title":2234,"description":3200},"blog/cra-compliance-zephyr-rtos","IT73m6bUOihX4cJH2kUrp6pcyrlnPY0V79AzTa6viS8",{"id":3216,"title":3217,"body":3218,"date":4315,"description":4316,"extension":1577,"image":4317,"keywords":4318,"meta":4324,"navigation":98,"path":4325,"readTime":3211,"seo":4326,"stem":4327,"__hash__":4328},"blog/blog/cra-compliance-freertos.md","CRA Compliance for FreeRTOS Firmware Projects",{"type":8,"value":3219,"toc":4300},[3220,3223,3226,3232,3236,3239,3243,3251,3268,3275,3298,3301,3305,3308,3352,3355,3359,3366,3392,3395,3400,3404,3406,3410,3415,3419,3457,3462,3467,3470,3541,3546,3550,3602,3607,3611,3623,3626,3630,3633,3637,3645,3649,3660,3664,3705,3710,3714,3717,3731,3737,3739,3743,3746,3752,3758,3775,3781,3786,3836,3841,3845,3853,3857,3860,3865,3891,3896,3922,3926,3929,3934,3948,3953,3967,3970,3974,3979,4016,4021,4056,4060,4086,4090,4123,4127,4157,4161,4200,4204,4238,4243,4245,4250,4252],[11,3221,3222],{},"FreeRTOS is the most widely deployed RTOS in the world. It runs on everything from temperature sensors to industrial controllers to consumer electronics. And its CRA compliance story is more complicated than any other RTOS — because \"FreeRTOS\" means different things depending on which variant and ecosystem you're using.",[11,3224,3225],{},"The vanilla FreeRTOS kernel gives you a task scheduler, memory management, and inter-task communication. That's it. No networking, no cryptography, no OTA updates, no secure boot. Everything else comes from libraries you choose to add — either AWS's FreeRTOS libraries, your MCU vendor's SDK, or open-source components you integrate yourself.",[11,3227,3228,3229,1603],{},"This means your CRA compliance posture depends almost entirely on what you've built on top of the kernel. This post maps the Annex I requirements to the various FreeRTOS variants and identifies what you need to build or adopt for each. Using Zephyr instead? See our ",[102,3230,3231],{"href":603},"Zephyr CRA compliance guide",[21,3233,3235],{"id":3234},"aws-freertos-vs-vanilla-freertos-kernel","AWS FreeRTOS vs. Vanilla FreeRTOS Kernel",[11,3237,3238],{},"This distinction matters enormously for CRA compliance:",[45,3240,3242],{"id":3241},"vanilla-freertos-kernel","Vanilla FreeRTOS Kernel",[11,3244,2150,3245,3250],{},[102,3246,3249],{"href":3247,"rel":3248},"https://github.com/FreeRTOS/FreeRTOS-Kernel",[1498],"FreeRTOS kernel"," (MIT licensed) provides:",[86,3252,3253,3256,3259,3262,3265],{},[91,3254,3255],{},"Pre-emptive and cooperative task scheduling",[91,3257,3258],{},"Binary and counting semaphores, mutexes, queues",[91,3260,3261],{},"Software timers",[91,3263,3264],{},"Memory management (heap_1 through heap_5)",[91,3266,3267],{},"MPU wrapper for Cortex-M (optional)",[11,3269,3270,3271,3274],{},"What the kernel does ",[31,3272,3273],{},"not"," provide:",[86,3276,3277,3280,3283,3286,3289,3292,3295],{},[91,3278,3279],{},"Networking (no TCP/IP, no TLS, no MQTT, no HTTP)",[91,3281,3282],{},"Cryptography (no AES, no RSA, no ECDSA, no hashing)",[91,3284,3285],{},"Secure boot (not a bootloader)",[91,3287,3288],{},"OTA updates (no update mechanism)",[91,3290,3291],{},"File system or persistent storage",[91,3293,3294],{},"SBOM generation tooling",[91,3296,3297],{},"Device management",[11,3299,3300],{},"For CRA compliance, the vanilla kernel alone covers almost none of the Annex I requirements. It's a scheduler. Everything security-relevant must come from additional components.",[45,3302,3304],{"id":3303},"aws-freertos-freertos-long-term-support","AWS FreeRTOS (FreeRTOS Long Term Support)",[11,3306,3307],{},"AWS provides a set of libraries designed to work with the FreeRTOS kernel and AWS IoT services:",[86,3309,3310,3316,3322,3328,3334,3340,3346],{},[91,3311,3312,3315],{},[31,3313,3314],{},"coreMQTT / coreMQTT-Agent:"," MQTT client with TLS support",[91,3317,3318,3321],{},[31,3319,3320],{},"coreHTTP:"," HTTP client",[91,3323,3324,3327],{},[31,3325,3326],{},"Mbed TLS (bundled):"," TLS and cryptographic operations",[91,3329,3330,3333],{},[31,3331,3332],{},"corePKCS11:"," Cryptographic key management interface",[91,3335,3336,3339],{},[31,3337,3338],{},"FreeRTOS OTA library:"," Over-the-air update client (works with AWS IoT Jobs)",[91,3341,3342,3345],{},[31,3343,3344],{},"FreeRTOS+TCP or lwIP:"," TCP/IP networking stacks",[91,3347,3348,3351],{},[31,3349,3350],{},"AWS IoT Device Shadow, Device Defender:"," Cloud device management",[11,3353,3354],{},"AWS FreeRTOS significantly improves the CRA compliance posture — but it ties you to the AWS IoT ecosystem, and many of the libraries only work well with AWS services.",[45,3356,3358],{"id":3357},"the-vendor-sdk-layer","The Vendor SDK Layer",[11,3360,3361,3362,3365],{},"Most real-world FreeRTOS projects don't use the vanilla kernel or pure AWS FreeRTOS. They use an ",[31,3363,3364],{},"MCU vendor SDK"," that bundles FreeRTOS with vendor-specific drivers, networking, and middleware:",[86,3367,3368,3374,3380,3386],{},[91,3369,3370,3373],{},[31,3371,3372],{},"STM32Cube + FreeRTOS:"," STM32 HAL, FreeRTOS kernel, optionally lwIP, mbedTLS, SBSFU bootloader",[91,3375,3376,3379],{},[31,3377,3378],{},"ESP-IDF (FreeRTOS-based):"," ESP-IDF uses a modified FreeRTOS kernel with ESP32-specific additions (SMP support, IPC), plus networking, TLS, OTA, and secure boot",[91,3381,3382,3385],{},[31,3383,3384],{},"NXP MCUXpresso SDK + FreeRTOS:"," NXP drivers, FreeRTOS kernel, lwIP, mbedTLS, optional AWS libraries",[91,3387,3388,3391],{},[31,3389,3390],{},"TI SimpleLink SDK + FreeRTOS:"," TI drivers, FreeRTOS kernel, TI networking stack, TLS",[11,3393,3394],{},"Each vendor SDK has a different security posture. The FreeRTOS kernel is the same across all of them, but the security-relevant components (TLS, bootloader, OTA, key storage) vary significantly.",[11,3396,3397],{},[31,3398,3399],{},"For CRA compliance: your SBOM, vulnerability tracking, and security assessment must cover the vendor SDK as a whole, not just the FreeRTOS kernel.",[21,3401,3403],{"id":3402},"annex-i-mapping-to-freertos-variants","Annex I Mapping to FreeRTOS Variants",[45,3405,69],{"id":68},[11,3407,3408],{},[31,3409,2301],{},[11,3411,3412,3413,1603],{},"None of the FreeRTOS variants provide a product threat model. This is your responsibility. See our ",[102,3414,2313],{"href":104},[11,3416,3417],{},[31,3418,131],{},[1097,3420,3421,3431],{},[1100,3422,3423],{},[1103,3424,3425,3428],{},[1106,3426,3427],{},"Variant",[1106,3429,3430],{},"CVE tracking",[1119,3432,3433,3441,3449],{},[1103,3434,3435,3438],{},[1124,3436,3437],{},"Vanilla kernel",[1124,3439,3440],{},"FreeRTOS project publishes advisories; few CVEs (kernel is small and well-audited)",[1103,3442,3443,3446],{},[1124,3444,3445],{},"AWS FreeRTOS libraries",[1124,3447,3448],{},"AWS publishes advisories; coreMQTT, coreHTTP, etc. have their own CVE tracking",[1103,3450,3451,3454],{},[1124,3452,3453],{},"Vendor SDKs",[1124,3455,3456],{},"Vendor-specific advisory process (ST, Espressif, NXP, TI each have their own)",[86,3458,3459],{},[91,3460,3461],{},"You still need: Monitoring for all three layers (kernel + libraries + vendor SDK), VEX triage process, and a way to patch across all three layers. The vendor SDK layer is typically the hardest to patch quickly.",[11,3463,3464],{},[31,3465,3466],{},"Requirement 3 — Integrity protection (secure boot)",[11,3468,3469],{},"FreeRTOS does not include a bootloader. Secure boot is entirely dependent on your MCU platform:",[1097,3471,3472,3485],{},[1100,3473,3474],{},[1103,3475,3476,3479,3482],{},[1106,3477,3478],{},"MCU Platform",[1106,3480,3481],{},"Secure boot option",[1106,3483,3484],{},"FreeRTOS integration",[1119,3486,3487,3498,3508,3519,3530],{},[1103,3488,3489,3492,3495],{},[1124,3490,3491],{},"STM32",[1124,3493,3494],{},"SBSFU or MCUboot",[1124,3496,3497],{},"SBSFU integrates with STM32Cube FreeRTOS projects; MCUboot can be used independently",[1103,3499,3500,3502,3505],{},[1124,3501,2729],{},[1124,3503,3504],{},"ESP-IDF Secure Boot V2",[1124,3506,3507],{},"Built into ESP-IDF (which uses FreeRTOS kernel internally)",[1103,3509,3510,3513,3516],{},[1124,3511,3512],{},"NXP i.MX RT",[1124,3514,3515],{},"HAB (High Assurance Boot)",[1124,3517,3518],{},"Independent of RTOS; operates at ROM level",[1103,3520,3521,3524,3527],{},[1124,3522,3523],{},"Nordic nRF",[1124,3525,3526],{},"NSIB + MCUboot",[1124,3528,3529],{},"Via nRF Connect SDK (which supports FreeRTOS as an alternative to Zephyr)",[1103,3531,3532,3535,3538],{},[1124,3533,3534],{},"TI CC32xx",[1124,3536,3537],{},"Built-in secure boot",[1124,3539,3540],{},"Part of SimpleLink ROM; independent of RTOS",[11,3542,1176,3543,3545],{},[102,3544,2370],{"href":209}," for implementation details per platform.",[11,3547,3548],{},[31,3549,2376],{},[1097,3551,3552,3561],{},[1100,3553,3554],{},[1103,3555,3556,3558],{},[1106,3557,3427],{},[1106,3559,3560],{},"Crypto / TLS support",[1119,3562,3563,3570,3578,3586,3594],{},[1103,3564,3565,3567],{},[1124,3566,3437],{},[1124,3568,3569],{},"None — you must add a crypto library",[1103,3571,3572,3575],{},[1124,3573,3574],{},"AWS FreeRTOS",[1124,3576,3577],{},"Mbed TLS (bundled), corePKCS11 for key management",[1103,3579,3580,3583],{},[1124,3581,3582],{},"STM32Cube",[1124,3584,3585],{},"mbedTLS available via STM32Cube package",[1103,3587,3588,3591],{},[1124,3589,3590],{},"ESP-IDF",[1124,3592,3593],{},"mbedTLS bundled, hardware crypto acceleration",[1103,3595,3596,3599],{},[1124,3597,3598],{},"NXP MCUXpresso",[1124,3600,3601],{},"mbedTLS, hardware crypto via CASPER/DCP",[86,3603,3604],{},[91,3605,3606],{},"You still need: Secure key storage (depends on MCU — TrustZone, secure element, or PUF), encryption of data at rest (no FreeRTOS variant provides this out of the box)",[11,3608,3609],{},[31,3610,333],{},[86,3612,3613,3620],{},[91,3614,3615,3616,3619],{},"FreeRTOS kernel provides: MPU wrapper (",[377,3617,3618],{},"CONFIG_USE_MPU_WRAPPERS",") for Cortex-M memory isolation",[91,3621,3622],{},"You still need: MPU configuration for your application's task isolation, JTAG/SWD disable (MCU-specific, not RTOS), disabled unused services and protocols, compiler hardening flags",[11,3624,3625],{},"The FreeRTOS MPU wrapper is less mature than Zephyr's userspace isolation. It provides basic task memory isolation but requires careful manual configuration of MPU regions per task.",[11,3627,3628],{},[31,3629,2439],{},[11,3631,3632],{},"Not an RTOS concern — this is about your application's default configuration.",[11,3634,3635],{},[31,3636,2452],{},[86,3638,3639,3642],{},[91,3640,3641],{},"FreeRTOS kernel provides: MPU wrapper for kernel/user task separation",[91,3643,3644],{},"You still need: Application-level authentication, network service access control",[11,3646,3647],{},[31,3648,2469],{},[86,3650,3651,3657],{},[91,3652,3653,3654,879],{},"FreeRTOS kernel provides: Task watchdog (via software timer), stack overflow detection (",[377,3655,3656],{},"configCHECK_FOR_STACK_OVERFLOW",[91,3658,3659],{},"You still need: Hardware watchdog configuration, network DoS resilience testing, resource limits for connections and buffers",[11,3661,3662],{},[31,3663,548],{},[1097,3665,3666,3675],{},[1100,3667,3668],{},[1103,3669,3670,3672],{},[1106,3671,3427],{},[1106,3673,3674],{},"TLS/DTLS support",[1119,3676,3677,3684,3691,3698],{},[1103,3678,3679,3681],{},[1124,3680,3437],{},[1124,3682,3683],{},"None",[1103,3685,3686,3688],{},[1124,3687,3574],{},[1124,3689,3690],{},"Mbed TLS with TLS 1.2, MQTT over TLS",[1103,3692,3693,3695],{},[1124,3694,3590],{},[1124,3696,3697],{},"Mbed TLS with TLS 1.2/1.3, DTLS",[1103,3699,3700,3702],{},[1124,3701,3582],{},[1124,3703,3704],{},"mbedTLS with TLS 1.2",[86,3706,3707],{},[91,3708,3709],{},"You still need: Strong cipher suite configuration, server certificate verification, certificate provisioning for your device fleet",[11,3711,3712],{},[31,3713,2502],{},[11,3715,3716],{},"FreeRTOS doesn't include a logging framework. You need to implement or adopt one. Options:",[86,3718,3719,3722,3725],{},[91,3720,3721],{},"AWS IoT Device Defender provides security metrics reporting (AWS ecosystem only)",[91,3723,3724],{},"Custom logging to flash, UART, or syslog",[91,3726,3727,3728,879],{},"ESP-IDF has a built-in logging framework (",[377,3729,3730],{},"esp_log",[11,3732,3733,3736],{},[31,3734,3735],{},"Requirements 5, 12, 13"," — Data minimisation, secure deletion, user notification: These are application-level requirements, not RTOS features.",[45,3738,2539],{"id":2538},[11,3740,3741],{},[31,3742,2544],{},[11,3744,3745],{},"This is where FreeRTOS projects have the most complexity:",[11,3747,3748,3751],{},[31,3749,3750],{},"Kernel SBOM:"," Simple — one component (FreeRTOS-Kernel) with a clear version number and MIT license.",[11,3753,3754,3757],{},[31,3755,3756],{},"Full project SBOM:"," Complex — you need to enumerate:",[1013,3759,3760,3763,3766,3769,3772],{},[91,3761,3762],{},"FreeRTOS kernel version",[91,3764,3765],{},"All AWS FreeRTOS libraries (if used) with versions",[91,3767,3768],{},"Vendor SDK version and all components within it",[91,3770,3771],{},"Third-party libraries (lwIP, mbedTLS, fatfs, etc.)",[91,3773,3774],{},"Binary blobs from the MCU vendor",[11,3776,3777,3778,3780],{},"There's no native SBOM tooling in the FreeRTOS ecosystem. See our ",[102,3779,1022],{"href":152}," for approaches.",[11,3782,3783],{},[31,3784,3785],{},"VH2 — Security update delivery (OTA)",[1097,3787,3788,3797],{},[1100,3789,3790],{},[1103,3791,3792,3794],{},[1106,3793,3427],{},[1106,3795,3796],{},"OTA capability",[1119,3798,3799,3805,3812,3822,3829],{},[1103,3800,3801,3803],{},[1124,3802,3437],{},[1124,3804,3683],{},[1103,3806,3807,3809],{},[1124,3808,3574],{},[1124,3810,3811],{},"OTA library (works with AWS IoT Jobs)",[1103,3813,3814,3816],{},[1124,3815,3590],{},[1124,3817,3818,3821],{},[377,3819,3820],{},"esp_https_ota"," with A/B partition scheme",[1103,3823,3824,3826],{},[1124,3825,3582],{},[1124,3827,3828],{},"SBSFU provides update mechanism; no fleet management",[1103,3830,3831,3833],{},[1124,3832,3598],{},[1124,3834,3835],{},"Vendor-specific update libraries",[11,3837,3838,3839,1603],{},"The AWS FreeRTOS OTA library is the most complete option, but it requires AWS IoT Core as the backend. For non-AWS deployments, you'll need to build or adopt an OTA solution. See our ",[102,3840,2626],{"href":220},[11,3842,3843],{},[31,3844,2631],{},[11,3846,3847,3848,605,3850,1603],{},"Organisational requirements — same as any RTOS. See our ",[102,3849,1055],{"href":911},[102,3851,3852],{"href":3112},"Annex I checklist",[21,3854,3856],{"id":3855},"the-vendor-sdk-dependency-problem","The Vendor SDK Dependency Problem",[11,3858,3859],{},"For most FreeRTOS projects, the biggest CRA compliance challenge isn't the RTOS — it's the vendor SDK layer.",[11,3861,3862],{},[31,3863,3864],{},"Why this matters:",[1013,3866,3867,3873,3879,3885],{},[91,3868,3869,3872],{},[31,3870,3871],{},"Patch latency:"," When a CVE is published for mbedTLS, the fix flows: mbedTLS upstream → vendor SDK team → vendor SDK release → your product update. This can take weeks to months for vendor SDKs with infrequent releases.",[91,3874,3875,3878],{},[31,3876,3877],{},"Version opacity:"," Vendor SDKs often bundle modified versions of open-source libraries. The mbedTLS version in STM32Cube may not match any public release — it's a vendor-patched fork. This complicates vulnerability matching.",[91,3880,3881,3884],{},[31,3882,3883],{},"SBOM difficulty:"," The vendor SDK is a monolithic package. Extracting individual component versions requires digging through release notes or header files, not a standard manifest.",[91,3886,3887,3890],{},[31,3888,3889],{},"Update coupling:"," Security updates to one component (e.g., mbedTLS) may require updating the entire vendor SDK, which may include breaking changes to HAL drivers or other components.",[11,3892,3893],{},[31,3894,3895],{},"Mitigation strategies:",[86,3897,3898,3904,3910,3916],{},[91,3899,3900,3903],{},[31,3901,3902],{},"Pin and track:"," Record the exact vendor SDK version and the upstream versions of all bundled components (mbedTLS, lwIP, FreeRTOS kernel, etc.)",[91,3905,3906,3909],{},[31,3907,3908],{},"Contractual requirements:"," Push your MCU vendor for timely security patches and SBOM data for their SDK",[91,3911,3912,3915],{},[31,3913,3914],{},"Decouple where possible:"," If you can link mbedTLS directly (bypassing the vendor's bundled version), you can patch it independently",[91,3917,3918,3921],{},[31,3919,3920],{},"Monitor both layers:"," Watch both the vendor SDK advisories and the upstream component CVE feeds",[21,3923,3925],{"id":3924},"when-to-skip-freertos-entirely","When to Skip FreeRTOS Entirely",[11,3927,3928],{},"For some products, FreeRTOS adds complexity without proportional benefit for CRA compliance:",[11,3930,3931],{},[31,3932,3933],{},"Consider bare-metal if:",[86,3935,3936,3939,3942,3945],{},[91,3937,3938],{},"Your application is single-purpose (one main loop, no concurrent tasks)",[91,3940,3941],{},"You don't need networking (FreeRTOS doesn't provide it anyway)",[91,3943,3944],{},"Your MCU vendor's bare-metal SDK provides everything you need",[91,3946,3947],{},"The FreeRTOS kernel adds to your SBOM and attack surface without adding security value",[11,3949,3950],{},[31,3951,3952],{},"Consider Zephyr if:",[86,3954,3955,3958,3961,3964],{},[91,3956,3957],{},"You need built-in MCUboot, TLS, and device management integration",[91,3959,3960],{},"You want a more unified security ecosystem (less vendor SDK dependency)",[91,3962,3963],{},"Your team is starting a new project (rather than migrating an existing FreeRTOS codebase)",[91,3965,3966],{},"SBOM generation and dependency tracking are priorities",[11,3968,3969],{},"FreeRTOS is the right choice when you have an existing codebase, need maximum portability across MCU vendors, or are committed to the AWS IoT ecosystem. But for greenfield projects with CRA compliance as a priority, Zephyr's integrated security ecosystem offers a smoother path.",[21,3971,3973],{"id":3972},"freertos-specific-compliance-checklist","FreeRTOS-Specific Compliance Checklist",[11,3975,3976],{},[31,3977,3978],{},"Kernel configuration",[86,3980,3982,3988,3998,4007],{"className":3981},[89],[91,3983,3985,3987],{"className":3984},[94],[96,3986],{"disabled":98,"type":99}," FreeRTOS kernel version pinned and recorded in project documentation",[91,3989,3991,3993,3994,3997],{"className":3990},[94],[96,3992],{"disabled":98,"type":99}," MPU wrapper enabled for Cortex-M (",[377,3995,3996],{},"configENABLE_MPU=1",") if memory isolation is needed",[91,3999,4001,4003,4004,879],{"className":4000},[94],[96,4002],{"disabled":98,"type":99}," Stack overflow detection enabled (",[377,4005,4006],{},"configCHECK_FOR_STACK_OVERFLOW=2",[91,4008,4010,784,4012,4015],{"className":4009},[94],[96,4011],{"disabled":98,"type":99},[377,4013,4014],{},"configASSERT"," enabled and routed to error handler (not disabled in production)",[11,4017,4018],{},[31,4019,4020],{},"Secure boot (MCU-dependent)",[86,4022,4024,4030,4036,4042,4048],{"className":4023},[89],[91,4025,4027,4029],{"className":4026},[94],[96,4028],{"disabled":98,"type":99}," Secure boot enabled using MCU vendor's mechanism (SBSFU, HAB, ESP-IDF secure boot, etc.)",[91,4031,4033,4035],{"className":4032},[94],[96,4034],{"disabled":98,"type":99}," Firmware signing key stored in HSM/KMS",[91,4037,4039,4041],{"className":4038},[94],[96,4040],{"disabled":98,"type":99}," Production images signed with production key",[91,4043,4045,4047],{"className":4044},[94],[96,4046],{"disabled":98,"type":99}," Anti-rollback protection configured",[91,4049,4051,4053,4054],{"className":4050},[94],[96,4052],{"disabled":98,"type":99}," See ",[102,4055,2370],{"href":209},[11,4057,4058],{},[31,4059,2831],{},[86,4061,4063,4069,4075,4080],{"className":4062},[89],[91,4064,4066,4068],{"className":4065},[94],[96,4067],{"disabled":98,"type":99}," TLS library integrated (mbedTLS, wolfSSL, or equivalent)",[91,4070,4072,4074],{"className":4071},[94],[96,4073],{"disabled":98,"type":99}," TLS 1.2+ configured with strong cipher suites",[91,4076,4078,2852],{"className":4077},[94],[96,4079],{"disabled":98,"type":99},[91,4081,4083,4085],{"className":4082},[94],[96,4084],{"disabled":98,"type":99}," Key storage uses hardware secure storage where available (TrustZone, SE, PUF)",[11,4087,4088],{},[31,4089,1036],{},[86,4091,4093,4099,4105,4111,4116],{"className":4092},[89],[91,4094,4096,4098],{"className":4095},[94],[96,4097],{"disabled":98,"type":99}," Update mechanism implemented (AWS OTA library, ESP-IDF OTA, vendor-specific, or custom)",[91,4100,4102,4104],{"className":4101},[94],[96,4103],{"disabled":98,"type":99}," A/B partition scheme with rollback on failure",[91,4106,4108,4110],{"className":4107},[94],[96,4109],{"disabled":98,"type":99}," Updates signed and verified before installation",[91,4112,4114,2949],{"className":4113},[94],[96,4115],{"disabled":98,"type":99},[91,4117,4119,4053,4121],{"className":4118},[94],[96,4120],{"disabled":98,"type":99},[102,4122,1040],{"href":220},[11,4124,4125],{},[31,4126,2903],{},[86,4128,4130,4136,4142,4147],{"className":4129},[89],[91,4131,4133,4135],{"className":4132},[94],[96,4134],{"disabled":98,"type":99}," JTAG/SWD disabled in production (MCU-specific configuration)",[91,4137,4139,4141],{"className":4138},[94],[96,4140],{"disabled":98,"type":99}," Unused peripherals and protocols disabled",[91,4143,4145,2924],{"className":4144},[94],[96,4146],{"disabled":98,"type":99},[91,4148,4150,4152,4153,380,4155,879],{"className":4149},[94],[96,4151],{"disabled":98,"type":99}," Compiler hardening flags enabled (",[377,4154,379],{},[377,4156,383],{},[11,4158,4159],{},[31,4160,153],{},[86,4162,4164,4170,4176,4182,4188,4193],{"className":4163},[89],[91,4165,4167,4169],{"className":4166},[94],[96,4168],{"disabled":98,"type":99}," FreeRTOS kernel version documented",[91,4171,4173,4175],{"className":4172},[94],[96,4174],{"disabled":98,"type":99}," All AWS/vendor/third-party libraries enumerated with versions",[91,4177,4179,4181],{"className":4178},[94],[96,4180],{"disabled":98,"type":99}," Vendor SDK version and bundled component versions recorded",[91,4183,4185,4187],{"className":4184},[94],[96,4186],{"disabled":98,"type":99}," Binary blobs documented with vendor and version",[91,4189,4191,2989],{"className":4190},[94],[96,4192],{"disabled":98,"type":99},[91,4194,4196,4053,4198],{"className":4195},[94],[96,4197],{"disabled":98,"type":99},[102,4199,1022],{"href":152},[11,4201,4202],{},[31,4203,3000],{},[86,4205,4207,4213,4219,4225,4231],{"className":4206},[89],[91,4208,4210,4212],{"className":4209},[94],[96,4211],{"disabled":98,"type":99}," CVE monitoring covers: FreeRTOS kernel, AWS libraries (if used), vendor SDK, all third-party components",[91,4214,4216,4218],{"className":4215},[94],[96,4217],{"disabled":98,"type":99}," Vendor SDK update process defined (how quickly can you adopt a new SDK version)",[91,4220,4222,4224],{"className":4221},[94],[96,4223],{"disabled":98,"type":99}," PSIRT process and CVD policy established",[91,4226,4228,4230],{"className":4227},[94],[96,4229],{"disabled":98,"type":99}," ENISA reporting registration completed",[91,4232,4234,4053,4236],{"className":4233},[94],[96,4235],{"disabled":98,"type":99},[102,4237,1055],{"href":911},[11,4239,2150,4240,4242],{},[102,4241,1475],{"href":1474}," assesses your full Annex I posture and identifies the specific gaps in your FreeRTOS project's CRA readiness.",[1478,4244],{},[11,4246,4247],{},[1483,4248,4249],{},"Based on Regulation EU 2024/2847 Annex I, FreeRTOS documentation, AWS FreeRTOS documentation, STM32Cube documentation, ESP-IDF documentation, NXP MCUXpresso documentation. This does not constitute legal advice.",[21,4251,1489],{"id":1488},[86,4253,4254,4259,4266,4272,4279,4286,4293],{},[91,4255,4256],{},[102,4257,1499],{"href":1496,"rel":4258},[1498],[91,4260,4261],{},[102,4262,4265],{"href":4263,"rel":4264},"https://www.freertos.org/Documentation/RTOS_book.html",[1498],"FreeRTOS — Official documentation",[91,4267,4268],{},[102,4269,4271],{"href":3247,"rel":4270},[1498],"FreeRTOS Kernel — GitHub repository",[91,4273,4274],{},[102,4275,4278],{"href":4276,"rel":4277},"https://docs.aws.amazon.com/freertos/latest/userguide/dev-guide-freertos-libraries.html",[1498],"AWS FreeRTOS — Libraries documentation",[91,4280,4281],{},[102,4282,4285],{"href":4283,"rel":4284},"https://docs.espressif.com/projects/esp-idf/en/stable/esp32/",[1498],"Espressif — ESP-IDF documentation",[91,4287,4288],{},[102,4289,4292],{"href":4290,"rel":4291},"https://www.st.com/en/embedded-software/stm32cube-mcu-mpu-packages.html",[1498],"STMicroelectronics — STM32Cube FreeRTOS integration",[91,4294,4295],{},[102,4296,4299],{"href":4297,"rel":4298},"https://www.nxp.com/design/design-center/software/development-software/mcuxpresso-software-and-tools-/mcuxpresso-software-development-kit-sdk:MCUXpresso-SDK",[1498],"NXP — MCUXpresso SDK",{"title":1536,"searchDepth":1537,"depth":1537,"links":4301},[4302,4307,4311,4312,4313,4314],{"id":3234,"depth":1537,"text":3235,"children":4303},[4304,4305,4306],{"id":3241,"depth":1542,"text":3242},{"id":3303,"depth":1542,"text":3304},{"id":3357,"depth":1542,"text":3358},{"id":3402,"depth":1537,"text":3403,"children":4308},[4309,4310],{"id":68,"depth":1542,"text":69},{"id":2538,"depth":1542,"text":2539},{"id":3855,"depth":1537,"text":3856},{"id":3924,"depth":1537,"text":3925},{"id":3972,"depth":1537,"text":3973},{"id":1488,"depth":1537,"text":1489},"2026-02-19","Map CRA Annex I requirements to FreeRTOS variants—vanilla kernel, AWS FreeRTOS, and vendor SDKs—and find the gaps the kernel doesn't cover.","/images/blog/previews/freertos.svg",[4319,4320,4321,4322,4323],"CRA FreeRTOS","FreeRTOS CRA compliance","Cyber Resilience Act FreeRTOS","FreeRTOS security CRA","AWS FreeRTOS CRA",{},"/blog/cra-compliance-freertos",{"title":3217,"description":4316},"blog/cra-compliance-freertos","JVswK3uSOpDkboMP5WDf7-vfLQ37yFubjMQQhLN4rLA",{"id":4330,"title":4331,"body":4332,"date":5203,"description":5204,"extension":1577,"image":5205,"keywords":5206,"meta":5212,"navigation":98,"path":5213,"readTime":3211,"seo":5214,"stem":5215,"__hash__":5216},"blog/blog/cra-secure-boot-firmware-signing.md","CRA Secure Boot and Firmware Signing for MCUs",{"type":8,"value":4333,"toc":5182},[4334,4337,4340,4344,4347,4352,4355,4360,4363,4368,4371,4374,4378,4381,4387,4393,4399,4405,4409,4412,4416,4423,4434,4438,4445,4456,4460,4467,4478,4482,4485,4496,4500,4503,4510,4514,4540,4546,4550,4637,4643,4647,4650,4653,4657,4660,4665,4715,4721,4725,4860,4866,4870,4873,4878,4889,4894,4911,4916,4930,4935,4946,4950,4955,4976,4981,5008,5013,5034,5038,5059,5064,5081,5086,5113,5119,5121,5126,5128],[11,4335,4336],{},"Secure boot is one of the foundational requirements in the CRA, and it's the one that causes the most confusion for firmware teams. The regulation doesn't use the phrase \"secure boot\" directly — but Annex I Part I lays down requirements that are impossible to meet without it.",[11,4338,4339],{},"If you're building MCU-based products that will be placed on the EU market, you need a boot integrity chain and a firmware code signing pipeline. This post explains what the regulation requires, how to implement it for common MCU families, and what the documentation burden looks like.",[21,4341,4343],{"id":4342},"what-annex-i-actually-requires","What Annex I Actually Requires",[11,4345,4346],{},"Three Annex I Part I requirements map directly to secure boot and firmware signing:",[11,4348,4349],{},[31,4350,4351],{},"Requirement 3 — Integrity protection:",[11,4353,4354],{},"Products must be designed so that their integrity is protected. This includes protection of firmware and software against unauthorised modification. For MCU firmware, this means: a mechanism to verify that the code running on the device is the code you intended to ship, and that it hasn't been tampered with at rest or during the update process.",[11,4356,4357],{},[31,4358,4359],{},"Requirement 6 — Minimise attack surface:",[11,4361,4362],{},"Products must minimise the attack surface, including external interfaces. An unsigned bootloader that loads arbitrary firmware images from flash is an open attack surface. Secure boot closes it by verifying firmware authenticity before execution.",[11,4364,4365],{},[31,4366,4367],{},"Requirement 2 — No known exploitable vulnerabilities:",[11,4369,4370],{},"Products must be delivered without known exploitable vulnerabilities. An unsigned or unverified boot chain is itself a vulnerability — it allows persistent code execution via firmware replacement attacks.",[11,4372,4373],{},"Taken together, these requirements mean: your device must verify the authenticity and integrity of its firmware at boot time, and the signing keys must be managed securely.",[21,4375,4377],{"id":4376},"secure-boot-vs-verified-boot-vs-measured-boot","Secure Boot vs. Verified Boot vs. Measured Boot",[11,4379,4380],{},"These terms get conflated. For CRA compliance purposes, the distinctions matter:",[11,4382,4383,4386],{},[31,4384,4385],{},"Secure Boot:"," The bootloader verifies a cryptographic signature on the firmware image before transferring execution. If verification fails, the device refuses to boot the image. This is the minimum bar for CRA compliance on most MCU platforms.",[11,4388,4389,4392],{},[31,4390,4391],{},"Verified Boot:"," A chain of trust where each stage verifies the next — ROM bootloader verifies first-stage bootloader, first-stage bootloader verifies application firmware. Each stage is signed independently. This is what platforms like STM32 SBSFU and MCUboot implement.",[11,4394,4395,4398],{},[31,4396,4397],{},"Measured Boot:"," Each stage is hashed and the measurement is recorded (typically in a TPM PCR or equivalent). The device boots regardless of measurement, but a remote verifier can check whether the device booted the expected code. This is common in Linux-based systems with TPM but rarely used in bare-metal MCU deployments.",[11,4400,4401,4404],{},[31,4402,4403],{},"For CRA compliance:"," Verified boot (with a chain of trust from an immutable root) is the recommended approach. Measured boot alone isn't sufficient — it doesn't prevent a tampered image from executing; it only detects it after the fact.",[21,4406,4408],{"id":4407},"root-of-trust-where-the-chain-starts","Root of Trust: Where the Chain Starts",[11,4410,4411],{},"The entire boot integrity chain depends on an immutable root of trust — a piece of code and/or a public key that cannot be modified by software. If an attacker can replace the root of trust, the entire chain is broken.",[45,4413,4415],{"id":4414},"stm32-stmicroelectronics","STM32 (STMicroelectronics)",[11,4417,4418,4419,4422],{},"STM32 MCUs with Secure Boot and Secure Firmware Update (SBSFU) use the ",[31,4420,4421],{},"OTP (One-Time Programmable) fuses"," to store the root of trust public key hash. Once the Read-out Protection (RDP) level is set to Level 2, the internal flash containing the secure bootloader is permanently locked.",[86,4424,4425,4428,4431],{},[91,4426,4427],{},"Root of trust: OTP-fused public key hash + locked bootloader in protected flash",[91,4429,4430],{},"Algorithm support: ECDSA P-256 for signature verification, AES-128-CBC for firmware encryption (default configuration)",[91,4432,4433],{},"Key revocation: Limited — OTP fuses don't support easy key rotation; plan your key management carefully",[45,4435,4437],{"id":4436},"esp32-espressif","ESP32 (Espressif)",[11,4439,4440,4441,4444],{},"ESP-IDF's secure boot V2 uses ",[31,4442,4443],{},"eFuse"," storage for up to three RSA-3072 or ECDSA-P256 public key digests. Once secure boot is enabled and the eFuses are burned, the ROM bootloader will only execute a signed second-stage bootloader.",[86,4446,4447,4450,4453],{},[91,4448,4449],{},"Root of trust: eFuse-stored key digests (up to 3 key slots for rotation)",[91,4451,4452],{},"Algorithm support: RSA-3072, ECDSA P-256 (ESP32-S2 and later)",[91,4454,4455],{},"Key revocation: Supported — individual key slots can be revoked via eFuse",[45,4457,4459],{"id":4458},"nxp-imx-rt-lpc-kinetis","NXP (i.MX RT, LPC, Kinetis)",[11,4461,4462,4463,4466],{},"NXP's HAB (High Assurance Boot) and newer AHAB use ",[31,4464,4465],{},"OTP fuses"," to store the Super Root Key (SRK) hash. The ROM bootloader verifies the first-stage image using the SRK table embedded in the image, validated against the fused hash.",[86,4468,4469,4472,4475],{},[91,4470,4471],{},"Root of trust: OTP-fused SRK hash",[91,4473,4474],{},"Algorithm support: RSA-2048/4096 (well-established); ECDSA support varies by platform and HAB version — check your specific SoC's security reference manual",[91,4476,4477],{},"Key revocation: SRK table supports up to 4 keys with per-key revocation via OTP fuses",[45,4479,4481],{"id":4480},"nordic-semiconductor-nrf52-nrf53-nrf91","Nordic Semiconductor (nRF52, nRF53, nRF91)",[11,4483,4484],{},"Nordic's Secure Bootloader (nRF Secure Immutable Bootloader, NSIB) uses a public key hash provisioned into a protected region. On nRF91 and nRF5340, ARM TrustZone provides hardware isolation for the secure bootloader.",[86,4486,4487,4490,4493],{},[91,4488,4489],{},"Root of trust: Provisioned key hash in KMU (Key Management Unit) or protected flash",[91,4491,4492],{},"Algorithm support: ECDSA P-256 via nrf_oberon or cc310 crypto libraries",[91,4494,4495],{},"Key revocation: Supported via key slot mechanism",[21,4497,4499],{"id":4498},"code-signing-pipeline","Code Signing Pipeline",[11,4501,4502],{},"Having secure boot hardware support is necessary but not sufficient. You also need a signing pipeline that protects your private keys and integrates into your build process.",[11,4504,4505],{},[4506,4507],"img",{"alt":4508,"src":4509},"Secure Boot Chain and Code Signing Pipeline","/images/blog/secure-boot-pipeline.svg",[45,4511,4513],{"id":4512},"minimum-viable-signing-pipeline","Minimum Viable Signing Pipeline",[1013,4515,4516,4522,4528,4534],{},[91,4517,4518,4521],{},[31,4519,4520],{},"Key generation:"," Generate an ECDSA P-256 or Ed25519 key pair. The private key never touches a developer workstation or CI runner's filesystem unencrypted.",[91,4523,4524,4527],{},[31,4525,4526],{},"HSM or KMS storage:"," Store the signing private key in a Hardware Security Module (HSM) or cloud KMS (AWS KMS, Azure Key Vault, Google Cloud KMS). For cost-sensitive teams, a YubiHSM 2 (~$750) provides PKCS#11-compatible key storage.",[91,4529,4530,4533],{},[31,4531,4532],{},"CI/CD integration:"," Your build pipeline produces an unsigned firmware binary, then calls the HSM/KMS to sign it. The signed binary is the release artifact.",[91,4535,4536,4539],{},[31,4537,4538],{},"Signature verification:"," The bootloader on the device verifies the signature against the public key stored in OTP/eFuse before executing the firmware.",[2358,4541,4544],{"className":4542,"code":4543,"language":2363},[2361],"┌─────────────┐    ┌──────────┐    ┌─────────┐    ┌────────────┐\n│  CI/CD      │───▶│ Build    │───▶│ Sign    │───▶│ Release    │\n│  Pipeline   │    │ Firmware │    │ via HSM │    │ Artifact   │\n└─────────────┘    └──────────┘    └─────────┘    └────────────┘\n                                        │\n                                   ┌────┴────┐\n                                   │  HSM /  │\n                                   │  KMS    │\n                                   └─────────┘\n",[377,4545,4543],{"__ignoreMap":1536},[45,4547,4549],{"id":4548},"algorithm-selection","Algorithm Selection",[1097,4551,4552,4571],{},[1100,4553,4554],{},[1103,4555,4556,4559,4562,4565,4568],{},[1106,4557,4558],{},"Algorithm",[1106,4560,4561],{},"Key Size",[1106,4563,4564],{},"Signature Size",[1106,4566,4567],{},"Verification Speed (Cortex-M4)",[1106,4569,4570],{},"Recommendation",[1119,4572,4573,4590,4605,4621],{},[1103,4574,4575,4578,4581,4584,4587],{},[1124,4576,4577],{},"ECDSA P-256",[1124,4579,4580],{},"32 bytes",[1124,4582,4583],{},"64 bytes",[1124,4585,4586],{},"~50ms",[1124,4588,4589],{},"Widely supported, good default",[1103,4591,4592,4595,4597,4599,4602],{},[1124,4593,4594],{},"Ed25519",[1124,4596,4580],{},[1124,4598,4583],{},[1124,4600,4601],{},"~30ms",[1124,4603,4604],{},"Faster verification, MCUboot default",[1103,4606,4607,4610,4613,4615,4618],{},[1124,4608,4609],{},"RSA-2048",[1124,4611,4612],{},"256 bytes",[1124,4614,4612],{},[1124,4616,4617],{},"~15ms (verify)",[1124,4619,4620],{},"Fast verify but large signatures",[1103,4622,4623,4626,4629,4631,4634],{},[1124,4624,4625],{},"RSA-3072",[1124,4627,4628],{},"384 bytes",[1124,4630,4628],{},[1124,4632,4633],{},"~30ms (verify)",[1124,4635,4636],{},"ESP32 secure boot default",[11,4638,4639,4642],{},[31,4640,4641],{},"Recommendation:"," Use Ed25519 for MCUboot-based systems (it's well-supported and fastest to verify). Use ECDSA P-256 when the MCU's secure boot ROM requires it (STM32, NXP HAB). Use RSA-3072 only for ESP32 secure boot V2 where the ROM requires it.",[21,4644,4646],{"id":4645},"anti-rollback-protection","Anti-Rollback Protection",[11,4648,4649],{},"Signing prevents unauthorised firmware from running. But without anti-rollback protection, an attacker with physical access can flash an older, signed firmware version that contains a known vulnerability.",[11,4651,4652],{},"Annex I Requirement 2 (no known exploitable vulnerabilities) and Requirement 3 (integrity protection) together imply that rollback to a known-vulnerable version should be prevented.",[45,4654,4656],{"id":4655},"how-anti-rollback-works","How Anti-Rollback Works",[11,4658,4659],{},"The firmware image includes a monotonic version counter. The bootloader stores the minimum acceptable version in a one-way counter (OTP fuses, monotonic counter register, or a wear-levelled flash counter). During boot, the bootloader rejects any image with a version counter below the stored minimum.",[11,4661,4662],{},[31,4663,4664],{},"Implementation by platform:",[1097,4666,4667,4676],{},[1100,4668,4669],{},[1103,4670,4671,4673],{},[1106,4672,2684],{},[1106,4674,4675],{},"Anti-Rollback Mechanism",[1119,4677,4678,4689,4697,4707],{},[1103,4679,4680,4683],{},[1124,4681,4682],{},"MCUboot",[1124,4684,4685,4688],{},[377,4686,4687],{},"IMAGE_VERSION"," field compared against stored minimum; requires hardware counter support from the platform",[1103,4690,4691,4694],{},[1124,4692,4693],{},"STM32 SBSFU",[1124,4695,4696],{},"Version counter stored in protected flash; updated during secure firmware install",[1103,4698,4699,4701],{},[1124,4700,3590],{},[1124,4702,4703,4706],{},[377,4704,4705],{},"security_version"," field in image header; compared against eFuse-stored version (max 32 increments on ESP32)",[1103,4708,4709,4712],{},[1124,4710,4711],{},"NXP HAB",[1124,4713,4714],{},"Software-implemented via OTP fuse field",[11,4716,4717,4720],{},[31,4718,4719],{},"Limitation:"," OTP-fuse-based counters have a finite number of increments (typically 32 or 64). Plan your versioning strategy so you don't exhaust the counter during the product's lifetime. For a 10-year product with monthly security updates, 120 increments are needed — this exceeds most OTP counters. Consider using flash-based counters with integrity protection for long-lifecycle products.",[21,4722,4724],{"id":4723},"bootloader-comparison-for-cra-compliance","Bootloader Comparison for CRA Compliance",[1097,4726,4727,4743],{},[1100,4728,4729],{},[1103,4730,4731,4734,4736,4738,4740],{},[1106,4732,4733],{},"Feature",[1106,4735,4682],{},[1106,4737,4693],{},[1106,4739,3504],{},[1106,4741,4742],{},"U-Boot (Verified Boot)",[1119,4744,4745,4761,4776,4792,4809,4826,4843],{},[1103,4746,4747,4750,4753,4756,4758],{},[1124,4748,4749],{},"Open source",[1124,4751,4752],{},"Yes (Apache 2.0)",[1124,4754,4755],{},"Partially (ST proprietary bootloader, open-source app layer)",[1124,4757,4752],{},[1124,4759,4760],{},"Yes (GPL-2.0)",[1103,4762,4763,4766,4769,4771,4773],{},[1124,4764,4765],{},"Chain of trust",[1124,4767,4768],{},"Yes (2-stage)",[1124,4770,4768],{},[1124,4772,4768],{},[1124,4774,4775],{},"Yes (multi-stage)",[1103,4777,4778,4781,4784,4786,4789],{},[1124,4779,4780],{},"Signing algorithms",[1124,4782,4783],{},"Ed25519, ECDSA P-256, RSA-2048/3072",[1124,4785,4577],{},[1124,4787,4788],{},"RSA-3072, ECDSA P-256",[1124,4790,4791],{},"RSA-2048/4096, ECDSA P-256",[1103,4793,4794,4797,4800,4803,4806],{},[1124,4795,4796],{},"Anti-rollback",[1124,4798,4799],{},"Via platform counter",[1124,4801,4802],{},"Built-in",[1124,4804,4805],{},"eFuse counter",[1124,4807,4808],{},"Via FIT image version",[1103,4810,4811,4814,4817,4820,4823],{},[1124,4812,4813],{},"A/B image support",[1124,4815,4816],{},"Yes (swap or overwrite)",[1124,4818,4819],{},"No (single slot + download slot)",[1124,4821,4822],{},"Yes (OTA data partition)",[1124,4824,4825],{},"Yes (redundant partitions)",[1103,4827,4828,4831,4834,4837,4840],{},[1124,4829,4830],{},"SBOM-friendly",[1124,4832,4833],{},"Yes (clear versioning, Apache license)",[1124,4835,4836],{},"Partially (proprietary components)",[1124,4838,4839],{},"Yes (part of ESP-IDF, Apache license)",[1124,4841,4842],{},"Yes (GPL, well-documented)",[1103,4844,4845,4848,4851,4854,4857],{},[1124,4846,4847],{},"MCU support",[1124,4849,4850],{},"Zephyr, Mbed OS, mynewt, bare-metal",[1124,4852,4853],{},"STM32 family only",[1124,4855,4856],{},"ESP32 family only",[1124,4858,4859],{},"ARM (Cortex-A), RISC-V, x86",[11,4861,4862,4865],{},[31,4863,4864],{},"For CRA purposes:"," MCUboot is the most portable and best-documented option for Cortex-M based designs. STM32 SBSFU is a reasonable choice if you're committed to the STM32 ecosystem. ESP-IDF secure boot is the only practical option for ESP32 products. U-Boot is relevant for Linux-based embedded systems (Yocto, Buildroot) rather than bare-metal MCU products.",[21,4867,4869],{"id":4868},"annex-vii-documentation-requirements","Annex VII Documentation Requirements",[11,4871,4872],{},"Your technical documentation file must include evidence that the secure boot and firmware signing implementation meets Annex I requirements. Specifically:",[11,4874,4875],{},[31,4876,4877],{},"1. Security architecture description",[86,4879,4880,4883,4886],{},[91,4881,4882],{},"Boot chain diagram showing each verification stage",[91,4884,4885],{},"Root of trust description (which hardware mechanism, what key material is stored)",[91,4887,4888],{},"Key management lifecycle (generation, storage, rotation, revocation)",[11,4890,4891],{},[31,4892,4893],{},"2. Threat model coverage",[86,4895,4896,4899,4902,4905],{},[91,4897,4898],{},"Firmware replacement attack and mitigation (secure boot)",[91,4900,4901],{},"Rollback attack and mitigation (anti-rollback counter)",[91,4903,4904],{},"Key extraction attack and mitigation (OTP fuses, HSM)",[91,4906,4907,4908,879],{},"Physical access attack surface (JTAG/SWD disable — see our post on ",[102,4909,4910],{"href":104},"CRA threat modeling for embedded",[11,4912,4913],{},[31,4914,4915],{},"3. Test evidence",[86,4917,4918,4921,4924,4927],{},[91,4919,4920],{},"Test results showing the device rejects unsigned firmware images",[91,4922,4923],{},"Test results showing the device rejects firmware signed with the wrong key",[91,4925,4926],{},"Test results showing the device rejects rollback to a lower version",[91,4928,4929],{},"Test results for the recovery mechanism when a valid image is unavailable",[11,4931,4932],{},[31,4933,4934],{},"4. SBOM entries",[86,4936,4937,4943],{},[91,4938,4939,4940,4942],{},"Bootloader component listed in the ",[102,4941,153],{"href":152}," with version, supplier, license, and hash",[91,4944,4945],{},"Crypto library used for signature verification listed separately",[21,4947,4949],{"id":4948},"implementation-checklist","Implementation Checklist",[11,4951,4952],{},[31,4953,4954],{},"Root of trust",[86,4956,4958,4964,4970],{"className":4957},[89],[91,4959,4961,4963],{"className":4960},[94],[96,4962],{"disabled":98,"type":99}," Public key or key hash provisioned in OTP/eFuse",[91,4965,4967,4969],{"className":4966},[94],[96,4968],{"disabled":98,"type":99}," Bootloader stored in write-protected flash or ROM",[91,4971,4973,4975],{"className":4972},[94],[96,4974],{"disabled":98,"type":99}," RDP/security fuses set to prevent readback of keys and bootloader",[11,4977,4978],{},[31,4979,4980],{},"Signing pipeline",[86,4982,4984,4990,4996,5002],{"className":4983},[89],[91,4985,4987,4989],{"className":4986},[94],[96,4988],{"disabled":98,"type":99}," Private signing key stored in HSM or cloud KMS (never in source control, never on CI filesystem)",[91,4991,4993,4995],{"className":4992},[94],[96,4994],{"disabled":98,"type":99}," CI/CD pipeline signs firmware as a build step",[91,4997,4999,5001],{"className":4998},[94],[96,5000],{"disabled":98,"type":99}," Signed binary is the only release artifact (unsigned binaries are not shipped)",[91,5003,5005,5007],{"className":5004},[94],[96,5006],{"disabled":98,"type":99}," Signing key rotation procedure documented and tested",[11,5009,5010],{},[31,5011,5012],{},"Boot verification",[86,5014,5016,5022,5028],{"className":5015},[89],[91,5017,5019,5021],{"className":5018},[94],[96,5020],{"disabled":98,"type":99}," Bootloader verifies firmware signature before execution",[91,5023,5025,5027],{"className":5024},[94],[96,5026],{"disabled":98,"type":99}," Verification failure results in a safe state (not a boot loop — either hold in bootloader for recovery or load a known-good backup)",[91,5029,5031,5033],{"className":5030},[94],[96,5032],{"disabled":98,"type":99}," Chain of trust covers all executable stages (ROM → bootloader → application)",[11,5035,5036],{},[31,5037,4796],{},[86,5039,5041,5047,5053],{"className":5040},[89],[91,5042,5044,5046],{"className":5043},[94],[96,5045],{"disabled":98,"type":99}," Monotonic version counter implemented in hardware or integrity-protected flash",[91,5048,5050,5052],{"className":5049},[94],[96,5051],{"disabled":98,"type":99}," Bootloader rejects firmware with version below the stored minimum",[91,5054,5056,5058],{"className":5055},[94],[96,5057],{"disabled":98,"type":99}," Counter increment strategy documented (how many updates before exhaustion)",[11,5060,5061],{},[31,5062,5063],{},"Debug interface lockdown",[86,5065,5067,5075],{"className":5066},[89],[91,5068,5070,5072,5073,879],{"className":5069},[94],[96,5071],{"disabled":98,"type":99}," JTAG/SWD disabled or locked in production firmware (see debug interface section of the ",[102,5074,3852],{"href":3112},[91,5076,5078,5080],{"className":5077},[94],[96,5079],{"disabled":98,"type":99}," Readback protection enabled",[11,5082,5083],{},[31,5084,5085],{},"Documentation",[86,5087,5089,5095,5101,5107],{"className":5088},[89],[91,5090,5092,5094],{"className":5091},[94],[96,5093],{"disabled":98,"type":99}," Boot chain diagram in technical documentation file",[91,5096,5098,5100],{"className":5097},[94],[96,5099],{"disabled":98,"type":99}," Key management lifecycle documented",[91,5102,5104,5106],{"className":5103},[94],[96,5105],{"disabled":98,"type":99}," Test evidence for all verification scenarios",[91,5108,5110,5112],{"className":5109},[94],[96,5111],{"disabled":98,"type":99}," Bootloader included in SBOM",[11,5114,5115,5116,5118],{},"If you're starting from scratch with secure boot and need to assess your full CRA gap, the ",[102,5117,1475],{"href":1474}," identifies which Annex I requirements you still need to address based on your current firmware architecture.",[1478,5120],{},[11,5122,5123],{},[1483,5124,5125],{},"Based on Regulation EU 2024/2847 Annex I Part I (Requirements 2, 3, 6), Annex VII, MCUboot documentation, STM32 SBSFU reference, ESP-IDF Secure Boot V2 documentation, NXP HAB/AHAB documentation. This does not constitute legal advice.",[21,5127,1489],{"id":1488},[86,5129,5130,5135,5140,5147,5154,5161,5168,5175],{},[91,5131,5132],{},[102,5133,1499],{"href":1496,"rel":5134},[1498],[91,5136,5137],{},[102,5138,3160],{"href":3158,"rel":5139},[1498],[91,5141,5142],{},[102,5143,5146],{"href":5144,"rel":5145},"https://docs.mcuboot.com/imgtool.html",[1498],"MCUboot — Image signing tool (imgtool)",[91,5148,5149],{},[102,5150,5153],{"href":5151,"rel":5152},"https://docs.espressif.com/projects/esp-idf/en/stable/esp32/security/secure-boot-v2.html",[1498],"Espressif — Secure Boot V2 (ESP-IDF)",[91,5155,5156],{},[102,5157,5160],{"href":5158,"rel":5159},"https://www.st.com/en/embedded-software/x-cube-sbsfu.html",[1498],"STMicroelectronics — SBSFU Secure Boot and Firmware Update",[91,5162,5163],{},[102,5164,5167],{"href":5165,"rel":5166},"https://www.nxp.com/docs/en/application-note/AN4581.pdf",[1498],"NXP — High Assurance Boot (HAB) overview",[91,5169,5170],{},[102,5171,5174],{"href":5172,"rel":5173},"https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/app_dev/bootloaders_dfu/index.html",[1498],"Nordic Semiconductor — Secure Bootloader documentation",[91,5176,5177],{},[102,5178,5181],{"href":5179,"rel":5180},"https://www.yubico.com/product/yubihsm-2/",[1498],"Yubico — YubiHSM 2",{"title":1536,"searchDepth":1537,"depth":1537,"links":5183},[5184,5185,5186,5192,5196,5199,5200,5201,5202],{"id":4342,"depth":1537,"text":4343},{"id":4376,"depth":1537,"text":4377},{"id":4407,"depth":1537,"text":4408,"children":5187},[5188,5189,5190,5191],{"id":4414,"depth":1542,"text":4415},{"id":4436,"depth":1542,"text":4437},{"id":4458,"depth":1542,"text":4459},{"id":4480,"depth":1542,"text":4481},{"id":4498,"depth":1537,"text":4499,"children":5193},[5194,5195],{"id":4512,"depth":1542,"text":4513},{"id":4548,"depth":1542,"text":4549},{"id":4645,"depth":1537,"text":4646,"children":5197},[5198],{"id":4655,"depth":1542,"text":4656},{"id":4723,"depth":1537,"text":4724},{"id":4868,"depth":1537,"text":4869},{"id":4948,"depth":1537,"text":4949},{"id":1488,"depth":1537,"text":1489},"2026-02-05","CRA Annex I secure boot for MCUs in practice: root of trust, code signing, anti-rollback, and choosing a bootloader for your product.","/images/blog/previews/secure-boot.svg",[5207,5208,5209,5210,3207,5211],"CRA secure boot","CRA firmware signing","secure boot MCU CRA","firmware code signing embedded","root of trust embedded",{},"/blog/cra-secure-boot-firmware-signing",{"title":4331,"description":5204},"blog/cra-secure-boot-firmware-signing","SHZwflbQd5-KZhgUnBTnAuBUhMyZyfrV7V_mqGcTRvk",{"id":5218,"title":5219,"body":5220,"date":6174,"description":6175,"extension":1577,"image":6176,"keywords":6177,"meta":6184,"navigation":98,"path":6185,"readTime":6186,"seo":6187,"stem":6188,"__hash__":6189},"blog/blog/cra-ota-firmware-updates.md","CRA-Compliant OTA Updates for Embedded Firmware",{"type":8,"value":5221,"toc":6140},[5222,5229,5232,5236,5240,5243,5253,5256,5262,5268,5274,5278,5281,5295,5299,5306,5323,5326,5330,5333,5337,5340,5346,5364,5370,5376,5380,5383,5413,5419,5423,5426,5437,5440,5446,5450,5453,5527,5530,5534,5537,5541,5547,5550,5558,5562,5565,5585,5588,5592,5595,5602,5616,5619,5623,5626,5630,5636,5642,5648,5653,5664,5668,5671,5675,5707,5711,5714,5728,5731,5735,5738,5742,5745,5765,5769,5772,5792,5796,5799,5803,5808,5829,5834,5873,5878,5899,5902,5906,5911,5938,5943,5980,5985,6012,6017,6044,6048,6072,6077,6079,6084,6086],[11,5223,5224,5225,5228],{},"The CRA doesn't just require you to find and fix vulnerabilities. It requires you to ",[31,5226,5227],{},"deliver"," those fixes to devices in the field — for the entire support period, free of charge, and without undue delay. For embedded product teams, this means having a working, secure firmware update mechanism isn't optional. It's a legal obligation.",[11,5230,5231],{},"This post covers the specific CRA requirements around security updates, how to implement A/B update schemes for common embedded platforms, and the infrastructure and testing evidence you'll need for compliance.",[21,5233,5235],{"id":5234},"what-the-cra-requires-for-security-updates","What the CRA Requires for Security Updates",[45,5237,5239],{"id":5238},"annex-i-part-ii-the-update-obligation","Annex I Part II: The Update Obligation",[11,5241,5242],{},"Annex I Part II, point 2 establishes the core requirement:",[11,5244,5245,5246,605,5249,5252],{},"Manufacturers must ensure that vulnerabilities can be addressed through security updates, including, where applicable, through automatic updates. The updates must be provided ",[31,5247,5248],{},"free of charge",[31,5250,5251],{},"without undue delay"," after the vulnerability becomes known.",[11,5254,5255],{},"Key elements to unpack:",[11,5257,5258,5261],{},[31,5259,5260],{},"\"Free of charge\":"," You cannot charge customers for security patches. Feature updates can be gated behind a subscription, but patches addressing known vulnerabilities must be free for the product's support period.",[11,5263,5264,5267],{},[31,5265,5266],{},"\"Without undue delay\":"," The CRA text doesn't specify a hard SLA (e.g., \"within 30 days\"), but ENISA guidance suggests that \"without undue delay\" for critical and actively exploited vulnerabilities means days to weeks, not months. Market surveillance authorities will look at your patch timeline relative to the vulnerability severity.",[11,5269,5270,5273],{},[31,5271,5272],{},"\"Where applicable, through automatic updates\":"," For connected devices, the expectation is that updates can be delivered remotely. If your device requires physical access to update (JTAG, SD card swap, serial connection), you need to document why remote updates aren't technically feasible.",[45,5275,5277],{"id":5276},"annex-i-part-i-requirement-3-update-integrity","Annex I Part I, Requirement 3: Update Integrity",[11,5279,5280],{},"Updates themselves must be delivered securely. Annex I Part I, Requirement 3 (integrity protection) applies to the update delivery mechanism:",[86,5282,5283,5289,5292],{},[91,5284,5285,5286,879],{},"Updates must be signed and verified before installation (see our post on ",[102,5287,5288],{"href":209},"secure boot and firmware signing",[91,5290,5291],{},"The update channel must be protected against tampering (TLS for transport, signature verification at the device)",[91,5293,5294],{},"Users must be informed about available security updates",[45,5296,5298],{"id":5297},"article-14-the-reporting-to-patching-pipeline","Article 14: The Reporting-to-Patching Pipeline",[11,5300,5301,5302,5305],{},"Article 14's vulnerability reporting obligations (see our ",[102,5303,5304],{"href":911},"Article 14 breakdown",") feed directly into the update pipeline:",[1013,5307,5308,5311,5314,5317,5320],{},[91,5309,5310],{},"You discover or are notified of a vulnerability",[91,5312,5313],{},"You report to ENISA within 24 hours (if actively exploited)",[91,5315,5316],{},"You develop and test a patch",[91,5318,5319],{},"You deliver the patch via your OTA update mechanism",[91,5321,5322],{},"You confirm patch deployment in your 14-day final report to ENISA",[11,5324,5325],{},"The update pipeline is the mechanism that closes the loop between vulnerability discovery and remediation. Without it, your Article 14 reports become a record of vulnerabilities you found but couldn't fix.",[21,5327,5329],{"id":5328},"ab-update-schemes-for-embedded-platforms","A/B Update Schemes for Embedded Platforms",[11,5331,5332],{},"The most robust firmware update pattern for MCU-based products is the A/B (dual-slot) scheme: the device maintains two firmware slots, runs from one, and installs updates into the other. If the update fails or the new image is faulty, the device can revert to the known-good slot.",[45,5334,5336],{"id":5335},"mcuboot-zephyr-bare-metal-cortex-m","MCUboot (Zephyr, bare-metal Cortex-M)",[11,5338,5339],{},"MCUboot supports two update strategies:",[11,5341,5342,5345],{},[31,5343,5344],{},"Swap mode:"," The bootloader swaps the contents of the primary and secondary slots during boot. If the new image fails validation (doesn't confirm itself within a timeout), the bootloader swaps back on the next reboot.",[86,5347,5348,5351,5354,5357],{},[91,5349,5350],{},"Primary slot: currently running firmware",[91,5352,5353],{},"Secondary slot: newly downloaded firmware image",[91,5355,5356],{},"Scratch area: temporary storage used during the swap (not needed in \"swap using move\" mode)",[91,5358,5359,5360,5363],{},"Image confirmation: the application must call ",[377,5361,5362],{},"boot_set_confirmed()"," after successful boot, or MCUboot reverts on next reboot",[11,5365,5366,5369],{},[31,5367,5368],{},"Overwrite mode:"," The bootloader copies the secondary slot image to the primary slot, destroying the previous image. Simpler but no automatic rollback — if the new image is broken, recovery requires re-downloading the previous version.",[11,5371,5372,5375],{},[31,5373,5374],{},"Recommendation for CRA compliance:"," Use swap mode. The automatic revert capability provides the fail-safe recovery mechanism that Annex I implicitly requires (a bricked device can't receive future security updates, violating the update obligation).",[45,5377,5379],{"id":5378},"esp-idf-esp32-family","ESP-IDF (ESP32 family)",[11,5381,5382],{},"ESP-IDF uses an OTA data partition to track which of two app partitions is active:",[86,5384,5385,5394,5400,5403,5410],{},[91,5386,5387,605,5390,5393],{},[377,5388,5389],{},"ota_0",[377,5391,5392],{},"ota_1",": two application firmware slots",[91,5395,5396,5399],{},[377,5397,5398],{},"otadata",": tracks which slot is active and whether it's been confirmed",[91,5401,5402],{},"The new image is written to the inactive slot, then the device reboots from that slot",[91,5404,5405,5406,5409],{},"If the app calls ",[377,5407,5408],{},"esp_ota_mark_app_valid_cancel_rollback()"," within the configured timeout, the slot becomes permanent",[91,5411,5412],{},"If the app crashes or fails to confirm, the bootloader reverts to the previous slot",[11,5414,5415,5416,5418],{},"ESP-IDF also provides ",[377,5417,3820],{}," for downloading firmware over HTTPS with built-in TLS and signature verification — a complete OTA client in one API.",[45,5420,5422],{"id":5421},"stm32-sbsfu-custom-bootloader","STM32 (SBSFU / custom bootloader)",[11,5424,5425],{},"STM32's SBSFU (Secure Boot and Secure Firmware Update) uses a download slot model:",[86,5427,5428,5431,5434],{},[91,5429,5430],{},"Protected slot: currently running firmware (read-protected via RDP)",[91,5432,5433],{},"Download slot: area where the new firmware is staged",[91,5435,5436],{},"The bootloader decrypts and verifies the download slot image, then installs it into the protected slot",[11,5438,5439],{},"SBSFU's limitation: it's not a true A/B scheme. The installation overwrites the current firmware. If the new image passes signature verification but has a runtime bug, there's no automatic rollback to the previous version.",[11,5441,5442,5445],{},[31,5443,5444],{},"For CRA compliance with STM32:"," Consider augmenting SBSFU with a self-test mechanism in the application that triggers a recovery mode if critical functionality fails post-update. Alternatively, use MCUboot on STM32 (it supports STM32 targets) for true A/B capability.",[45,5447,5449],{"id":5448},"yocto-embedded-linux-rauc-mender-swupdate","Yocto / Embedded Linux (RAUC, Mender, SWUpdate)",[11,5451,5452],{},"For Linux-based embedded products, the same A/B principle applies at the rootfs level:",[1097,5454,5455,5474],{},[1100,5456,5457],{},[1103,5458,5459,5462,5465,5468,5471],{},[1106,5460,5461],{},"Tool",[1106,5463,5464],{},"Update unit",[1106,5466,5467],{},"Rollback",[1106,5469,5470],{},"Signing",[1106,5472,5473],{},"Server component",[1119,5475,5476,5493,5510],{},[1103,5477,5478,5481,5484,5487,5490],{},[1124,5479,5480],{},"RAUC",[1124,5482,5483],{},"Full rootfs or bundle",[1124,5485,5486],{},"A/B slot with bootloader integration",[1124,5488,5489],{},"X.509 certificates (OpenSSL)",[1124,5491,5492],{},"Compatible with hawkBit, custom",[1103,5494,5495,5498,5501,5504,5507],{},[1124,5496,5497],{},"Mender",[1124,5499,5500],{},"Full rootfs image",[1124,5502,5503],{},"A/B partition with U-Boot/GRUB integration",[1124,5505,5506],{},"RSA or ECDSA signatures",[1124,5508,5509],{},"Mender Server (open-source or hosted)",[1103,5511,5512,5515,5518,5521,5524],{},[1124,5513,5514],{},"SWUpdate",[1124,5516,5517],{},"Image or delta",[1124,5519,5520],{},"A/B with U-Boot integration",[1124,5522,5523],{},"RSA, CMS signatures",[1124,5525,5526],{},"hawkBit, custom",[11,5528,5529],{},"All three integrate with U-Boot's verified boot for a complete chain of trust from bootloader to application.",[21,5531,5533],{"id":5532},"signing-and-verification-in-the-update-pipeline","Signing and Verification in the Update Pipeline",[11,5535,5536],{},"Every firmware update must be cryptographically signed and verified before installation. This isn't just for secure boot — it's for the OTA delivery path specifically.",[45,5538,5540],{"id":5539},"end-to-end-update-signing","End-to-End Update Signing",[2358,5542,5545],{"className":5543,"code":5544,"language":2363},[2361],"┌──────────┐    ┌──────────┐    ┌────────────┐    ┌──────────┐\n│ Build    │───▶│ Sign     │───▶│ Update     │───▶│ Device   │\n│ System   │    │ (HSM)    │    │ Server     │    │ Verifies │\n└──────────┘    └──────────┘    └────────────┘    └──────────┘\n                     │                                  │\n                ┌────┴────┐                        ┌────┴────┐\n                │ Private │                        │ Public  │\n                │ Key     │                        │ Key     │\n                └─────────┘                        └─────────┘\n",[377,5546,5544],{"__ignoreMap":1536},[11,5548,5549],{},"The signing key for OTA updates should be the same key (or in the same trust chain) as your secure boot signing key. This means the device's bootloader verifies both:",[86,5551,5552,5555],{},[91,5553,5554],{},"Firmware images at boot time",[91,5556,5557],{},"Firmware images received via OTA before installation",[45,5559,5561],{"id":5560},"transport-security","Transport Security",[11,5563,5564],{},"Even with signed images, the transport channel should use TLS to prevent:",[86,5566,5567,5573,5579],{},[91,5568,5569,5572],{},[31,5570,5571],{},"Downgrade attacks:"," An attacker intercepts the update check and tells the device \"no update available\" or serves an older signed image",[91,5574,5575,5578],{},[31,5576,5577],{},"Metadata tampering:"," Modifying update metadata (version numbers, release notes) to confuse the update logic",[91,5580,5581,5584],{},[31,5582,5583],{},"Privacy leakage:"," Device firmware versions and update patterns are sensitive information",[11,5586,5587],{},"For constrained devices that can't run full TLS 1.3, DTLS 1.2 (over UDP/CoAP) is an acceptable alternative. The key requirement is mutual authentication: the device must verify the server's identity, and ideally the server verifies the device's identity.",[21,5589,5591],{"id":5590},"rollback-protection-in-the-update-path","Rollback Protection in the Update Path",[11,5593,5594],{},"Anti-rollback in the OTA context prevents an attacker (or a misconfigured update server) from pushing an older firmware version that contains a known vulnerability.",[11,5596,5597,5598,5601],{},"This complements the boot-time anti-rollback described in the ",[102,5599,5600],{"href":209},"secure boot post"," — but it operates at the update level:",[1013,5603,5604,5607,5610,5613],{},[91,5605,5606],{},"The update server includes a version number in the signed update metadata",[91,5608,5609],{},"The device compares the incoming version against its stored minimum version",[91,5611,5612],{},"If the incoming version is lower, the device rejects the update before writing it to flash",[91,5614,5615],{},"After successful installation and confirmation, the device increments its stored minimum version",[11,5617,5618],{},"This check should happen before the device spends time downloading the full image (check version in the update manifest first) and again after download (verify the version in the signed image header).",[21,5620,5622],{"id":5621},"fail-safe-recovery","Fail-Safe Recovery",[11,5624,5625],{},"What happens when an update fails? The CRA implicitly requires a recovery mechanism — if a device is bricked by a bad update, it can no longer receive future security updates, which violates the ongoing update obligation.",[45,5627,5629],{"id":5628},"recovery-strategies","Recovery Strategies",[11,5631,5632,5635],{},[31,5633,5634],{},"Automatic rollback (MCUboot swap, ESP-IDF OTA):"," If the new firmware doesn't confirm itself within a timeout, the bootloader automatically reverts to the previous version. This is the gold standard.",[11,5637,5638,5641],{},[31,5639,5640],{},"Recovery mode bootloader:"," If both A/B slots are corrupted, the device enters a minimal recovery mode that can accept firmware via a secondary channel (USB, UART, BLE DFU). The recovery bootloader itself must be immutable and signed.",[11,5643,5644,5647],{},[31,5645,5646],{},"Factory reset partition:"," A read-only partition containing a known-good base firmware image. If all else fails, the device can revert to the factory image. This image should be periodically updated (if possible) or at minimum be free of known critical vulnerabilities at manufacturing time.",[11,5649,5650],{},[31,5651,5652],{},"What's not acceptable for CRA:",[86,5654,5655,5658,5661],{},[91,5656,5657],{},"A device that's permanently bricked by a failed update (no recovery path)",[91,5659,5660],{},"A device that requires physical return to the manufacturer for firmware recovery",[91,5662,5663],{},"A device that requires special tooling (JTAG programmer) that the end user doesn't have access to",[21,5665,5667],{"id":5666},"update-infrastructure","Update Infrastructure",[11,5669,5670],{},"The update mechanism on the device is only half the story. You also need server-side infrastructure to manage firmware distribution.",[45,5672,5674],{"id":5673},"minimum-viable-update-infrastructure","Minimum Viable Update Infrastructure",[1013,5676,5677,5683,5689,5695,5701],{},[91,5678,5679,5682],{},[31,5680,5681],{},"Firmware hosting:"," A server (or CDN) that hosts signed firmware images. Can be as simple as an S3 bucket with signed URLs.",[91,5684,5685,5688],{},[31,5686,5687],{},"Version manifest:"," A signed JSON/CBOR document that tells devices what the latest version is, its hash, download URL, and minimum required version.",[91,5690,5691,5694],{},[31,5692,5693],{},"Device check-in:"," Devices periodically query the manifest to check for updates. The check-in interval should be configurable — daily is reasonable for most IoT products.",[91,5696,5697,5700],{},[31,5698,5699],{},"Staged rollout:"," Don't push updates to 100% of devices simultaneously. Use a staged rollout (1% → 10% → 50% → 100%) with monitoring between stages. This isn't a CRA requirement, but it prevents a bad update from bricking your entire installed base.",[91,5702,5703,5706],{},[31,5704,5705],{},"Audit logging:"," Record which devices have received which updates. This is needed for your Article 14 final reports (demonstrating that patches were deployed) and for your technical documentation.",[45,5708,5710],{"id":5709},"fleet-management-considerations","Fleet Management Considerations",[11,5712,5713],{},"For products with large installed bases, you'll need:",[86,5715,5716,5719,5722,5725],{},[91,5717,5718],{},"Device registration and identity management",[91,5720,5721],{},"Per-device update status tracking",[91,5723,5724],{},"The ability to target updates to specific device groups (by hardware revision, region, etc.)",[91,5726,5727],{},"Metrics on update adoption rate (what percentage of devices are running the patched version)",[11,5729,5730],{},"Open-source options include Eclipse hawkBit (works with RAUC, SWUpdate, and Mender) and Mender Server. For MCU-based products with simpler needs, AWS IoT Jobs or Azure IoT Hub device management provide managed alternatives.",[21,5732,5734],{"id":5733},"end-of-life-and-support-period","End-of-Life and Support Period",[11,5736,5737],{},"Annex I Part II, point 2 requires security updates for a period appropriate to the expected product lifetime. Article 13(8) adds that the support period must be at least five years from product placement on the market.",[45,5739,5741],{"id":5740},"what-end-of-life-means-under-the-cra","What \"End of Life\" Means Under the CRA",[11,5743,5744],{},"When you end-of-life a product, you must:",[1013,5746,5747,5753,5759],{},[91,5748,5749,5752],{},[31,5750,5751],{},"Declare the support end date"," in advance (give customers time to plan)",[91,5754,5755,5758],{},[31,5756,5757],{},"Continue delivering security updates"," until that date",[91,5760,5761,5764],{},[31,5762,5763],{},"Consider making the source code available"," — Recital 70 suggests that after end-of-support, manufacturers should consider making source code available so users can continue to maintain security",[45,5766,5768],{"id":5767},"planning-for-long-product-lifecycles","Planning for Long Product Lifecycles",[11,5770,5771],{},"Embedded products often have 10–15 year lifecycles, especially in industrial settings. Your update infrastructure needs to survive that long:",[86,5773,5774,5780,5786],{},[91,5775,5776,5779],{},[31,5777,5778],{},"Key rotation:"," Your signing keys may need to be rotated during the product lifecycle. Plan for key rotation in your bootloader design (support multiple key slots)",[91,5781,5782,5785],{},[31,5783,5784],{},"Server infrastructure:"," Will your update server still be running in 10 years? Plan for infrastructure transitions",[91,5787,5788,5791],{},[31,5789,5790],{},"Dependency maintenance:"," The libraries your update client uses (TLS stack, HTTP client) will need updates themselves over the product lifecycle",[21,5793,5795],{"id":5794},"testing-evidence-for-compliance","Testing Evidence for Compliance",[11,5797,5798],{},"Your technical documentation must demonstrate that the update mechanism works correctly under normal and failure conditions.",[45,5800,5802],{"id":5801},"required-test-scenarios","Required Test Scenarios",[11,5804,5805],{},[31,5806,5807],{},"Positive tests:",[86,5809,5811,5817,5823],{"className":5810},[89],[91,5812,5814,5816],{"className":5813},[94],[96,5815],{"disabled":98,"type":99}," Device successfully downloads and installs a valid, signed update",[91,5818,5820,5822],{"className":5819},[94],[96,5821],{"disabled":98,"type":99}," Device confirms the update and boots into the new version",[91,5824,5826,5828],{"className":5825},[94],[96,5827],{"disabled":98,"type":99}," Update metadata (version, hash) matches the installed image",[11,5830,5831],{},[31,5832,5833],{},"Failure and recovery tests:",[86,5835,5837,5843,5849,5855,5861,5867],{"className":5836},[89],[91,5838,5840,5842],{"className":5839},[94],[96,5841],{"disabled":98,"type":99}," Device rejects an unsigned update image",[91,5844,5846,5848],{"className":5845},[94],[96,5847],{"disabled":98,"type":99}," Device rejects an update signed with the wrong key",[91,5850,5852,5854],{"className":5851},[94],[96,5853],{"disabled":98,"type":99}," Device rejects a rollback to an older version",[91,5856,5858,5860],{"className":5857},[94],[96,5859],{"disabled":98,"type":99}," Device automatically reverts after a failed update (image doesn't confirm)",[91,5862,5864,5866],{"className":5863},[94],[96,5865],{"disabled":98,"type":99}," Device recovers from a power loss during update installation",[91,5868,5870,5872],{"className":5869},[94],[96,5871],{"disabled":98,"type":99}," Device recovers from a network interruption during download",[11,5874,5875],{},[31,5876,5877],{},"Security tests:",[86,5879,5881,5887,5893],{"className":5880},[89],[91,5882,5884,5886],{"className":5883},[94],[96,5885],{"disabled":98,"type":99}," Update channel uses TLS/DTLS with certificate verification",[91,5888,5890,5892],{"className":5889},[94],[96,5891],{"disabled":98,"type":99}," Man-in-the-middle on the update channel is detected and rejected",[91,5894,5896,5898],{"className":5895},[94],[96,5897],{"disabled":98,"type":99}," Device does not expose firmware images in cleartext on the network",[11,5900,5901],{},"Document the test results with screenshots, logs, or automated test reports. These go into the Annex VII technical documentation file.",[21,5903,5905],{"id":5904},"ota-update-compliance-checklist","OTA Update Compliance Checklist",[11,5907,5908],{},[31,5909,5910],{},"Update mechanism",[86,5912,5914,5920,5926,5932],{"className":5913},[89],[91,5915,5917,5919],{"className":5916},[94],[96,5918],{"disabled":98,"type":99}," A/B or equivalent dual-slot update scheme implemented",[91,5921,5923,5925],{"className":5922},[94],[96,5924],{"disabled":98,"type":99}," Automatic rollback on failed update (image doesn't confirm within timeout)",[91,5927,5929,5931],{"className":5928},[94],[96,5930],{"disabled":98,"type":99}," Recovery mode available if both slots are corrupted",[91,5933,5935,5937],{"className":5934},[94],[96,5936],{"disabled":98,"type":99}," Power-loss resilience tested and documented",[11,5939,5940],{},[31,5941,5942],{},"Security",[86,5944,5946,5954,5960,5966,5972],{"className":5945},[89],[91,5947,5949,5951,5952,879],{"className":5948},[94],[96,5950],{"disabled":98,"type":99}," All updates cryptographically signed (same trust chain as ",[102,5953,210],{"href":209},[91,5955,5957,5959],{"className":5956},[94],[96,5958],{"disabled":98,"type":99}," Signature verified before installation on device",[91,5961,5963,5965],{"className":5962},[94],[96,5964],{"disabled":98,"type":99}," Transport channel encrypted (TLS 1.2+ or DTLS for constrained devices)",[91,5967,5969,5971],{"className":5968},[94],[96,5970],{"disabled":98,"type":99}," Anti-rollback protection prevents installation of older versions",[91,5973,5975,5977,5978],{"className":5974},[94],[96,5976],{"disabled":98,"type":99}," Update components listed in ",[102,5979,153],{"href":152},[11,5981,5982],{},[31,5983,5984],{},"Delivery",[86,5986,5988,5994,6000,6006],{"className":5987},[89],[91,5989,5991,5993],{"className":5990},[94],[96,5992],{"disabled":98,"type":99}," Security updates deliverable free of charge",[91,5995,5997,5999],{"className":5996},[94],[96,5998],{"disabled":98,"type":99}," Remote update capability (or documented justification for physical-access-only updates)",[91,6001,6003,6005],{"className":6002},[94],[96,6004],{"disabled":98,"type":99}," Update infrastructure operational and maintained",[91,6007,6009,6011],{"className":6008},[94],[96,6010],{"disabled":98,"type":99}," Staged rollout process documented",[11,6013,6014],{},[31,6015,6016],{},"Lifecycle",[86,6018,6020,6026,6032,6038],{"className":6019},[89],[91,6021,6023,6025],{"className":6022},[94],[96,6024],{"disabled":98,"type":99}," Support period declared (minimum 5 years from market placement)",[91,6027,6029,6031],{"className":6028},[94],[96,6030],{"disabled":98,"type":99}," End-of-life policy documented and communicated to customers",[91,6033,6035,6037],{"className":6034},[94],[96,6036],{"disabled":98,"type":99}," Key rotation plan covers the full product lifecycle",[91,6039,6041,6043],{"className":6040},[94],[96,6042],{"disabled":98,"type":99}," Update adoption metrics tracked",[11,6045,6046],{},[31,6047,5085],{},[86,6049,6051,6057,6063],{"className":6050},[89],[91,6052,6054,6056],{"className":6053},[94],[96,6055],{"disabled":98,"type":99}," Update mechanism described in Annex VII technical documentation",[91,6058,6060,6062],{"className":6059},[94],[96,6061],{"disabled":98,"type":99}," Test evidence for all positive, failure, and security scenarios",[91,6064,6066,784,6068,6071],{"className":6065},[94],[96,6067],{"disabled":98,"type":99},[102,6069,6070],{"href":911},"Vulnerability reporting"," to patching pipeline documented",[11,6073,2150,6074,6076],{},[102,6075,1475],{"href":1474}," assesses your update mechanism alongside your full Annex I posture and identifies specific gaps in your firmware update pipeline.",[1478,6078],{},[11,6080,6081],{},[1483,6082,6083],{},"Based on Regulation EU 2024/2847 Annex I Part I (Requirement 3), Annex I Part II (point 2), Article 13(8), Article 14, Annex VII. MCUboot, ESP-IDF, STM32 SBSFU, RAUC, Mender, and SWUpdate documentation. This does not constitute legal advice.",[21,6085,1489],{"id":1488},[86,6087,6088,6093,6099,6106,6112,6119,6126,6133],{},[91,6089,6090],{},[102,6091,1499],{"href":1496,"rel":6092},[1498],[91,6094,6095],{},[102,6096,6098],{"href":3158,"rel":6097},[1498],"MCUboot — Design documentation (swap modes)",[91,6100,6101],{},[102,6102,6105],{"href":6103,"rel":6104},"https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/esp_https_ota.html",[1498],"Espressif — ESP HTTPS OTA",[91,6107,6108],{},[102,6109,6111],{"href":5158,"rel":6110},[1498],"STMicroelectronics — SBSFU reference",[91,6113,6114],{},[102,6115,6118],{"href":6116,"rel":6117},"https://www.eclipse.org/hawkbit/",[1498],"Eclipse hawkBit — Update management",[91,6120,6121],{},[102,6122,6125],{"href":6123,"rel":6124},"https://docs.mender.io/",[1498],"Mender — OTA updates documentation",[91,6127,6128],{},[102,6129,6132],{"href":6130,"rel":6131},"https://rauc.io/",[1498],"RAUC — Robust Auto-Update Controller",[91,6134,6135],{},[102,6136,6139],{"href":6137,"rel":6138},"https://sbabic.github.io/swupdate/",[1498],"SWUpdate — Software Update for Embedded Linux",{"title":1536,"searchDepth":1537,"depth":1537,"links":6141},[6142,6147,6153,6157,6158,6161,6165,6169,6172,6173],{"id":5234,"depth":1537,"text":5235,"children":6143},[6144,6145,6146],{"id":5238,"depth":1542,"text":5239},{"id":5276,"depth":1542,"text":5277},{"id":5297,"depth":1542,"text":5298},{"id":5328,"depth":1537,"text":5329,"children":6148},[6149,6150,6151,6152],{"id":5335,"depth":1542,"text":5336},{"id":5378,"depth":1542,"text":5379},{"id":5421,"depth":1542,"text":5422},{"id":5448,"depth":1542,"text":5449},{"id":5532,"depth":1537,"text":5533,"children":6154},[6155,6156],{"id":5539,"depth":1542,"text":5540},{"id":5560,"depth":1542,"text":5561},{"id":5590,"depth":1537,"text":5591},{"id":5621,"depth":1537,"text":5622,"children":6159},[6160],{"id":5628,"depth":1542,"text":5629},{"id":5666,"depth":1537,"text":5667,"children":6162},[6163,6164],{"id":5673,"depth":1542,"text":5674},{"id":5709,"depth":1542,"text":5710},{"id":5733,"depth":1537,"text":5734,"children":6166},[6167,6168],{"id":5740,"depth":1542,"text":5741},{"id":5767,"depth":1542,"text":5768},{"id":5794,"depth":1537,"text":5795,"children":6170},[6171],{"id":5801,"depth":1542,"text":5802},{"id":5904,"depth":1537,"text":5905},{"id":1488,"depth":1537,"text":1489},"2026-01-22","Build a CRA-compliant OTA firmware update pipeline for MCU and embedded Linux products—free, timely, and meeting Annex I lifecycle requirements.","/images/blog/previews/ota-updates.svg",[6178,6179,6180,6181,6182,6183],"CRA OTA update","CRA firmware update requirements","secure OTA embedded","firmware update rollback CRA","MCUboot OTA","ESP-IDF OTA CRA",{},"/blog/cra-ota-firmware-updates","12 min",{"title":5219,"description":6175},"blog/cra-ota-firmware-updates","U3VBWkMxQi5kGzheIPkCZnJskkvUkV9qneMmZtQ8y0Q",{"id":6191,"title":6192,"body":6193,"date":8311,"description":8312,"extension":1577,"image":8313,"keywords":8314,"meta":8320,"navigation":98,"path":8321,"readTime":8322,"seo":8323,"stem":8324,"__hash__":8325},"blog/blog/zephyr-sbom-cra-compliance.md","From west spdx to a CRA-Compliant Zephyr SBOM",{"type":8,"value":6194,"toc":8280},[6195,6200,6203,6206,6218,6225,6230,6235,6249,6254,6274,6278,6284,6359,6365,6371,6425,6431,6449,6452,6456,6460,6463,6472,6476,6483,6486,6489,6493,6496,6501,6515,6519,6525,6529,6538,6541,6545,6548,6552,6555,6653,6659,6682,6686,6693,6699,6702,6965,6972,6976,6979,6985,6991,6994,7025,7028,7032,7039,7042,7171,7174,7203,7206,7223,7229,7233,7241,7244,7289,7292,7306,7313,7317,7320,7400,7405,7416,7421,7435,7438,7442,7445,7449,7469,7472,7475,7508,7512,7515,7518,7538,7545,7549,7552,7876,7879,7887,7893,7977,7983,7990,7995,8018,8023,8050,8055,8094,8099,8128,8133,8163,8168,8195,8206,8208,8213,8215,8276],[11,6196,2547,6197,6199],{},[377,6198,2550],{},". Run it after a build, and you'll get four SPDX files describing your application, Zephyr kernel, and build environment. It's one of the few RTOSes with any native SBOM tooling at all.",[11,6201,6202],{},"The problem is that the output is nearly useless for CRA compliance out of the box.",[11,6204,6205],{},"The generated SPDX files lack CPE and PURL identifiers, so vulnerability scanners can't match components to known CVEs. Subsystem components like the Bluetooth stack, MQTT library, and cJSON parser don't appear as discrete packages — they're compiled into the Zephyr kernel blob. Vendor HAL binary blobs are opaque. And the output is SPDX-only, with no CycloneDX option.",[11,6207,6208,6209,6211,6212,6215,6216,1603],{},"This tutorial covers what ",[377,6210,2550],{}," gives you, what it doesn't, and the step-by-step enrichment workflow to produce an SBOM that actually satisfies CRA Annex I Part II. For broader SBOM context, see our ",[102,6213,6214],{"href":152},"SBOM guide for firmware",". For the full Zephyr CRA picture, see our ",[102,6217,3231],{"href":603},[21,6219,6221,6222,6224],{"id":6220},"what-west-spdx-gives-you-and-what-it-doesnt","What ",[377,6223,2550],{}," Gives You (and What It Doesn't)",[11,6226,2150,6227,6229],{},[377,6228,2550],{}," command was added in Zephyr 3.x. It hooks into the CMake build system and generates SPDX 2.3 documents based on the source files and libraries that were actually compiled.",[11,6231,6232],{},[31,6233,6234],{},"What it does well:",[86,6236,6237,6240,6243,6246],{},[91,6238,6239],{},"Enumerates source files that went into the build (not the full manifest — only what was compiled)",[91,6241,6242],{},"Produces valid SPDX 2.3 documents",[91,6244,6245],{},"Generates four separate SPDX files: application, Zephyr kernel, build environment, and an overall document",[91,6247,6248],{},"Uses build-system data, so it reflects your actual configuration (Kconfig-dependent)",[11,6250,6251],{},[31,6252,6253],{},"What it doesn't do:",[86,6255,6256,6259,6262,6265,6268,6271],{},[91,6257,6258],{},"No CPE or PURL identifiers on any package — vulnerability scanners get nothing to match against",[91,6260,6261],{},"No version information derived from upstream sources — packages are identified by local path only",[91,6263,6264],{},"Subsystem components (Bluetooth, networking, USB) are rolled into the Zephyr kernel package, not listed individually",[91,6266,6267],{},"Vendor HAL modules (hal_stm32, hal_nordic, hal_nxp) appear as packages but with no upstream version or vulnerability identifiers",[91,6269,6270],{},"SPDX output only — no CycloneDX option",[91,6272,6273],{},"MCUboot (if used) is a separate build and isn't captured in the application's SPDX output",[21,6275,6277],{"id":6276},"step-by-step-generating-spdx-from-a-zephyr-build","Step by Step: Generating SPDX from a Zephyr Build",[11,6279,6280,6281,6283],{},"Start with a clean build. The ",[377,6282,2550],{}," command operates on the build directory, so it needs a completed build to analyse.",[2358,6285,6289],{"className":6286,"code":6287,"language":6288,"meta":1536,"style":1536},"language-bash shiki shiki-themes github-light github-dark","# Clean build for your board\nwest build -p always -b nrf52840dk/nrf52840 -- -DCONFIG_BOOTLOADER_MCUBOOT=y\n\n# Generate SPDX documents\nwest spdx -d build -n \"https://your-company.com/spdx\"\n","bash",[377,6290,6291,6300,6329,6334,6340],{"__ignoreMap":1536},[6292,6293,6296],"span",{"class":6294,"line":6295},"line",1,[6292,6297,6299],{"class":6298},"sJ8bj","# Clean build for your board\n",[6292,6301,6302,6306,6310,6314,6317,6320,6323,6326],{"class":6294,"line":1537},[6292,6303,6305],{"class":6304},"sScJk","west",[6292,6307,6309],{"class":6308},"sZZnC"," build",[6292,6311,6313],{"class":6312},"sj4cs"," -p",[6292,6315,6316],{"class":6308}," always",[6292,6318,6319],{"class":6312}," -b",[6292,6321,6322],{"class":6308}," nrf52840dk/nrf52840",[6292,6324,6325],{"class":6312}," --",[6292,6327,6328],{"class":6312}," -DCONFIG_BOOTLOADER_MCUBOOT=y\n",[6292,6330,6331],{"class":6294,"line":1542},[6292,6332,6333],{"emptyLinePlaceholder":98},"\n",[6292,6335,6337],{"class":6294,"line":6336},4,[6292,6338,6339],{"class":6298},"# Generate SPDX documents\n",[6292,6341,6343,6345,6348,6351,6353,6356],{"class":6294,"line":6342},5,[6292,6344,6305],{"class":6304},[6292,6346,6347],{"class":6308}," spdx",[6292,6349,6350],{"class":6312}," -d",[6292,6352,6309],{"class":6308},[6292,6354,6355],{"class":6312}," -n",[6292,6357,6358],{"class":6308}," \"https://your-company.com/spdx\"\n",[11,6360,2150,6361,6364],{},[377,6362,6363],{},"-n"," flag sets the SPDX namespace URI. Use your company's domain — this becomes the document namespace in the SPDX output.",[11,6366,6367,6368,1750],{},"This produces four files in ",[377,6369,6370],{},"build/spdx/",[1097,6372,6373,6383],{},[1100,6374,6375],{},[1103,6376,6377,6380],{},[1106,6378,6379],{},"File",[1106,6381,6382],{},"Contents",[1119,6384,6385,6395,6405,6415],{},[1103,6386,6387,6392],{},[1124,6388,6389],{},[377,6390,6391],{},"app.spdx",[1124,6393,6394],{},"Your application source files and libraries",[1103,6396,6397,6402],{},[1124,6398,6399],{},[377,6400,6401],{},"zephyr.spdx",[1124,6403,6404],{},"Zephyr kernel and all compiled subsystems",[1103,6406,6407,6412],{},[1124,6408,6409],{},[377,6410,6411],{},"build.spdx",[1124,6413,6414],{},"Build tools (compiler, linker)",[1103,6416,6417,6422],{},[1124,6418,6419],{},[377,6420,6421],{},"sdk.spdx",[1124,6423,6424],{},"Relationships between the above documents",[11,6426,6427,6428,6430],{},"Open ",[377,6429,6401],{}," and you'll see packages for Zephyr modules that were compiled. But try running a vulnerability scanner against it:",[2358,6432,6434],{"className":6286,"code":6433,"language":6288,"meta":1536,"style":1536},"# This will find almost nothing — no CPE/PURL to match against\ngrype sbom:build/spdx/zephyr.spdx\n",[377,6435,6436,6441],{"__ignoreMap":1536},[6292,6437,6438],{"class":6294,"line":6295},[6292,6439,6440],{"class":6298},"# This will find almost nothing — no CPE/PURL to match against\n",[6292,6442,6443,6446],{"class":6294,"line":1537},[6292,6444,6445],{"class":6304},"grype",[6292,6447,6448],{"class":6308}," sbom:build/spdx/zephyr.spdx\n",[11,6450,6451],{},"Zero or near-zero results. Not because your firmware has no vulnerabilities, but because the scanner has no identifiers to look up.",[21,6453,6455],{"id":6454},"the-5-gaps-that-make-raw-output-useless-for-cra","The 5 Gaps That Make Raw Output Useless for CRA",[45,6457,6459],{"id":6458},"gap-1-no-cpepurl-identifiers","Gap 1: No CPE/PURL Identifiers",[11,6461,6462],{},"This is the critical gap. The NTIA minimum SBOM elements (referenced by ENISA guidance) require \"other unique identifiers\" — specifically CPE or PURL — so that consumers of the SBOM can correlate components to vulnerability databases like NVD and OSV.",[11,6464,2150,6465,6467,6468,6471],{},[377,6466,2550],{}," output identifies packages by their local filesystem path (",[377,6469,6470],{},"/home/user/zephyrproject/modules/crypto/mbedtls","). No vulnerability scanner can do anything with this.",[45,6473,6475],{"id":6474},"gap-2-invisible-subsystem-components","Gap 2: Invisible Subsystem Components",[11,6477,6478,6479,6482],{},"When you enable Bluetooth in Zephyr (",[377,6480,6481],{},"CONFIG_BT=y","), the Bluetooth stack source files get compiled into the Zephyr kernel. In the SPDX output, these files appear under the main Zephyr package — there's no separate \"Bluetooth Host Stack\" package entry with its own version and identifiers.",[11,6484,6485],{},"The same applies to the networking stack (TCP/IP, MQTT, CoAP), USB, cJSON, and other subsystems. They're compiled-in library code, not discrete packages from the build system's perspective.",[11,6487,6488],{},"For CRA compliance, these are distinct components with distinct vulnerability histories and they need their own SBOM entries.",[45,6490,6492],{"id":6491},"gap-3-vendor-hal-binary-blobs","Gap 3: Vendor HAL Binary Blobs",[11,6494,6495],{},"Zephyr's HAL modules (hal_stm32, hal_nordic, hal_nxp, hal_espressif) contain vendor-provided code that often includes pre-compiled binary blobs — particularly for radio stacks (BLE SoftDevice on Nordic, WiFi firmware on ESP32).",[11,6497,2150,6498,6500],{},[377,6499,2550],{}," output will list the HAL module as a package, but:",[86,6502,6503,6506,6509,6512],{},[91,6504,6505],{},"The binary blob contents are completely opaque",[91,6507,6508],{},"No sub-components are enumerated",[91,6510,6511],{},"No vendor-provided SBOM is included",[91,6513,6514],{},"Vulnerability status of the binary code is unknown",[45,6516,6518],{"id":6517},"gap-4-spdx-only-no-cyclonedx","Gap 4: SPDX Only — No CycloneDX",[11,6520,6521,6522,6524],{},"Some organisations and tools prefer CycloneDX, and some supply chain requirements specify it. The ",[377,6523,2550],{}," command only outputs SPDX. Converting SPDX to CycloneDX is possible but lossy.",[45,6526,6528],{"id":6527},"gap-5-mcuboot-is-a-separate-build","Gap 5: MCUboot Is a Separate Build",[11,6530,6531,6532,6534,6535,6537],{},"If you're using MCUboot (and for CRA secure boot compliance, you should be — see our ",[102,6533,2370],{"href":209},"), it's built as a separate application. Running ",[377,6536,2550],{}," on your main application build doesn't capture MCUboot's dependencies. You need to generate and merge a separate SBOM for the bootloader.",[11,6539,6540],{},"Additionally, MCUboot has limited NVD coverage. Searching the NVD for \"MCUboot\" returns few or no results, even though security issues have been found and fixed. Your vulnerability scanning process needs to account for this.",[21,6542,6544],{"id":6543},"enriching-the-sbom-adding-cpepurl-identifiers","Enriching the SBOM: Adding CPE/PURL Identifiers",[11,6546,6547],{},"This is the hardest part and where no existing tooling helps you. You need to manually map each component to its upstream identity and add CPE/PURL identifiers.",[45,6549,6551],{"id":6550},"identifying-your-components","Identifying Your Components",[11,6553,6554],{},"First, extract the package list from the SPDX output and map each to its upstream source:",[1097,6556,6557,6573],{},[1100,6558,6559],{},[1103,6560,6561,6564,6567,6570],{},[1106,6562,6563],{},"Local package (from west spdx)",[1106,6565,6566],{},"Upstream component",[1106,6568,6569],{},"CPE",[1106,6571,6572],{},"PURL",[1119,6574,6575,6595,6615,6635],{},[1103,6576,6577,6582,6585,6590],{},[1124,6578,6579],{},[377,6580,6581],{},"modules/crypto/mbedtls",[1124,6583,6584],{},"Mbed TLS 3.6.2",[1124,6586,6587],{},[377,6588,6589],{},"cpe:2.3:a:arm:mbed_tls:3.6.2:*:*:*:*:*:*:*",[1124,6591,6592],{},[377,6593,6594],{},"pkg:github/Mbed-TLS/mbedtls@v3.6.2",[1103,6596,6597,6602,6605,6610],{},[1124,6598,6599],{},[377,6600,6601],{},"modules/lib/cjson",[1124,6603,6604],{},"cJSON 1.7.17",[1124,6606,6607],{},[377,6608,6609],{},"cpe:2.3:a:cjson_project:cjson:1.7.17:*:*:*:*:*:*:*",[1124,6611,6612],{},[377,6613,6614],{},"pkg:github/DaveGamble/cJSON@v1.7.17",[1103,6616,6617,6622,6625,6630],{},[1124,6618,6619],{},[377,6620,6621],{},"bootloader/mcuboot",[1124,6623,6624],{},"MCUboot 2.1.0",[1124,6626,6627],{},[377,6628,6629],{},"cpe:2.3:a:mcuboot:mcuboot:2.1.0:*:*:*:*:*:*:*",[1124,6631,6632],{},[377,6633,6634],{},"pkg:github/mcu-tools/mcuboot@v2.1.0",[1103,6636,6637,6642,6645,6648],{},[1124,6638,6639],{},[377,6640,6641],{},"modules/hal/nordic",[1124,6643,6644],{},"nRF Connect SDK HAL",[1124,6646,6647],{},"—",[1124,6649,6650],{},[377,6651,6652],{},"pkg:github/zephyrproject-rtos/hal_nordic@\u003Ccommit>",[11,6654,6655,6656,6658],{},"Get the exact versions from your ",[377,6657,2976],{}," manifest:",[2358,6660,6662],{"className":6286,"code":6661,"language":6288,"meta":1536,"style":1536},"# Check exact module revisions pinned in your manifest\nwest list --format \"{name} {revision} {url}\"\n",[377,6663,6664,6669],{"__ignoreMap":1536},[6292,6665,6666],{"class":6294,"line":6295},[6292,6667,6668],{"class":6298},"# Check exact module revisions pinned in your manifest\n",[6292,6670,6671,6673,6676,6679],{"class":6294,"line":1537},[6292,6672,6305],{"class":6304},[6292,6674,6675],{"class":6308}," list",[6292,6677,6678],{"class":6312}," --format",[6292,6680,6681],{"class":6308}," \"{name} {revision} {url}\"\n",[45,6683,6685],{"id":6684},"adding-identifiers-to-spdx","Adding Identifiers to SPDX",[11,6687,6688,6689,6692],{},"SPDX 2.3 supports external references on packages. For each package that's missing identifiers, add ",[377,6690,6691],{},"ExternalRef"," entries:",[2358,6694,6697],{"className":6695,"code":6696,"language":2363},[2361],"ExternalRef: SECURITY cpe23Type cpe:2.3:a:arm:mbed_tls:3.6.2:*:*:*:*:*:*:*\nExternalRef: PACKAGE-MANAGER purl pkg:github/Mbed-TLS/mbedtls@v3.6.2\n",[377,6698,6696],{"__ignoreMap":1536},[11,6700,6701],{},"You can script this. A basic approach:",[2358,6703,6707],{"className":6704,"code":6705,"language":6706,"meta":1536,"style":1536},"language-python shiki shiki-themes github-light github-dark","#!/usr/bin/env python3\n\"\"\"Add CPE/PURL identifiers to west spdx output.\"\"\"\n\n# Mapping of Zephyr module paths to upstream identifiers\nCOMPONENT_MAP = {\n    \"mbedtls\": {\n        \"cpe\": \"cpe:2.3:a:arm:mbed_tls:{version}:*:*:*:*:*:*:*\",\n        \"purl\": \"pkg:github/Mbed-TLS/mbedtls@v{version}\",\n    },\n    \"mcuboot\": {\n        \"cpe\": \"cpe:2.3:a:mcuboot:mcuboot:{version}:*:*:*:*:*:*:*\",\n        \"purl\": \"pkg:github/mcu-tools/mcuboot@v{version}\",\n    },\n    \"cjson\": {\n        \"cpe\": \"cpe:2.3:a:cjson_project:cjson:{version}:*:*:*:*:*:*:*\",\n        \"purl\": \"pkg:github/DaveGamble/cJSON@v{version}\",\n    },\n    \"littlefs\": {\n        \"cpe\": \"cpe:2.3:a:littlefs_project:littlefs:{version}:*:*:*:*:*:*:*\",\n        \"purl\": \"pkg:github/littlefs-project/littlefs@v{version}\",\n    },\n}\n\ndef enrich_spdx(spdx_path, versions):\n    \"\"\"Insert ExternalRef lines after matching PackageName entries.\"\"\"\n    with open(spdx_path, \"r\") as f:\n        lines = f.readlines()\n\n    enriched = []\n    for line in lines:\n        enriched.append(line)\n        if line.startswith(\"PackageName:\"):\n            pkg_name = line.split(\":\", 1)[1].strip().lower()\n            for key, refs in COMPONENT_MAP.items():\n                if key in pkg_name and key in versions:\n                    ver = versions[key]\n                    enriched.append(\n                        f'ExternalRef: SECURITY cpe23Type {refs[\"cpe\"].format(version=ver)}\\n'\n                    )\n                    enriched.append(\n                        f'ExternalRef: PACKAGE-MANAGER purl {refs[\"purl\"].format(version=ver)}\\n'\n                    )\n\n    with open(spdx_path, \"w\") as f:\n        f.writelines(enriched)\n","python",[377,6708,6709,6714,6719,6723,6728,6733,6739,6745,6751,6757,6763,6769,6775,6780,6786,6792,6798,6803,6809,6815,6821,6826,6832,6837,6843,6849,6855,6861,6866,6872,6878,6884,6890,6896,6902,6908,6914,6920,6926,6932,6937,6943,6948,6953,6959],{"__ignoreMap":1536},[6292,6710,6711],{"class":6294,"line":6295},[6292,6712,6713],{},"#!/usr/bin/env python3\n",[6292,6715,6716],{"class":6294,"line":1537},[6292,6717,6718],{},"\"\"\"Add CPE/PURL identifiers to west spdx output.\"\"\"\n",[6292,6720,6721],{"class":6294,"line":1542},[6292,6722,6333],{"emptyLinePlaceholder":98},[6292,6724,6725],{"class":6294,"line":6336},[6292,6726,6727],{},"# Mapping of Zephyr module paths to upstream identifiers\n",[6292,6729,6730],{"class":6294,"line":6342},[6292,6731,6732],{},"COMPONENT_MAP = {\n",[6292,6734,6736],{"class":6294,"line":6735},6,[6292,6737,6738],{},"    \"mbedtls\": {\n",[6292,6740,6742],{"class":6294,"line":6741},7,[6292,6743,6744],{},"        \"cpe\": \"cpe:2.3:a:arm:mbed_tls:{version}:*:*:*:*:*:*:*\",\n",[6292,6746,6748],{"class":6294,"line":6747},8,[6292,6749,6750],{},"        \"purl\": \"pkg:github/Mbed-TLS/mbedtls@v{version}\",\n",[6292,6752,6754],{"class":6294,"line":6753},9,[6292,6755,6756],{},"    },\n",[6292,6758,6760],{"class":6294,"line":6759},10,[6292,6761,6762],{},"    \"mcuboot\": {\n",[6292,6764,6766],{"class":6294,"line":6765},11,[6292,6767,6768],{},"        \"cpe\": \"cpe:2.3:a:mcuboot:mcuboot:{version}:*:*:*:*:*:*:*\",\n",[6292,6770,6772],{"class":6294,"line":6771},12,[6292,6773,6774],{},"        \"purl\": \"pkg:github/mcu-tools/mcuboot@v{version}\",\n",[6292,6776,6778],{"class":6294,"line":6777},13,[6292,6779,6756],{},[6292,6781,6783],{"class":6294,"line":6782},14,[6292,6784,6785],{},"    \"cjson\": {\n",[6292,6787,6789],{"class":6294,"line":6788},15,[6292,6790,6791],{},"        \"cpe\": \"cpe:2.3:a:cjson_project:cjson:{version}:*:*:*:*:*:*:*\",\n",[6292,6793,6795],{"class":6294,"line":6794},16,[6292,6796,6797],{},"        \"purl\": \"pkg:github/DaveGamble/cJSON@v{version}\",\n",[6292,6799,6801],{"class":6294,"line":6800},17,[6292,6802,6756],{},[6292,6804,6806],{"class":6294,"line":6805},18,[6292,6807,6808],{},"    \"littlefs\": {\n",[6292,6810,6812],{"class":6294,"line":6811},19,[6292,6813,6814],{},"        \"cpe\": \"cpe:2.3:a:littlefs_project:littlefs:{version}:*:*:*:*:*:*:*\",\n",[6292,6816,6818],{"class":6294,"line":6817},20,[6292,6819,6820],{},"        \"purl\": \"pkg:github/littlefs-project/littlefs@v{version}\",\n",[6292,6822,6824],{"class":6294,"line":6823},21,[6292,6825,6756],{},[6292,6827,6829],{"class":6294,"line":6828},22,[6292,6830,6831],{},"}\n",[6292,6833,6835],{"class":6294,"line":6834},23,[6292,6836,6333],{"emptyLinePlaceholder":98},[6292,6838,6840],{"class":6294,"line":6839},24,[6292,6841,6842],{},"def enrich_spdx(spdx_path, versions):\n",[6292,6844,6846],{"class":6294,"line":6845},25,[6292,6847,6848],{},"    \"\"\"Insert ExternalRef lines after matching PackageName entries.\"\"\"\n",[6292,6850,6852],{"class":6294,"line":6851},26,[6292,6853,6854],{},"    with open(spdx_path, \"r\") as f:\n",[6292,6856,6858],{"class":6294,"line":6857},27,[6292,6859,6860],{},"        lines = f.readlines()\n",[6292,6862,6864],{"class":6294,"line":6863},28,[6292,6865,6333],{"emptyLinePlaceholder":98},[6292,6867,6869],{"class":6294,"line":6868},29,[6292,6870,6871],{},"    enriched = []\n",[6292,6873,6875],{"class":6294,"line":6874},30,[6292,6876,6877],{},"    for line in lines:\n",[6292,6879,6881],{"class":6294,"line":6880},31,[6292,6882,6883],{},"        enriched.append(line)\n",[6292,6885,6887],{"class":6294,"line":6886},32,[6292,6888,6889],{},"        if line.startswith(\"PackageName:\"):\n",[6292,6891,6893],{"class":6294,"line":6892},33,[6292,6894,6895],{},"            pkg_name = line.split(\":\", 1)[1].strip().lower()\n",[6292,6897,6899],{"class":6294,"line":6898},34,[6292,6900,6901],{},"            for key, refs in COMPONENT_MAP.items():\n",[6292,6903,6905],{"class":6294,"line":6904},35,[6292,6906,6907],{},"                if key in pkg_name and key in versions:\n",[6292,6909,6911],{"class":6294,"line":6910},36,[6292,6912,6913],{},"                    ver = versions[key]\n",[6292,6915,6917],{"class":6294,"line":6916},37,[6292,6918,6919],{},"                    enriched.append(\n",[6292,6921,6923],{"class":6294,"line":6922},38,[6292,6924,6925],{},"                        f'ExternalRef: SECURITY cpe23Type {refs[\"cpe\"].format(version=ver)}\\n'\n",[6292,6927,6929],{"class":6294,"line":6928},39,[6292,6930,6931],{},"                    )\n",[6292,6933,6935],{"class":6294,"line":6934},40,[6292,6936,6919],{},[6292,6938,6940],{"class":6294,"line":6939},41,[6292,6941,6942],{},"                        f'ExternalRef: PACKAGE-MANAGER purl {refs[\"purl\"].format(version=ver)}\\n'\n",[6292,6944,6946],{"class":6294,"line":6945},42,[6292,6947,6931],{},[6292,6949,6951],{"class":6294,"line":6950},43,[6292,6952,6333],{"emptyLinePlaceholder":98},[6292,6954,6956],{"class":6294,"line":6955},44,[6292,6957,6958],{},"    with open(spdx_path, \"w\") as f:\n",[6292,6960,6962],{"class":6294,"line":6961},45,[6292,6963,6964],{},"        f.writelines(enriched)\n",[11,6966,6967,6968,6971],{},"This is a starting point — you'll need to extend the ",[377,6969,6970],{},"COMPONENT_MAP"," for every third-party module in your build.",[21,6973,6975],{"id":6974},"documenting-vendor-hal-binary-blobs","Documenting Vendor HAL Binary Blobs",[11,6977,6978],{},"Vendor HAL modules require special treatment. You can't enumerate the contents of a pre-compiled binary blob, but CRA still requires you to document what's in your firmware.",[11,6980,6981,6982,6984],{},"For each binary blob, add a package entry with ",[377,6983,2591],{}," for fields you genuinely cannot determine:",[2358,6986,6989],{"className":6987,"code":6988,"language":2363},[2361],"PackageName: Nordic SoftDevice S140\nSPDXID: SPDXRef-softdevice-s140\nPackageVersion: 7.3.0\nPackageSupplier: Organization: Nordic Semiconductor\nPackageDownloadLocation: NOASSERTION\nFilesAnalyzed: false\nPackageVerificationCode: NOASSERTION (binary blob — source not available)\nPackageLicenseConcluded: LicenseRef-Nordic-Proprietary\nPackageLicenseDeclared: LicenseRef-Nordic-Proprietary\nPackageCopyrightText: Copyright Nordic Semiconductor ASA\nExternalRef: PACKAGE-MANAGER purl pkg:generic/nordic/softdevice-s140@7.3.0\nPackageComment: Pre-compiled binary blob provided by Nordic Semiconductor.\n  Source code not available. Vulnerability assessment depends on vendor advisories.\n",[377,6990,6988],{"__ignoreMap":1536},[11,6992,6993],{},"Key points for binary blob documentation:",[86,6995,6996,7003,7009,7016,7022],{},[91,6997,6998,6999,7002],{},"Set ",[377,7000,7001],{},"FilesAnalyzed: false"," — you can't inspect the source",[91,7004,7005,7006,7008],{},"Use ",[377,7007,2591],{}," for verification codes and download locations you don't have",[91,7010,7011,7012,7015],{},"Add a ",[377,7013,7014],{},"PackageComment"," explaining why information is limited",[91,7017,7005,7018,7021],{},[377,7019,7020],{},"pkg:generic/"," PURL type for vendor-specific packages without a standard package manager",[91,7023,7024],{},"Track the vendor's security advisories separately — NVD won't cover these",[11,7026,7027],{},"Request SBOMs from your silicon vendors. More vendors are providing them (Nordic, NXP, and STMicroelectronics all have SBOM initiatives), but you may need to ask.",[21,7029,7031],{"id":7030},"adding-invisible-components","Adding Invisible Components",[11,7033,7034,7035,7038],{},"Zephyr subsystems that are compiled in but don't appear as discrete SPDX packages need to be added manually. Which ones depend on your Kconfig — check your build's ",[377,7036,7037],{},".config"," file.",[11,7040,7041],{},"Common invisible components to add:",[1097,7043,7044,7057],{},[1100,7045,7046],{},[1103,7047,7048,7051,7054],{},[1106,7049,7050],{},"Kconfig option",[1106,7052,7053],{},"Component to add",[1106,7055,7056],{},"How to determine version",[1119,7058,7059,7071,7083,7095,7107,7119,7135,7147,7159],{},[1103,7060,7061,7065,7068],{},[1124,7062,7063],{},[377,7064,6481],{},[1124,7066,7067],{},"Zephyr Bluetooth Host Stack",[1124,7069,7070],{},"Same as your Zephyr version",[1103,7072,7073,7078,7081],{},[1124,7074,7075],{},[377,7076,7077],{},"CONFIG_BT_CTLR=y",[1124,7079,7080],{},"Zephyr Bluetooth Controller",[1124,7082,7070],{},[1103,7084,7085,7090,7093],{},[1124,7086,7087],{},[377,7088,7089],{},"CONFIG_MQTT_LIB=y",[1124,7091,7092],{},"Zephyr MQTT Library",[1124,7094,7070],{},[1103,7096,7097,7102,7105],{},[1124,7098,7099],{},[377,7100,7101],{},"CONFIG_NET_TCP=y",[1124,7103,7104],{},"Zephyr TCP/IP Stack",[1124,7106,7070],{},[1103,7108,7109,7114,7117],{},[1124,7110,7111],{},[377,7112,7113],{},"CONFIG_HTTP_CLIENT=y",[1124,7115,7116],{},"Zephyr HTTP Client",[1124,7118,7070],{},[1103,7120,7121,7126,7129],{},[1124,7122,7123],{},[377,7124,7125],{},"CONFIG_CJSON_LIB=y",[1124,7127,7128],{},"cJSON",[1124,7130,7131,7132,7134],{},"Check ",[377,7133,6601],{}," revision",[1103,7136,7137,7142,7145],{},[1124,7138,7139],{},[377,7140,7141],{},"CONFIG_LWM2M=y",[1124,7143,7144],{},"Zephyr LwM2M Engine",[1124,7146,7070],{},[1103,7148,7149,7154,7157],{},[1124,7150,7151],{},[377,7152,7153],{},"CONFIG_COAP=y",[1124,7155,7156],{},"Zephyr CoAP Library",[1124,7158,7070],{},[1103,7160,7161,7166,7169],{},[1124,7162,7163],{},[377,7164,7165],{},"CONFIG_USB_DEVICE_STACK=y",[1124,7167,7168],{},"Zephyr USB Device Stack",[1124,7170,7070],{},[11,7172,7173],{},"Script the detection from your build configuration:",[2358,7175,7177],{"className":6286,"code":7176,"language":6288,"meta":1536,"style":1536},"# Extract enabled subsystems from the build config\ngrep -E \"^CONFIG_(BT|MQTT|NET_TCP|HTTP|CJSON|LWM2M|COAP|USB_DEVICE)=\" \\\n  build/zephyr/.config\n",[377,7178,7179,7184,7198],{"__ignoreMap":1536},[6292,7180,7181],{"class":6294,"line":6295},[6292,7182,7183],{"class":6298},"# Extract enabled subsystems from the build config\n",[6292,7185,7186,7189,7192,7195],{"class":6294,"line":1537},[6292,7187,7188],{"class":6304},"grep",[6292,7190,7191],{"class":6312}," -E",[6292,7193,7194],{"class":6308}," \"^CONFIG_(BT|MQTT|NET_TCP|HTTP|CJSON|LWM2M|COAP|USB_DEVICE)=\"",[6292,7196,7197],{"class":6312}," \\\n",[6292,7199,7200],{"class":6294,"line":1542},[6292,7201,7202],{"class":6308},"  build/zephyr/.config\n",[11,7204,7205],{},"For each enabled subsystem, add a package entry to your SPDX document with:",[86,7207,7208,7211,7220],{},[91,7209,7210],{},"The Zephyr version as the package version (these are part of the Zephyr source tree)",[91,7212,7213,7214,2409,7217,879],{},"A relationship to the main Zephyr kernel package (",[377,7215,7216],{},"CONTAINS",[377,7218,7219],{},"DEPENDS_ON",[91,7221,7222],{},"A PURL pointing to the Zephyr project with the subsystem path",[2358,7224,7227],{"className":7225,"code":7226,"language":2363},[2361],"PackageName: Zephyr Bluetooth Host Stack\nSPDXID: SPDXRef-zephyr-bluetooth\nPackageVersion: 3.7.0\nPackageSupplier: Organization: Zephyr Project\nPackageDownloadLocation: https://github.com/zephyrproject-rtos/zephyr\nFilesAnalyzed: false\nPackageLicenseConcluded: Apache-2.0\nPackageLicenseDeclared: Apache-2.0\nPackageCopyrightText: Copyright Zephyr Project Contributors\nExternalRef: PACKAGE-MANAGER purl pkg:github/zephyrproject-rtos/zephyr@v3.7.0#subsys/bluetooth\nRelationship: SPDXRef-zephyr-kernel CONTAINS SPDXRef-zephyr-bluetooth\n",[377,7228,7226],{"__ignoreMap":1536},[21,7230,7232],{"id":7231},"merging-the-4-spdx-files-into-one-document","Merging the 4 SPDX Files into One Document",[11,7234,7235,7236,784,7238,7240],{},"For submission to market surveillance authorities and for tooling compatibility, you'll want a single SPDX document rather than four separate files. The ",[377,7237,2550],{},[377,7239,6421],{}," file provides relationships between the documents, but many tools expect a single file.",[11,7242,7243],{},"Use the SPDX tools Python library:",[2358,7245,7247],{"className":6286,"code":7246,"language":6288,"meta":1536,"style":1536},"pip install spdx-tools\n\n# Validate individual files first\npyspdx-tv parse build/spdx/app.spdx\npyspdx-tv parse build/spdx/zephyr.spdx\n",[377,7248,7249,7260,7264,7269,7280],{"__ignoreMap":1536},[6292,7250,7251,7254,7257],{"class":6294,"line":6295},[6292,7252,7253],{"class":6304},"pip",[6292,7255,7256],{"class":6308}," install",[6292,7258,7259],{"class":6308}," spdx-tools\n",[6292,7261,7262],{"class":6294,"line":1537},[6292,7263,6333],{"emptyLinePlaceholder":98},[6292,7265,7266],{"class":6294,"line":1542},[6292,7267,7268],{"class":6298},"# Validate individual files first\n",[6292,7270,7271,7274,7277],{"class":6294,"line":6336},[6292,7272,7273],{"class":6304},"pyspdx-tv",[6292,7275,7276],{"class":6308}," parse",[6292,7278,7279],{"class":6308}," build/spdx/app.spdx\n",[6292,7281,7282,7284,7286],{"class":6294,"line":6342},[6292,7283,7273],{"class":6304},[6292,7285,7276],{"class":6308},[6292,7287,7288],{"class":6308}," build/spdx/zephyr.spdx\n",[11,7290,7291],{},"For merging, write a script that:",[1013,7293,7294,7297,7300,7303],{},[91,7295,7296],{},"Reads all four SPDX documents",[91,7298,7299],{},"Assigns unique SPDX IDs across documents (prefix with document origin to avoid collisions)",[91,7301,7302],{},"Combines all packages, files, and relationships into a single document",[91,7304,7305],{},"Updates the document namespace and creation info",[11,7307,7308,7309,7312],{},"Alternatively, use SPDX JSON format (",[377,7310,7311],{},"west spdx -d build --output-format json",") if your toolchain handles JSON better — the merge is simpler with JSON than with SPDX tag-value format.",[21,7314,7316],{"id":7315},"converting-to-cyclonedx","Converting to CycloneDX",[11,7318,7319],{},"If your supply chain requires CycloneDX, you can convert the enriched SPDX output. Be aware that the conversion is lossy.",[2358,7321,7323],{"className":6286,"code":7322,"language":6288,"meta":1536,"style":1536},"# Install the CycloneDX CLI tool\nnpm install -g @cyclonedx/cyclonedx-cli\n\n# Convert SPDX to CycloneDX\ncyclonedx-cli convert \\\n  --input-file build/spdx/merged.spdx \\\n  --input-format spdxjson \\\n  --output-file firmware-sbom.cdx.json \\\n  --output-format json\n",[377,7324,7325,7330,7343,7347,7352,7362,7372,7382,7392],{"__ignoreMap":1536},[6292,7326,7327],{"class":6294,"line":6295},[6292,7328,7329],{"class":6298},"# Install the CycloneDX CLI tool\n",[6292,7331,7332,7335,7337,7340],{"class":6294,"line":1537},[6292,7333,7334],{"class":6304},"npm",[6292,7336,7256],{"class":6308},[6292,7338,7339],{"class":6312}," -g",[6292,7341,7342],{"class":6308}," @cyclonedx/cyclonedx-cli\n",[6292,7344,7345],{"class":6294,"line":1542},[6292,7346,6333],{"emptyLinePlaceholder":98},[6292,7348,7349],{"class":6294,"line":6336},[6292,7350,7351],{"class":6298},"# Convert SPDX to CycloneDX\n",[6292,7353,7354,7357,7360],{"class":6294,"line":6342},[6292,7355,7356],{"class":6304},"cyclonedx-cli",[6292,7358,7359],{"class":6308}," convert",[6292,7361,7197],{"class":6312},[6292,7363,7364,7367,7370],{"class":6294,"line":6735},[6292,7365,7366],{"class":6312},"  --input-file",[6292,7368,7369],{"class":6308}," build/spdx/merged.spdx",[6292,7371,7197],{"class":6312},[6292,7373,7374,7377,7380],{"class":6294,"line":6741},[6292,7375,7376],{"class":6312},"  --input-format",[6292,7378,7379],{"class":6308}," spdxjson",[6292,7381,7197],{"class":6312},[6292,7383,7384,7387,7390],{"class":6294,"line":6747},[6292,7385,7386],{"class":6312},"  --output-file",[6292,7388,7389],{"class":6308}," firmware-sbom.cdx.json",[6292,7391,7197],{"class":6312},[6292,7393,7394,7397],{"class":6294,"line":6753},[6292,7395,7396],{"class":6312},"  --output-format",[6292,7398,7399],{"class":6308}," json\n",[11,7401,7402],{},[31,7403,7404],{},"What gets lost in conversion:",[86,7406,7407,7410,7413],{},[91,7408,7409],{},"SPDX file-level entries (CycloneDX focuses on components, not individual source files)",[91,7411,7412],{},"Some relationship types that don't have CycloneDX equivalents",[91,7414,7415],{},"SPDX-specific annotations and review information",[11,7417,7418],{},[31,7419,7420],{},"What converts cleanly:",[86,7422,7423,7426,7429,7432],{},[91,7424,7425],{},"Package names, versions, and suppliers",[91,7427,7428],{},"CPE and PURL identifiers (this is why enrichment matters — identifiers survive conversion)",[91,7430,7431],{},"License information",[91,7433,7434],{},"Dependency relationships (mapped to CycloneDX dependency graph)",[11,7436,7437],{},"If you need both formats, generate the enriched SPDX as your source of truth and derive CycloneDX from it. Don't maintain two parallel SBOMs.",[21,7439,7441],{"id":7440},"running-vulnerability-scanners-against-the-enriched-sbom","Running Vulnerability Scanners Against the Enriched SBOM",[11,7443,7444],{},"With CPE/PURL identifiers in place, vulnerability scanners can actually do their job.",[45,7446,7448],{"id":7447},"osv-scanner","OSV-Scanner",[2358,7450,7452],{"className":6286,"code":7451,"language":6288,"meta":1536,"style":1536},"# OSV-Scanner works well with SPDX\nosv-scanner --sbom build/spdx/merged-enriched.spdx\n",[377,7453,7454,7459],{"__ignoreMap":1536},[6292,7455,7456],{"class":6294,"line":6295},[6292,7457,7458],{"class":6298},"# OSV-Scanner works well with SPDX\n",[6292,7460,7461,7463,7466],{"class":6294,"line":1537},[6292,7462,7447],{"class":6304},[6292,7464,7465],{"class":6312}," --sbom",[6292,7467,7468],{"class":6308}," build/spdx/merged-enriched.spdx\n",[11,7470,7471],{},"OSV-Scanner queries the OSV database, which aggregates vulnerabilities from multiple sources including NVD, GitHub Advisories, and project-specific databases.",[45,7473,7474],{"id":6445},"Grype",[2358,7476,7478],{"className":6286,"code":7477,"language":6288,"meta":1536,"style":1536},"# Grype supports both SPDX and CycloneDX\ngrype sbom:build/spdx/merged-enriched.spdx\n\n# Or against the CycloneDX version\ngrype sbom:firmware-sbom.cdx.json\n",[377,7479,7480,7485,7492,7496,7501],{"__ignoreMap":1536},[6292,7481,7482],{"class":6294,"line":6295},[6292,7483,7484],{"class":6298},"# Grype supports both SPDX and CycloneDX\n",[6292,7486,7487,7489],{"class":6294,"line":1537},[6292,7488,6445],{"class":6304},[6292,7490,7491],{"class":6308}," sbom:build/spdx/merged-enriched.spdx\n",[6292,7493,7494],{"class":6294,"line":1542},[6292,7495,6333],{"emptyLinePlaceholder":98},[6292,7497,7498],{"class":6294,"line":6336},[6292,7499,7500],{"class":6298},"# Or against the CycloneDX version\n",[6292,7502,7503,7505],{"class":6294,"line":6342},[6292,7504,6445],{"class":6304},[6292,7506,7507],{"class":6308}," sbom:firmware-sbom.cdx.json\n",[45,7509,7511],{"id":7510},"interpreting-results","Interpreting Results",[11,7513,7514],{},"Expect false positives. Embedded firmware often uses stripped-down configurations of libraries. A vulnerability in Mbed TLS's X.509 parsing doesn't affect your build if you've disabled X.509 entirely via Kconfig.",[11,7516,7517],{},"This is where VEX (Vulnerability Exploitability eXchange) documents come in. For each scanner result, determine:",[86,7519,7520,7526,7532],{},[91,7521,7522,7525],{},[31,7523,7524],{},"Affected:"," The vulnerable code path exists in your build and is reachable",[91,7527,7528,7531],{},[31,7529,7530],{},"Not affected:"," The vulnerable code is compiled out (Kconfig), not reachable, or mitigated by other controls",[91,7533,7534,7537],{},[31,7535,7536],{},"Under investigation:"," You need to analyse further",[11,7539,7540,7541,7544],{},"Document your VEX assessments — CRA Article 14 requires you to track and communicate vulnerability status. See our ",[102,7542,7543],{"href":911},"vulnerability reporting guide"," for the full process.",[21,7546,7548],{"id":7547},"cicd-integration-sbom-on-every-build","CI/CD Integration: SBOM on Every Build",[11,7550,7551],{},"Generate the SBOM as part of your CI pipeline, not as a manual step. This ensures every release has a corresponding SBOM and prevents drift between what's documented and what's shipped.",[2358,7553,7557],{"className":7554,"code":7555,"language":7556,"meta":1536,"style":1536},"language-yaml shiki shiki-themes github-light github-dark","# Example GitHub Actions workflow\nname: Firmware Build + SBOM\n\non:\n  push:\n    tags: [\"v*\"]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    container:\n      image: ghcr.io/zephyrproject-rtos/ci:v0.27\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: West init and update\n        run: |\n          west init -l .\n          west update\n\n      - name: Build firmware\n        run: west build -p always -b ${{ env.BOARD }}\n\n      - name: Generate SPDX\n        run: west spdx -d build -n \"https://your-company.com/spdx/${{ github.ref_name }}\"\n\n      - name: Enrich SBOM\n        run: python scripts/enrich-sbom.py build/spdx/ --manifest west.yml\n\n      - name: Scan for vulnerabilities\n        run: |\n          osv-scanner --sbom build/spdx/merged-enriched.spdx\n\n      - name: Upload SBOM artifacts\n        uses: actions/upload-artifact@v4\n        with:\n          name: sbom-${{ github.ref_name }}\n          path: |\n            build/spdx/merged-enriched.spdx\n            firmware-sbom.cdx.json\n","yaml",[377,7558,7559,7564,7577,7581,7589,7596,7610,7614,7621,7628,7638,7645,7655,7659,7666,7679,7683,7694,7705,7710,7715,7719,7730,7739,7743,7754,7763,7767,7778,7787,7791,7802,7810,7815,7819,7830,7840,7847,7857,7866,7871],{"__ignoreMap":1536},[6292,7560,7561],{"class":6294,"line":6295},[6292,7562,7563],{"class":6298},"# Example GitHub Actions workflow\n",[6292,7565,7566,7570,7574],{"class":6294,"line":1537},[6292,7567,7569],{"class":7568},"s9eBZ","name",[6292,7571,7573],{"class":7572},"sVt8B",": ",[6292,7575,7576],{"class":6308},"Firmware Build + SBOM\n",[6292,7578,7579],{"class":6294,"line":1542},[6292,7580,6333],{"emptyLinePlaceholder":98},[6292,7582,7583,7586],{"class":6294,"line":6336},[6292,7584,7585],{"class":6312},"on",[6292,7587,7588],{"class":7572},":\n",[6292,7590,7591,7594],{"class":6294,"line":6342},[6292,7592,7593],{"class":7568},"  push",[6292,7595,7588],{"class":7572},[6292,7597,7598,7601,7604,7607],{"class":6294,"line":6735},[6292,7599,7600],{"class":7568},"    tags",[6292,7602,7603],{"class":7572},": [",[6292,7605,7606],{"class":6308},"\"v*\"",[6292,7608,7609],{"class":7572},"]\n",[6292,7611,7612],{"class":6294,"line":6741},[6292,7613,6333],{"emptyLinePlaceholder":98},[6292,7615,7616,7619],{"class":6294,"line":6747},[6292,7617,7618],{"class":7568},"jobs",[6292,7620,7588],{"class":7572},[6292,7622,7623,7626],{"class":6294,"line":6753},[6292,7624,7625],{"class":7568},"  build",[6292,7627,7588],{"class":7572},[6292,7629,7630,7633,7635],{"class":6294,"line":6759},[6292,7631,7632],{"class":7568},"    runs-on",[6292,7634,7573],{"class":7572},[6292,7636,7637],{"class":6308},"ubuntu-latest\n",[6292,7639,7640,7643],{"class":6294,"line":6765},[6292,7641,7642],{"class":7568},"    container",[6292,7644,7588],{"class":7572},[6292,7646,7647,7650,7652],{"class":6294,"line":6771},[6292,7648,7649],{"class":7568},"      image",[6292,7651,7573],{"class":7572},[6292,7653,7654],{"class":6308},"ghcr.io/zephyrproject-rtos/ci:v0.27\n",[6292,7656,7657],{"class":6294,"line":6777},[6292,7658,6333],{"emptyLinePlaceholder":98},[6292,7660,7661,7664],{"class":6294,"line":6782},[6292,7662,7663],{"class":7568},"    steps",[6292,7665,7588],{"class":7572},[6292,7667,7668,7671,7674,7676],{"class":6294,"line":6788},[6292,7669,7670],{"class":7572},"      - ",[6292,7672,7673],{"class":7568},"uses",[6292,7675,7573],{"class":7572},[6292,7677,7678],{"class":6308},"actions/checkout@v4\n",[6292,7680,7681],{"class":6294,"line":6794},[6292,7682,6333],{"emptyLinePlaceholder":98},[6292,7684,7685,7687,7689,7691],{"class":6294,"line":6800},[6292,7686,7670],{"class":7572},[6292,7688,7569],{"class":7568},[6292,7690,7573],{"class":7572},[6292,7692,7693],{"class":6308},"West init and update\n",[6292,7695,7696,7699,7701],{"class":6294,"line":6805},[6292,7697,7698],{"class":7568},"        run",[6292,7700,7573],{"class":7572},[6292,7702,7704],{"class":7703},"szBVR","|\n",[6292,7706,7707],{"class":6294,"line":6811},[6292,7708,7709],{"class":6308},"          west init -l .\n",[6292,7711,7712],{"class":6294,"line":6817},[6292,7713,7714],{"class":6308},"          west update\n",[6292,7716,7717],{"class":6294,"line":6823},[6292,7718,6333],{"emptyLinePlaceholder":98},[6292,7720,7721,7723,7725,7727],{"class":6294,"line":6828},[6292,7722,7670],{"class":7572},[6292,7724,7569],{"class":7568},[6292,7726,7573],{"class":7572},[6292,7728,7729],{"class":6308},"Build firmware\n",[6292,7731,7732,7734,7736],{"class":6294,"line":6834},[6292,7733,7698],{"class":7568},[6292,7735,7573],{"class":7572},[6292,7737,7738],{"class":6308},"west build -p always -b ${{ env.BOARD }}\n",[6292,7740,7741],{"class":6294,"line":6839},[6292,7742,6333],{"emptyLinePlaceholder":98},[6292,7744,7745,7747,7749,7751],{"class":6294,"line":6845},[6292,7746,7670],{"class":7572},[6292,7748,7569],{"class":7568},[6292,7750,7573],{"class":7572},[6292,7752,7753],{"class":6308},"Generate SPDX\n",[6292,7755,7756,7758,7760],{"class":6294,"line":6851},[6292,7757,7698],{"class":7568},[6292,7759,7573],{"class":7572},[6292,7761,7762],{"class":6308},"west spdx -d build -n \"https://your-company.com/spdx/${{ github.ref_name }}\"\n",[6292,7764,7765],{"class":6294,"line":6857},[6292,7766,6333],{"emptyLinePlaceholder":98},[6292,7768,7769,7771,7773,7775],{"class":6294,"line":6863},[6292,7770,7670],{"class":7572},[6292,7772,7569],{"class":7568},[6292,7774,7573],{"class":7572},[6292,7776,7777],{"class":6308},"Enrich SBOM\n",[6292,7779,7780,7782,7784],{"class":6294,"line":6868},[6292,7781,7698],{"class":7568},[6292,7783,7573],{"class":7572},[6292,7785,7786],{"class":6308},"python scripts/enrich-sbom.py build/spdx/ --manifest west.yml\n",[6292,7788,7789],{"class":6294,"line":6874},[6292,7790,6333],{"emptyLinePlaceholder":98},[6292,7792,7793,7795,7797,7799],{"class":6294,"line":6880},[6292,7794,7670],{"class":7572},[6292,7796,7569],{"class":7568},[6292,7798,7573],{"class":7572},[6292,7800,7801],{"class":6308},"Scan for vulnerabilities\n",[6292,7803,7804,7806,7808],{"class":6294,"line":6886},[6292,7805,7698],{"class":7568},[6292,7807,7573],{"class":7572},[6292,7809,7704],{"class":7703},[6292,7811,7812],{"class":6294,"line":6892},[6292,7813,7814],{"class":6308},"          osv-scanner --sbom build/spdx/merged-enriched.spdx\n",[6292,7816,7817],{"class":6294,"line":6898},[6292,7818,6333],{"emptyLinePlaceholder":98},[6292,7820,7821,7823,7825,7827],{"class":6294,"line":6904},[6292,7822,7670],{"class":7572},[6292,7824,7569],{"class":7568},[6292,7826,7573],{"class":7572},[6292,7828,7829],{"class":6308},"Upload SBOM artifacts\n",[6292,7831,7832,7835,7837],{"class":6294,"line":6910},[6292,7833,7834],{"class":7568},"        uses",[6292,7836,7573],{"class":7572},[6292,7838,7839],{"class":6308},"actions/upload-artifact@v4\n",[6292,7841,7842,7845],{"class":6294,"line":6916},[6292,7843,7844],{"class":7568},"        with",[6292,7846,7588],{"class":7572},[6292,7848,7849,7852,7854],{"class":6294,"line":6922},[6292,7850,7851],{"class":7568},"          name",[6292,7853,7573],{"class":7572},[6292,7855,7856],{"class":6308},"sbom-${{ github.ref_name }}\n",[6292,7858,7859,7862,7864],{"class":6294,"line":6928},[6292,7860,7861],{"class":7568},"          path",[6292,7863,7573],{"class":7572},[6292,7865,7704],{"class":7703},[6292,7867,7868],{"class":6294,"line":6934},[6292,7869,7870],{"class":6308},"            build/spdx/merged-enriched.spdx\n",[6292,7872,7873],{"class":6294,"line":6939},[6292,7874,7875],{"class":6308},"            firmware-sbom.cdx.json\n",[11,7877,7878],{},"Tag the SBOM with the release version. When a market surveillance authority requests documentation, you need to produce the SBOM that matches the specific firmware version deployed.",[21,7880,7882,7883,7886],{"id":7881},"nordic-west-ncs-sbom-comparison","Nordic ",[377,7884,7885],{},"west ncs-sbom"," Comparison",[11,7888,7889,7890,7892],{},"If you're using the nRF Connect SDK (which is built on Zephyr), Nordic provides ",[377,7891,7885],{}," — a separate SBOM tool with different goals.",[1097,7894,7895,7911],{},[1100,7896,7897],{},[1103,7898,7899,7901,7906],{},[1106,7900,4733],{},[1106,7902,7903,7905],{},[377,7904,2550],{}," (Zephyr)",[1106,7907,7908,7910],{},[377,7909,7885],{}," (Nordic)",[1119,7912,7913,7924,7935,7945,7956,7967],{},[1103,7914,7915,7918,7921],{},[1124,7916,7917],{},"Primary focus",[1124,7919,7920],{},"Build-accurate source enumeration",[1124,7922,7923],{},"License compliance",[1103,7925,7926,7929,7932],{},[1124,7927,7928],{},"Output formats",[1124,7930,7931],{},"SPDX 2.3 tag-value/JSON",[1124,7933,7934],{},"SPDX, custom report",[1103,7936,7937,7940,7943],{},[1124,7938,7939],{},"CPE/PURL identifiers",[1124,7941,7942],{},"No",[1124,7944,7942],{},[1103,7946,7947,7950,7953],{},[1124,7948,7949],{},"Binary blob handling",[1124,7951,7952],{},"Listed but opaque",[1124,7954,7955],{},"Better Nordic-specific coverage",[1103,7957,7958,7961,7964],{},[1124,7959,7960],{},"Subsystem enumeration",[1124,7962,7963],{},"Rolled into kernel",[1124,7965,7966],{},"Similar limitation",[1103,7968,7969,7972,7975],{},[1124,7970,7971],{},"CRA vulnerability scanning",[1124,7973,7974],{},"Not useful without enrichment",[1124,7976,7974],{},[11,7978,7979,7980,7982],{},"Neither tool solves the CRA SBOM problem on its own. Both require the enrichment workflow described in this tutorial. The ",[377,7981,7885],{}," tool is better for license compliance documentation but has the same gaps for security-focused SBOM use.",[21,7984,7986,7987,7989],{"id":7985},"checklist-from-west-spdx-to-cra-compliant-sbom","Checklist: From ",[377,7988,2550],{}," to CRA-Compliant SBOM",[11,7991,7992],{},[31,7993,7994],{},"Generation",[86,7996,7998,8006,8012],{"className":7997},[89],[91,7999,8001,784,8003,8005],{"className":8000},[94],[96,8002],{"disabled":98,"type":99},[377,8004,2550],{}," runs on every release build",[91,8007,8009,8011],{"className":8008},[94],[96,8010],{"disabled":98,"type":99}," SPDX namespace uses your company's domain",[91,8013,8015,8017],{"className":8014},[94],[96,8016],{"disabled":98,"type":99}," MCUboot SBOM generated separately and merged",[11,8019,8020],{},[31,8021,8022],{},"Enrichment",[86,8024,8026,8032,8038,8044],{"className":8025},[89],[91,8027,8029,8031],{"className":8028},[94],[96,8030],{"disabled":98,"type":99}," Every package has a CPE identifier (or documented reason for omission)",[91,8033,8035,8037],{"className":8034},[94],[96,8036],{"disabled":98,"type":99}," Every package has a PURL identifier",[91,8039,8041,8043],{"className":8040},[94],[96,8042],{"disabled":98,"type":99}," Package versions match upstream release versions (not just commit hashes)",[91,8045,8047,8049],{"className":8046},[94],[96,8048],{"disabled":98,"type":99}," Supplier information populated for all packages",[11,8051,8052],{},[31,8053,8054],{},"Invisible components",[86,8056,8058,8066,8072,8080,8088],{"className":8057},[89],[91,8059,8061,8063,8064,879],{"className":8060},[94],[96,8062],{"disabled":98,"type":99}," Bluetooth stack listed as separate component (if ",[377,8065,6481],{},[91,8067,8069,8071],{"className":8068},[94],[96,8070],{"disabled":98,"type":99}," MQTT/CoAP/HTTP libraries listed (if enabled)",[91,8073,8075,8077,8078,879],{"className":8074},[94],[96,8076],{"disabled":98,"type":99}," cJSON listed separately (if ",[377,8079,7125],{},[91,8081,8083,8085,8086,879],{"className":8082},[94],[96,8084],{"disabled":98,"type":99}," USB stack listed (if ",[377,8087,7165],{},[91,8089,8091,8093],{"className":8090},[94],[96,8092],{"disabled":98,"type":99}," All Kconfig-enabled subsystems audited",[11,8095,8096],{},[31,8097,8098],{},"Binary blobs",[86,8100,8102,8108,8114,8122],{"className":8101},[89],[91,8103,8105,8107],{"className":8104},[94],[96,8106],{"disabled":98,"type":99}," Vendor HAL modules documented with available version info",[91,8109,8111,8113],{"className":8110},[94],[96,8112],{"disabled":98,"type":99}," Pre-compiled radio stacks (SoftDevice, WiFi firmware) listed",[91,8115,8117,784,8119,8121],{"className":8116},[94],[96,8118],{"disabled":98,"type":99},[377,8120,7001],{}," set for opaque binaries",[91,8123,8125,8127],{"className":8124},[94],[96,8126],{"disabled":98,"type":99}," Vendor SBOM requested from silicon supplier",[11,8129,8130],{},[31,8131,8132],{},"Vulnerability scanning",[86,8134,8136,8145,8151,8157],{"className":8135},[89],[91,8137,8139,8141,8142,8144],{"className":8138},[94],[96,8140],{"disabled":98,"type":99}," Scanner runs against enriched SBOM (not raw ",[377,8143,2550],{}," output)",[91,8146,8148,8150],{"className":8147},[94],[96,8149],{"disabled":98,"type":99}," False positives triaged via VEX assessment",[91,8152,8154,8156],{"className":8153},[94],[96,8155],{"disabled":98,"type":99}," MCUboot vulnerabilities tracked via project advisories (not just NVD)",[91,8158,8160,8162],{"className":8159},[94],[96,8161],{"disabled":98,"type":99}," Scan results archived per release",[11,8164,8165],{},[31,8166,8167],{},"Format and delivery",[86,8169,8171,8177,8183,8189],{"className":8170},[89],[91,8172,8174,8176],{"className":8173},[94],[96,8175],{"disabled":98,"type":99}," Four SPDX files merged into single document",[91,8178,8180,8182],{"className":8179},[94],[96,8181],{"disabled":98,"type":99}," CycloneDX version generated if required by supply chain",[91,8184,8186,8188],{"className":8185},[94],[96,8187],{"disabled":98,"type":99}," SBOM included in Annex VII technical documentation",[91,8190,8192,8194],{"className":8191},[94],[96,8193],{"disabled":98,"type":99}," SBOM versioned and archived alongside firmware releases",[11,8196,8197,8198,8201,8202,8205],{},"For a broader view of Zephyr CRA compliance beyond SBOM, see our ",[102,8199,8200],{"href":603},"complete Zephyr CRA guide",". For the ",[102,8203,8204],{"href":3112},"Annex I essential requirements checklist",", see the full mapping of every requirement to implementation actions.",[1478,8207],{},[11,8209,8210],{},[1483,8211,8212],{},"Based on Zephyr Project documentation (v3.7+), SPDX 2.3 specification, CycloneDX 1.7 specification, NTIA minimum SBOM elements (2021), and Regulation EU 2024/2847 Annex I Part II. This does not constitute legal advice.",[21,8214,1489],{"id":1488},[86,8216,8217,8222,8227,8234,8241,8248,8255,8262,8269],{},[91,8218,8219],{},[102,8220,1499],{"href":1496,"rel":8221},[1498],[91,8223,8224],{},[102,8225,3153],{"href":3151,"rel":8226},[1498],[91,8228,8229],{},[102,8230,8233],{"href":8231,"rel":8232},"https://zephyrproject.org/practical-sbom-management-with-zephyr-and-spdx-benjamin-cabe-the-linux-foundation/",[1498],"Zephyr Project — Practical SBOM Management with Zephyr and SPDX",[91,8235,8236],{},[102,8237,8240],{"href":8238,"rel":8239},"https://spdx.github.io/spdx-spec/v2.3/",[1498],"SPDX 2.3 Specification",[91,8242,8243],{},[102,8244,8247],{"href":8245,"rel":8246},"https://cyclonedx.org/specification/overview/",[1498],"OWASP CycloneDX Specification",[91,8249,8250],{},[102,8251,8254],{"href":8252,"rel":8253},"https://www.ntia.gov/sites/default/files/publications/sbom_minimum_elements_report_0.pdf",[1498],"NTIA — Minimum Elements for a Software Bill of Materials (2021)",[91,8256,8257],{},[102,8258,8261],{"href":8259,"rel":8260},"https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/scripts/west_commands/ncs-sbom.html",[1498],"Nordic Semiconductor — west ncs-sbom",[91,8263,8264],{},[102,8265,8268],{"href":8266,"rel":8267},"https://google.github.io/osv-scanner/",[1498],"OSV-Scanner — Vulnerability scanning",[91,8270,8271],{},[102,8272,8275],{"href":8273,"rel":8274},"https://github.com/anchore/grype",[1498],"Grype — Vulnerability scanner for container images and filesystems",[8277,8278,8279],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":1536,"searchDepth":1537,"depth":1537,"links":8281},[8282,8284,8285,8292,8296,8297,8298,8299,8300,8305,8306,8308,8310],{"id":6220,"depth":1537,"text":8283},"What west spdx Gives You (and What It Doesn't)",{"id":6276,"depth":1537,"text":6277},{"id":6454,"depth":1537,"text":6455,"children":8286},[8287,8288,8289,8290,8291],{"id":6458,"depth":1542,"text":6459},{"id":6474,"depth":1542,"text":6475},{"id":6491,"depth":1542,"text":6492},{"id":6517,"depth":1542,"text":6518},{"id":6527,"depth":1542,"text":6528},{"id":6543,"depth":1537,"text":6544,"children":8293},[8294,8295],{"id":6550,"depth":1542,"text":6551},{"id":6684,"depth":1542,"text":6685},{"id":6974,"depth":1537,"text":6975},{"id":7030,"depth":1537,"text":7031},{"id":7231,"depth":1537,"text":7232},{"id":7315,"depth":1537,"text":7316},{"id":7440,"depth":1537,"text":7441,"children":8301},[8302,8303,8304],{"id":7447,"depth":1542,"text":7448},{"id":6445,"depth":1542,"text":7474},{"id":7510,"depth":1542,"text":7511},{"id":7547,"depth":1537,"text":7548},{"id":7881,"depth":1537,"text":8307},"Nordic west ncs-sbom Comparison",{"id":7985,"depth":1537,"text":8309},"Checklist: From west spdx to CRA-Compliant SBOM",{"id":1488,"depth":1537,"text":1489},"2026-01-08","Zephyr's west spdx misses CPE/PURL identifiers and binary blobs needed for CRA vulnerability scanning. Full SBOM enrichment tutorial.","/images/blog/previews/zephyr-sbom.svg",[8315,2550,8316,8317,8318,8319],"Zephyr SBOM","Zephyr CRA SBOM","SBOM embedded firmware","Zephyr CycloneDX","Zephyr vulnerability scanning",{},"/blog/zephyr-sbom-cra-compliance","15 min",{"title":6192,"description":8312},"blog/zephyr-sbom-cra-compliance","kjA4jDzZ2TH3obxqvobY29MXLroJuArlYh_koJ4rqz0",{"id":8327,"title":8328,"body":8329,"date":9321,"description":9322,"extension":1577,"image":9323,"keywords":9324,"meta":9332,"navigation":98,"path":9333,"readTime":9334,"seo":9335,"stem":9336,"__hash__":9337},"blog/blog/cra-sbom-firmware.md","Generating a CRA-Compliant SBOM for Embedded Firmware",{"type":8,"value":8330,"toc":9306},[8331,8338,8341,8348,8354,8357,8361,8364,8369,8372,8377,8380,8383,8388,8391,8396,8399,8422,8425,8429,8432,8435,8439,8442,8445,8468,8474,8477,8481,8484,8487,8496,8500,8509,8512,8532,8549,8553,8559,8565,8569,8572,8696,8701,8712,8715,8721,8727,8832,8835,8841,8847,8854,8869,8875,8969,8973,8976,8982,9007,9010,9024,9029,9052,9055,9069,9072,9076,9079,9084,9111,9116,9143,9148,9178,9183,9210,9215,9236,9245,9247,9252,9254,9303],[11,8332,8333,8334,8337],{},"If you ask a firmware team about SBOMs, you'll get one of two responses: either they've been generating them via Yocto's ",[377,8335,8336],{},"create-spdx"," class for years and treat this as solved, or they have almost no idea where to start because half their firmware is binary blobs from chipset vendors.",[11,8339,8340],{},"The reality for most embedded product companies is somewhere in the middle—some components are tracked, others aren't, and the tracking that exists isn't machine-readable in any standard format.",[11,8342,8343,8344,8347],{},"The CRA is going to force resolution of this ambiguity. ",[31,8345,8346],{},"Annex I Part II, point 1"," requires manufacturers to:",[8349,8350,8351],"blockquote",{},[11,8352,8353],{},"Identify and document vulnerabilities and components contained in the product with digital elements, 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 of the products.",[11,8355,8356],{},"This post breaks down what the regulation actually requires, why firmware SBOM is harder than application SBOM, and how to implement it for Yocto-based and non-Yocto firmware builds.",[21,8358,8360],{"id":8359},"what-the-regulation-actually-requires","What the Regulation Actually Requires",[11,8362,8363],{},"The CRA text is more permissive than many summaries suggest. Key points:",[11,8365,8366],{},[31,8367,8368],{},"1. Machine-readable format, but no mandatory standard",[11,8370,8371],{},"The regulation says \"commonly used and machine-readable format.\" It does not mandate SPDX or CycloneDX specifically. Both are acceptable; either is compliant. The format decision is yours to make based on your tooling ecosystem.",[11,8373,8374],{},[31,8375,8376],{},"2. \"At the very least top-level dependencies\"",[11,8378,8379],{},"The SBOM must cover top-level dependencies as a minimum. However, ENISA guidance (2025) interprets \"top-level dependencies\" broadly for firmware: all libraries, packages, and components that are linked into or bundled with your firmware image count as top-level dependencies, regardless of whether they're direct or transitive.",[11,8381,8382],{},"The practical implication: you can't get away with listing only the packages in your CMakeLists.txt or Makefile and ignoring transitive dependencies. If a library you link pulls in three others and those are compiled into your binary, they need to be in the SBOM.",[11,8384,8385],{},[31,8386,8387],{},"3. The SBOM is part of your technical documentation",[11,8389,8390],{},"Article 31 and Annex VII require the SBOM to be kept in the technical documentation file. It doesn't need to be published publicly, but it must be available to market surveillance authorities upon request. Many manufacturers are choosing to publish SBOMs alongside their products anyway (for supply chain transparency), but this isn't a CRA mandate.",[11,8392,8393],{},[31,8394,8395],{},"4. NTIA minimum elements apply as a baseline",[11,8397,8398],{},"ENISA has cross-referenced the NTIA minimum SBOM elements (2021) as a baseline for what constitutes an adequate SBOM. These are:",[86,8400,8401,8404,8407,8410,8413,8416,8419],{},[91,8402,8403],{},"Supplier name",[91,8405,8406],{},"Component name",[91,8408,8409],{},"Version of the component",[91,8411,8412],{},"Other unique identifiers (CPE, PURL)",[91,8414,8415],{},"Dependency relationships",[91,8417,8418],{},"Author of SBOM data",[91,8420,8421],{},"Timestamp",[11,8423,8424],{},"Your SBOM needs to cover at least these fields per component.",[21,8426,8428],{"id":8427},"why-firmware-sbom-is-harder-than-application-sbom","Why Firmware SBOM Is Harder Than Application SBOM",[11,8430,8431],{},"For web application or backend service teams, generating an SBOM is relatively straightforward: parse your package manager lock file (package-lock.json, Pipfile.lock, Cargo.lock, go.sum), generate an SPDX or CycloneDX document, done.",[11,8433,8434],{},"Firmware is different for four structural reasons:",[45,8436,8438],{"id":8437},"_1-binary-blobs-and-closed-source-components","1. Binary Blobs and Closed-Source Components",[11,8440,8441],{},"The most common hard problem: your Wi-Fi chipset vendor provides a pre-compiled binary library. You link it into your firmware. You don't have source code. You have a version number and a filename.",[11,8443,8444],{},"What can you include in the SBOM?",[86,8446,8447,8450,8453,8456,8459,8462,8465],{},[91,8448,8449],{},"Component name: yes",[91,8451,8452],{},"Supplier: yes",[91,8454,8455],{},"Version: yes (if the vendor documents it, which isn't always the case)",[91,8457,8458],{},"Hash/checksum: yes (SHA-256 of the binary blob)",[91,8460,8461],{},"PURL: sometimes (if the vendor has a published CPE or package registry entry)",[91,8463,8464],{},"License: sometimes (if the vendor's distribution terms are documented)",[91,8466,8467],{},"Transitive dependencies of the blob: generally no",[11,8469,8470,8471,8473],{},"For binary blobs, you create an SBOM entry with what you know and mark the license and dependency information as ",[377,8472,2591],{}," in SPDX or equivalent in CycloneDX. This is incomplete but defensible if you've made reasonable efforts to gather information.",[11,8475,8476],{},"The better long-term answer: contractual requirements on your chipset and SDK vendors to provide SBOMs for their binary deliverables. This is becoming a procurement requirement in the embedded industry.",[45,8478,8480],{"id":8479},"_2-vendor-sdks-with-unreleased-patches","2. Vendor SDKs with Unreleased Patches",[11,8482,8483],{},"Many embedded product teams use a vendor SDK that's built on top of an open-source project (FreeRTOS, lwIP, mbedTLS, etc.) but with proprietary patches applied. The vendor ships a versioned SDK, but that version doesn't correspond to any public release of the underlying component.",[11,8485,8486],{},"This creates an SBOM problem: your SBOM should reference the vendor SDK version (since that's what's actually in your firmware), but you also want to capture the underlying component versions for vulnerability matching.",[11,8488,8489,8490,2409,8492,8495],{},"The SPDX approach: include both entries—the vendor SDK package and the upstream component it's derived from, with a ",[377,8491,7216],{},[377,8493,8494],{},"DYNAMIC_LINK"," relationship. Many scanners won't generate this automatically; you'll need to add it manually or via tooling customization.",[45,8497,8499],{"id":8498},"_3-rtos-forks-and-custom-modifications","3. RTOS Forks and Custom Modifications",[11,8501,8502,8503,8505,8506,8508],{},"If your team has forked FreeRTOS, Zephyr, or another open-source RTOS and applied custom patches, your firmware contains a component that doesn't match any public release. This is common for embedded teams that need to backport security fixes or add hardware-specific support. For RTOS-specific SBOM guidance, see our ",[102,8504,3231],{"href":603}," (which covers west manifest parsing) and ",[102,8507,2248],{"href":608}," (which covers the vendor SDK dependency challenge).",[11,8510,8511],{},"For SBOM purposes:",[86,8513,8514,8520,8526,8529],{},[91,8515,8516,8517,879],{},"List the upstream project as your component (e.g., ",[377,8518,8519],{},"FreeRTOS-Kernel",[91,8521,8522,8523,879],{},"Record your fork's base version (e.g., ",[377,8524,8525],{},"v11.0.1",[91,8527,8528],{},"Add the patch commit hash or your internal version identifier",[91,8530,8531],{},"Mark it as a modified version",[11,8533,8534,8535,8537,8538,8540,8541,8544,8545,8548],{},"In SPDX: use the ",[377,8536,7014],{}," field or the ",[377,8539,6691],{}," field to document the modification. In CycloneDX: use the ",[377,8542,8543],{},"pedigree"," element with ",[377,8546,8547],{},"patches"," to describe modifications.",[45,8550,8552],{"id":8551},"_4-bootloaders-and-secure-boot-chains","4. Bootloaders and Secure Boot Chains",[11,8554,8555,8556,1603],{},"The full firmware image often includes components that aren't part of the main application firmware build: bootloaders (U-Boot, MCUboot, proprietary), secure boot verification code, trust anchor certificates, and provisioning tools. These need to be in your SBOM too. For details on which bootloader components to document and how secure boot chains work, see our ",[102,8557,8558],{"href":209},"secure boot and firmware signing guide",[11,8560,8561,8562,8564],{},"For Yocto-based builds, the ",[377,8563,8336],{}," class captures most of this if configured correctly. For custom build systems, you may need to add these components manually.",[21,8566,8568],{"id":8567},"spdx-vs-cyclonedx-which-to-choose","SPDX vs. CycloneDX: Which to Choose",[11,8570,8571],{},"Both formats are CRA-compliant. Choose based on your tooling ecosystem:",[1097,8573,8574,8586],{},[1100,8575,8576],{},[1103,8577,8578,8580,8583],{},[1106,8579,4733],{},[1106,8581,8582],{},"SPDX (ISO/IEC 5962:2021)",[1106,8584,8585],{},"CycloneDX (OWASP, v1.7+)",[1119,8587,8588,8599,8610,8621,8632,8647,8672,8686],{},[1103,8589,8590,8593,8596],{},[1124,8591,8592],{},"Standardisation",[1124,8594,8595],{},"ISO/IEC international standard",[1124,8597,8598],{},"OWASP community standard",[1103,8600,8601,8604,8607],{},[1124,8602,8603],{},"Formats",[1124,8605,8606],{},"Tag-value, JSON, RDF, YAML, XML",[1124,8608,8609],{},"JSON, XML, Protobuf",[1103,8611,8612,8615,8618],{},[1124,8613,8614],{},"Tooling ecosystem",[1124,8616,8617],{},"Strong in Linux/Yocto world",[1124,8619,8620],{},"Strong in DevSecOps/cloud world",[1103,8622,8623,8626,8629],{},[1124,8624,8625],{},"License expression",[1124,8627,8628],{},"Rich SPDX license syntax",[1124,8630,8631],{},"SPDX license identifiers supported",[1103,8633,8634,8637,8640],{},[1124,8635,8636],{},"VEX support",[1124,8638,8639],{},"SPDX VEX (OpenVEX)",[1124,8641,8642,8643,8646],{},"Native VEX via ",[377,8644,8645],{},"vulnerabilities"," component",[1103,8648,8649,8651,8661],{},[1124,8650,8415],{},[1124,8652,8653,380,8656,380,8658,8660],{},[377,8654,8655],{},"DESCRIBES",[377,8657,7216],{},[377,8659,7219],{},", etc.",[1124,8662,8663,380,8666,380,8669],{},[377,8664,8665],{},"dependsOn",[377,8667,8668],{},"provides",[377,8670,8671],{},"runtimeDependency",[1103,8673,8674,8677,8683],{},[1124,8675,8676],{},"Yocto native support",[1124,8678,8679,8680,8682],{},"Yes (",[377,8681,8336],{}," class)",[1124,8684,8685],{},"Via external tools",[1103,8687,8688,8691,8694],{},[1124,8689,8690],{},"Vulnerability matching",[1124,8692,8693],{},"Via PURL, CPE",[1124,8695,8693],{},[11,8697,8698],{},[31,8699,8700],{},"Recommendation for embedded teams:",[86,8702,8703,8706,8709],{},[91,8704,8705],{},"If you're using Yocto: use SPDX (native support, lower effort)",[91,8707,8708],{},"If you need rich VEX integration for vulnerability triage: consider CycloneDX",[91,8710,8711],{},"If you need to consume SBOMs from your chipset vendors: match their format",[11,8713,8714],{},"You can generate both—SPDX as your authoritative SBOM for the technical documentation file, CycloneDX for integration with vulnerability scanning tools.",[21,8716,8718,8719],{"id":8717},"yocto-setting-up-create-spdx","Yocto: Setting Up ",[377,8720,8336],{},[11,8722,8723,8724,8726],{},"The Yocto Project's ",[377,8725,8336],{}," class (available since Kirkstone) generates SPDX 2.3 or SPDX 3.0 documents for your image. Here's a minimal configuration:",[2358,8728,8730],{"className":6286,"code":8729,"language":6288,"meta":1536,"style":1536},"# In your local.conf or distro.conf\n\n# Enable SPDX generation\nINHERIT += \"create-spdx\"\n\n# Output format (spdx-json, spdx-tag-value, or spdx-rdf)\nSPDX_PRETTY = \"1\"\n\n# Include security metadata (CVE checkpoints)\nSPDX_INCLUDE_SOURCES = \"1\"\n\n# Namespace for your SBOM (use your company domain)\nSPDX_NAMESPACE_PREFIX = \"https://sbom.yourcompany.com\"\n\n# Optional: generate per-package SBOMs in addition to image-level\nSPDX_INCLUDE_PACKAGED = \"1\"\n",[377,8731,8732,8737,8741,8746,8757,8761,8766,8777,8781,8786,8795,8799,8804,8814,8818,8823],{"__ignoreMap":1536},[6292,8733,8734],{"class":6294,"line":6295},[6292,8735,8736],{"class":6298},"# In your local.conf or distro.conf\n",[6292,8738,8739],{"class":6294,"line":1537},[6292,8740,6333],{"emptyLinePlaceholder":98},[6292,8742,8743],{"class":6294,"line":1542},[6292,8744,8745],{"class":6298},"# Enable SPDX generation\n",[6292,8747,8748,8751,8754],{"class":6294,"line":6336},[6292,8749,8750],{"class":6304},"INHERIT",[6292,8752,8753],{"class":6308}," +=",[6292,8755,8756],{"class":6308}," \"create-spdx\"\n",[6292,8758,8759],{"class":6294,"line":6342},[6292,8760,6333],{"emptyLinePlaceholder":98},[6292,8762,8763],{"class":6294,"line":6735},[6292,8764,8765],{"class":6298},"# Output format (spdx-json, spdx-tag-value, or spdx-rdf)\n",[6292,8767,8768,8771,8774],{"class":6294,"line":6741},[6292,8769,8770],{"class":6304},"SPDX_PRETTY",[6292,8772,8773],{"class":6308}," =",[6292,8775,8776],{"class":6308}," \"1\"\n",[6292,8778,8779],{"class":6294,"line":6747},[6292,8780,6333],{"emptyLinePlaceholder":98},[6292,8782,8783],{"class":6294,"line":6753},[6292,8784,8785],{"class":6298},"# Include security metadata (CVE checkpoints)\n",[6292,8787,8788,8791,8793],{"class":6294,"line":6759},[6292,8789,8790],{"class":6304},"SPDX_INCLUDE_SOURCES",[6292,8792,8773],{"class":6308},[6292,8794,8776],{"class":6308},[6292,8796,8797],{"class":6294,"line":6765},[6292,8798,6333],{"emptyLinePlaceholder":98},[6292,8800,8801],{"class":6294,"line":6771},[6292,8802,8803],{"class":6298},"# Namespace for your SBOM (use your company domain)\n",[6292,8805,8806,8809,8811],{"class":6294,"line":6777},[6292,8807,8808],{"class":6304},"SPDX_NAMESPACE_PREFIX",[6292,8810,8773],{"class":6308},[6292,8812,8813],{"class":6308}," \"https://sbom.yourcompany.com\"\n",[6292,8815,8816],{"class":6294,"line":6782},[6292,8817,6333],{"emptyLinePlaceholder":98},[6292,8819,8820],{"class":6294,"line":6788},[6292,8821,8822],{"class":6298},"# Optional: generate per-package SBOMs in addition to image-level\n",[6292,8824,8825,8828,8830],{"class":6294,"line":6794},[6292,8826,8827],{"class":6304},"SPDX_INCLUDE_PACKAGED",[6292,8829,8773],{"class":6308},[6292,8831,8776],{"class":6308},[11,8833,8834],{},"After a full image build, Yocto outputs SPDX documents to:",[2358,8836,8839],{"className":8837,"code":8838,"language":2363},[2361],"tmp/deploy/spdx/\u003Cmachine>/\u003Cimage>/\n",[377,8840,8838],{"__ignoreMap":1536},[11,8842,8843,8844,8846],{},"The top-level SPDX document describes the full image and includes ",[377,8845,8655],{}," relationships to all packages. Each package document includes license information, source URIs, and checksums.",[11,8848,8849],{},[31,8850,6221,8851,8853],{},[377,8852,8336],{}," doesn't handle automatically:",[86,8855,8856,8859,8866],{},[91,8857,8858],{},"Binary blob components (you'll need to add these manually or via a custom bbclass)",[91,8860,8861,8862,8865],{},"Components fetched via custom ",[377,8863,8864],{},"do_fetch"," scripts outside of Yocto's standard fetchers",[91,8867,8868],{},"Bootloader components if they're built outside the Yocto image (e.g., a separate U-Boot build)",[11,8870,8871,8872,8874],{},"For binary blobs, write a custom bbclass that adds them as SPDX packages with ",[377,8873,2591],{}," for license fields:",[2358,8876,8878],{"className":6704,"code":8877,"language":6706,"meta":1536,"style":1536},"# In your custom bbclass (e.g., wifi-blob-spdx.bbclass)\npython do_spdx_wifi_blob() {\n    import json\n    spdx_pkg = {\n        \"SPDXID\": \"SPDXRef-wifi-firmware\",\n        \"name\": d.getVar(\"WIFI_BLOB_NAME\"),\n        \"version\": d.getVar(\"WIFI_BLOB_VERSION\"),\n        \"supplier\": \"Organization: \" + d.getVar(\"WIFI_BLOB_VENDOR\"),\n        \"downloadLocation\": \"NOASSERTION\",\n        \"filesAnalyzed\": False,\n        \"checksums\": [{\"algorithm\": \"SHA256\", \"checksumValue\": d.getVar(\"WIFI_BLOB_SHA256\")}],\n        \"licenseConcluded\": \"NOASSERTION\",\n        \"licenseDeclared\": \"NOASSERTION\",\n        \"copyrightText\": \"NOASSERTION\",\n    }\n    # Append to image SPDX document\n    # (implementation depends on your Yocto version and SPDX class structure)\n}\n",[377,8879,8880,8885,8890,8895,8900,8905,8910,8915,8920,8925,8930,8935,8940,8945,8950,8955,8960,8965],{"__ignoreMap":1536},[6292,8881,8882],{"class":6294,"line":6295},[6292,8883,8884],{},"# In your custom bbclass (e.g., wifi-blob-spdx.bbclass)\n",[6292,8886,8887],{"class":6294,"line":1537},[6292,8888,8889],{},"python do_spdx_wifi_blob() {\n",[6292,8891,8892],{"class":6294,"line":1542},[6292,8893,8894],{},"    import json\n",[6292,8896,8897],{"class":6294,"line":6336},[6292,8898,8899],{},"    spdx_pkg = {\n",[6292,8901,8902],{"class":6294,"line":6342},[6292,8903,8904],{},"        \"SPDXID\": \"SPDXRef-wifi-firmware\",\n",[6292,8906,8907],{"class":6294,"line":6735},[6292,8908,8909],{},"        \"name\": d.getVar(\"WIFI_BLOB_NAME\"),\n",[6292,8911,8912],{"class":6294,"line":6741},[6292,8913,8914],{},"        \"version\": d.getVar(\"WIFI_BLOB_VERSION\"),\n",[6292,8916,8917],{"class":6294,"line":6747},[6292,8918,8919],{},"        \"supplier\": \"Organization: \" + d.getVar(\"WIFI_BLOB_VENDOR\"),\n",[6292,8921,8922],{"class":6294,"line":6753},[6292,8923,8924],{},"        \"downloadLocation\": \"NOASSERTION\",\n",[6292,8926,8927],{"class":6294,"line":6759},[6292,8928,8929],{},"        \"filesAnalyzed\": False,\n",[6292,8931,8932],{"class":6294,"line":6765},[6292,8933,8934],{},"        \"checksums\": [{\"algorithm\": \"SHA256\", \"checksumValue\": d.getVar(\"WIFI_BLOB_SHA256\")}],\n",[6292,8936,8937],{"class":6294,"line":6771},[6292,8938,8939],{},"        \"licenseConcluded\": \"NOASSERTION\",\n",[6292,8941,8942],{"class":6294,"line":6777},[6292,8943,8944],{},"        \"licenseDeclared\": \"NOASSERTION\",\n",[6292,8946,8947],{"class":6294,"line":6782},[6292,8948,8949],{},"        \"copyrightText\": \"NOASSERTION\",\n",[6292,8951,8952],{"class":6294,"line":6788},[6292,8953,8954],{},"    }\n",[6292,8956,8957],{"class":6294,"line":6794},[6292,8958,8959],{},"    # Append to image SPDX document\n",[6292,8961,8962],{"class":6294,"line":6800},[6292,8963,8964],{},"    # (implementation depends on your Yocto version and SPDX class structure)\n",[6292,8966,8967],{"class":6294,"line":6805},[6292,8968,6831],{},[21,8970,8972],{"id":8971},"vex-reducing-triage-noise","VEX: Reducing Triage Noise",[11,8974,8975],{},"An SBOM listing all your firmware components will generate a large number of CVE matches — many of which aren't actually exploitable in your firmware configuration. Research on SBOM-based vulnerability scanning suggests that the vast majority of CVE matches against firmware SBOMs are false positives — studies have shown baseline false-positive rates as high as 95%+ for downstream vulnerability scanners. The most common false-positive categories are: CVEs affecting a feature you don't use, a code path you've compiled out, or a library version your vendor has backported a fix into.",[11,8977,8978,8981],{},[31,8979,8980],{},"VEX (Vulnerability Exploitability eXchange)"," is a specification for expressing whether a known CVE is exploitable in a specific product configuration. A VEX document says, for each CVE matched against your SBOM:",[86,8983,8984,8990,8995,9001],{},[91,8985,8986,8989],{},[31,8987,8988],{},"Not Affected:"," The CVE affects this component, but not in the way your firmware uses it",[91,8991,8992,8994],{},[31,8993,7524],{}," The CVE is exploitable in your firmware",[91,8996,8997,9000],{},[31,8998,8999],{},"Fixed:"," The CVE was exploitable but has been addressed in the current version",[91,9002,9003,9006],{},[31,9004,9005],{},"Under Investigation:"," Not yet determined",[11,9008,9009],{},"For CRA compliance, VEX serves two functions:",[1013,9011,9012,9018],{},[91,9013,9014,9017],{},[31,9015,9016],{},"Internal triage:"," Filter your CVE matches to the ones that actually require action (Article 14 obligations only apply to actually-exploitable vulnerabilities)",[91,9019,9020,9023],{},[31,9021,9022],{},"Customer communication:"," Share VEX documents with your customers so they can make accurate risk assessments without relying on raw CVE matches against your SBOM",[11,9025,9026],{},[31,9027,9028],{},"VEX formats:",[86,9030,9031,9037,9043],{},[91,9032,9033,9036],{},[31,9034,9035],{},"OpenVEX:"," Simple JSON-LD format, good for standalone VEX documents",[91,9038,9039,9042],{},[31,9040,9041],{},"SPDX VEX:"," Part of the SPDX 3.0 specification",[91,9044,9045,9048,9049,9051],{},[31,9046,9047],{},"CycloneDX VEX:"," Embedded in CycloneDX documents via the ",[377,9050,8645],{}," element",[11,9053,9054],{},"For embedded product companies, the minimum viable VEX process:",[1013,9056,9057,9060,9063,9066],{},[91,9058,9059],{},"Run vulnerability scanning against your SBOM (using tools like Grype, OSV-Scanner, or ENISA's planned tooling)",[91,9061,9062],{},"For each CVE match with CVSS ≥ 7.0: triage whether it's actually exploitable in your firmware",[91,9064,9065],{},"Document the triage decision in a VEX document with justification",[91,9067,9068],{},"Update the VEX document with each new firmware release",[11,9070,9071],{},"The VEX process naturally feeds into your Article 14 obligation: if your triage shows a CVE is actively exploited and affects your firmware, the 24-hour notification clock starts.",[21,9073,9075],{"id":9074},"pre-deadline-checklist","Pre-Deadline Checklist",[11,9077,9078],{},"Use this checklist to assess your current SBOM posture:",[11,9080,9081],{},[31,9082,9083],{},"Foundation",[86,9085,9087,9093,9099,9105],{"className":9086},[89],[91,9088,9090,9092],{"className":9089},[94],[96,9091],{"disabled":98,"type":99}," Complete inventory of all components in your firmware image (open source, commercial, binary blobs)",[91,9094,9096,9098],{"className":9095},[94],[96,9097],{"disabled":98,"type":99}," Version numbers recorded for all components including binary blobs (where available)",[91,9100,9102,9104],{"className":9101},[94],[96,9103],{"disabled":98,"type":99}," Hash/checksum recorded for all binary blobs",[91,9106,9108,9110],{"className":9107},[94],[96,9109],{"disabled":98,"type":99}," Supplier information recorded for all components",[11,9112,9113],{},[31,9114,9115],{},"Generation tooling",[86,9117,9119,9125,9131,9137],{"className":9118},[89],[91,9120,9122,9124],{"className":9121},[94],[96,9123],{"disabled":98,"type":99}," Automated SBOM generation integrated into your build pipeline (not a one-time manual exercise)",[91,9126,9128,9130],{"className":9127},[94],[96,9129],{"disabled":98,"type":99}," SBOM updated with every firmware release (not just when you remember to)",[91,9132,9134,9136],{"className":9133},[94],[96,9135],{"disabled":98,"type":99}," SBOM format is SPDX or CycloneDX (not a custom spreadsheet or proprietary format)",[91,9138,9140,9142],{"className":9139},[94],[96,9141],{"disabled":98,"type":99}," NTIA minimum elements present for all components",[11,9144,9145],{},[31,9146,9147],{},"Hard cases addressed",[86,9149,9151,9160,9166,9172],{"className":9150},[89],[91,9152,9154,9156,9157,9159],{"className":9153},[94],[96,9155],{"disabled":98,"type":99}," Binary blobs documented with ",[377,9158,2591],{}," for unknown fields (not omitted)",[91,9161,9163,9165],{"className":9162},[94],[96,9164],{"disabled":98,"type":99}," Vendor SDKs with upstream components documented at both levels",[91,9167,9169,9171],{"className":9168},[94],[96,9170],{"disabled":98,"type":99}," RTOS forks documented with base version and modification indicator",[91,9173,9175,9177],{"className":9174},[94],[96,9176],{"disabled":98,"type":99}," Bootloader and secure boot components included",[11,9179,9180],{},[31,9181,9182],{},"VEX integration",[86,9184,9186,9192,9198,9204],{"className":9185},[89],[91,9187,9189,9191],{"className":9188},[94],[96,9190],{"disabled":98,"type":99}," CVE monitoring against SBOM running continuously",[91,9193,9195,9197],{"className":9194},[94],[96,9196],{"disabled":98,"type":99}," VEX triage process defined and documented",[91,9199,9201,9203],{"className":9200},[94],[96,9202],{"disabled":98,"type":99}," VEX documents generated and versioned alongside firmware releases",[91,9205,9207,9209],{"className":9206},[94],[96,9208],{"disabled":98,"type":99}," VEX documents available to customers on request",[11,9211,9212],{},[31,9213,9214],{},"Compliance documentation",[86,9216,9218,9224,9230],{"className":9217},[89],[91,9219,9221,9223],{"className":9220},[94],[96,9222],{"disabled":98,"type":99}," SBOM included in technical documentation file (Annex VII)",[91,9225,9227,9229],{"className":9226},[94],[96,9228],{"disabled":98,"type":99}," SBOM generation process documented as part of your security processes",[91,9231,9233,9235],{"className":9232},[94],[96,9234],{"disabled":98,"type":99}," Retention process in place (10 years from product placement on market)",[11,9237,9238,9239,9241,9242,9244],{},"If you're working through Yocto's ",[377,9240,8336],{}," class and are dealing with binary blob gaps, the ",[102,9243,1475],{"href":1474}," will help identify which Annex I requirements remain open and prioritise your remediation work.",[1478,9246],{},[11,9248,9249],{},[1483,9250,9251],{},"Based on Regulation EU 2024/2847 Annex I Part II, NTIA Minimum Elements for a Software Bill of Materials (2021), Yocto Project documentation, SPDX ISO/IEC 5962:2021, and OWASP CycloneDX specification v1.7. ENISA SBOM guidance for the CRA (2025). This does not constitute legal advice.",[21,9253,1489],{"id":1488},[86,9255,9256,9261,9266,9273,9278,9283,9290,9296],{},[91,9257,9258],{},[102,9259,1499],{"href":1496,"rel":9260},[1498],[91,9262,9263],{},[102,9264,8254],{"href":8252,"rel":9265},[1498],[91,9267,9268],{},[102,9269,9272],{"href":9270,"rel":9271},"https://spdx.dev/specifications/",[1498],"SPDX Specification — ISO/IEC 5962:2021",[91,9274,9275],{},[102,9276,8247],{"href":8245,"rel":9277},[1498],[91,9279,9280],{},[102,9281,1520],{"href":1518,"rel":9282},[1498],[91,9284,9285],{},[102,9286,9289],{"href":9287,"rel":9288},"https://docs.yoctoproject.org/dev/ref-manual/classes.html#create-spdx",[1498],"Yocto Project — create-spdx class documentation",[91,9291,9292],{},[102,9293,9295],{"href":1504,"rel":9294},[1498],"CRA full text (HTML) — see Annex I Part II",[91,9297,9298],{},[102,9299,9302],{"href":9300,"rel":9301},"https://arxiv.org/pdf/2511.20313",[1498],"A Reality Check on SBOM-based Vulnerability Management (arXiv, 2025)",[8277,9304,9305],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":1536,"searchDepth":1537,"depth":1537,"links":9307},[9308,9309,9315,9316,9318,9319,9320],{"id":8359,"depth":1537,"text":8360},{"id":8427,"depth":1537,"text":8428,"children":9310},[9311,9312,9313,9314],{"id":8437,"depth":1542,"text":8438},{"id":8479,"depth":1542,"text":8480},{"id":8498,"depth":1542,"text":8499},{"id":8551,"depth":1542,"text":8552},{"id":8567,"depth":1537,"text":8568},{"id":8717,"depth":1537,"text":9317},"Yocto: Setting Up create-spdx",{"id":8971,"depth":1537,"text":8972},{"id":9074,"depth":1537,"text":9075},{"id":1488,"depth":1537,"text":1489},"2025-12-18","Generate a CRA-compliant SBOM for embedded firmware: handle binary blobs, vendor SDKs, and RTOS forks that break standard SBOM tools.","/images/blog/previews/sbom-firmware.svg",[9325,9326,9327,9328,9329,9330,9331],"CRA SBOM","firmware SBOM","SPDX","CycloneDX","Yocto SBOM","CRA Annex I","software bill of materials",{},"/blog/cra-sbom-firmware","11 min",{"title":8328,"description":9322},"blog/cra-sbom-firmware","kEsSR7UST9DSLykkIj-SYSeVz-J0ck80Ul_TPb9nBtE",{"id":9339,"title":9340,"body":9341,"date":10449,"description":10450,"extension":1577,"image":10451,"keywords":10452,"meta":10459,"navigation":98,"path":10460,"readTime":6186,"seo":10461,"stem":10462,"__hash__":10463},"blog/blog/cra-threat-modeling-embedded.md","CRA Threat Modeling for Embedded Products",{"type":8,"value":9342,"toc":10425},[9343,9350,9353,9356,9360,9363,9374,9377,9382,9393,9398,9412,9416,9419,9425,9431,9437,9443,9446,9484,9488,9491,9495,9590,9594,9599,9602,9616,9621,9624,9658,9663,9666,9671,9674,9685,9688,9693,9696,9707,9711,9714,9718,9724,9730,9734,9951,9955,10070,10073,10077,10081,10084,10088,10091,10095,10098,10102,10105,10109,10112,10117,10134,10139,10150,10155,10163,10168,10176,10181,10189,10193,10196,10201,10239,10249,10253,10259,10265,10271,10277,10283,10287,10371,10376,10378,10383,10385],[11,9344,9345,9346,9349],{},"Annex VII of the Cyber Resilience Act requires manufacturers to include a ",[31,9347,9348],{},"cybersecurity risk assessment"," in their technical documentation. In practice, this means you need a threat model — a structured analysis of how your product could be attacked and what you've done about it.",[11,9351,9352],{},"For firmware and embedded product teams, this is unfamiliar territory. Threat modeling has been a standard practice in web application and cloud security for years (OWASP, Microsoft SDL), but embedded teams have historically relied on security-by-obscurity, physical inaccessibility, or simply not thinking about it.",[11,9354,9355],{},"The CRA changes that. You need a documented threat model, it needs to cover the embedded-specific attack surface (physical access, debug interfaces, side channels, supply chain), and it needs to map to your Annex I mitigations. This post shows you how.",[21,9357,9359],{"id":9358},"what-annex-vii-requires","What Annex VII Requires",[11,9361,9362],{},"Annex VII, Section 2 requires the technical documentation to include:",[86,9364,9365,9368,9371],{},[91,9366,9367],{},"An assessment of the cybersecurity risks against which the product is designed, developed, and manufactured",[91,9369,9370],{},"How the essential requirements in Annex I are addressed based on that assessment",[91,9372,9373],{},"The security design and architecture of the product",[11,9375,9376],{},"In regulatory terms: the threat model is the justification for your security design decisions. It answers \"why did you implement these specific security controls?\" with \"because our risk assessment identified these specific threats.\"",[11,9378,9379],{},[31,9380,9381],{},"What it doesn't require:",[86,9383,9384,9387,9390],{},[91,9385,9386],{},"A specific threat modeling methodology (STRIDE, PASTA, LINDDUN, attack trees — any recognised approach is acceptable)",[91,9388,9389],{},"A specific format or template",[91,9391,9392],{},"Third-party validation (for default-category products)",[11,9394,9395],{},[31,9396,9397],{},"What market surveillance authorities will look for:",[86,9399,9400,9403,9406,9409],{},[91,9401,9402],{},"Evidence that the threat model was created before or during development (not retroactively slapped together for compliance)",[91,9404,9405],{},"Coverage of the product's actual attack surface (not a generic template)",[91,9407,9408],{},"Traceability from identified threats to implemented mitigations",[91,9410,9411],{},"Alignment between the threat model and the Annex I requirements you claim to satisfy",[21,9413,9415],{"id":9414},"why-it-threat-models-dont-fit-embedded","Why IT Threat Models Don't Fit Embedded",[11,9417,9418],{},"Standard IT threat models (STRIDE applied to web applications, OWASP Top 10 for APIs) assume a context that doesn't match embedded products:",[11,9420,9421,9424],{},[31,9422,9423],{},"IT assumes network-only attackers."," Embedded products have physical attack surfaces: debug ports, flash memory that can be desoldered and read, RF interfaces that can be intercepted at close range, side-channel emissions.",[11,9426,9427,9430],{},[31,9428,9429],{},"IT assumes patching is fast."," Web applications deploy patches in hours. Firmware updates for devices in the field take days to weeks, and many devices may never update. The threat model needs to account for the window of exposure.",[11,9432,9433,9436],{},[31,9434,9435],{},"IT assumes abundant resources."," Crypto libraries, logging infrastructure, intrusion detection — all of these consume CPU, RAM, and flash that may be severely constrained on an MCU.",[11,9438,9439,9442],{},[31,9440,9441],{},"IT ignores supply chain hardware attacks."," For embedded products, the supply chain includes PCB fabrication, component sourcing, firmware programming during manufacturing — each is an attack surface.",[11,9444,9445],{},"An embedded threat model needs to cover:",[1013,9447,9448,9454,9460,9466,9472,9478],{},[91,9449,9450,9453],{},[31,9451,9452],{},"Network attacks"," (same as IT, but for constrained devices)",[91,9455,9456,9459],{},[31,9457,9458],{},"Physical attacks"," (debug ports, flash readout, hardware tampering)",[91,9461,9462,9465],{},[31,9463,9464],{},"Side-channel attacks"," (power analysis, EM analysis, timing attacks)",[91,9467,9468,9471],{},[31,9469,9470],{},"Supply chain attacks"," (counterfeit components, firmware tampering during manufacturing)",[91,9473,9474,9477],{},[31,9475,9476],{},"RF/wireless attacks"," (BLE spoofing, Wi-Fi deauth, Zigbee interception)",[91,9479,9480,9483],{},[31,9481,9482],{},"Firmware-specific attacks"," (rollback, unsigned updates, bootloader exploits)",[21,9485,9487],{"id":9486},"stride-adapted-for-embedded-systems","STRIDE Adapted for Embedded Systems",[11,9489,9490],{},"STRIDE (Spoofing, Tampering, Repudiation, Information disclosure, Denial of service, Elevation of privilege) is a good starting framework because it's well-documented and widely recognised by conformity assessment bodies. But it needs adaptation for embedded contexts.",[45,9492,9494],{"id":9493},"embedded-stride-categories","Embedded STRIDE Categories",[1097,9496,9497,9510],{},[1100,9498,9499],{},[1103,9500,9501,9504,9507],{},[1106,9502,9503],{},"STRIDE Category",[1106,9505,9506],{},"IT Example",[1106,9508,9509],{},"Embedded Example",[1119,9511,9512,9525,9538,9551,9564,9577],{},[1103,9513,9514,9519,9522],{},[1124,9515,9516],{},[31,9517,9518],{},"Spoofing",[1124,9520,9521],{},"Forged authentication token",[1124,9523,9524],{},"Cloned device identity, spoofed BLE peripheral, rogue OTA server",[1103,9526,9527,9532,9535],{},[1124,9528,9529],{},[31,9530,9531],{},"Tampering",[1124,9533,9534],{},"Modified HTTP request",[1124,9536,9537],{},"Firmware replacement via JTAG, flash chip swap, OTA image manipulation",[1103,9539,9540,9545,9548],{},[1124,9541,9542],{},[31,9543,9544],{},"Repudiation",[1124,9546,9547],{},"User denies sending a message",[1124,9549,9550],{},"Device denies it was in a specific state; no audit logs on constrained device",[1103,9552,9553,9558,9561],{},[1124,9554,9555],{},[31,9556,9557],{},"Information Disclosure",[1124,9559,9560],{},"SQL injection leaks database",[1124,9562,9563],{},"JTAG readout of firmware and keys, side-channel key extraction, unencrypted BLE data",[1103,9565,9566,9571,9574],{},[1124,9567,9568],{},[31,9569,9570],{},"Denial of Service",[1124,9572,9573],{},"HTTP flood",[1124,9575,9576],{},"Network stack crash via malformed packets, radio jamming, flash wear-out",[1103,9578,9579,9584,9587],{},[1124,9580,9581],{},[31,9582,9583],{},"Elevation of Privilege",[1124,9585,9586],{},"SQL injection to admin",[1124,9588,9589],{},"Buffer overflow to code execution, debug port to full device access, MPU bypass",[45,9591,9593],{"id":9592},"step-by-step-embedded-stride-process","Step-by-Step Embedded STRIDE Process",[11,9595,9596],{},[31,9597,9598],{},"Step 1: Define the system boundary",[11,9600,9601],{},"Draw a context diagram showing:",[86,9603,9604,9607,9610,9613],{},[91,9605,9606],{},"Your device and its internal components (MCU, flash, sensors, radio)",[91,9608,9609],{},"External entities that interact with it (cloud services, mobile apps, other devices, users, maintenance technicians)",[91,9611,9612],{},"Data flows between them (MQTT, BLE, UART, JTAG, OTA updates, sensor data)",[91,9614,9615],{},"Trust boundaries (what's inside your device vs. what's external and untrusted)",[11,9617,9618],{},[31,9619,9620],{},"Step 2: Decompose into elements",[11,9622,9623],{},"Break the system into individual components:",[86,9625,9626,9629,9632,9635,9638,9641,9644,9647,9650,9653,9655],{},[91,9627,9628],{},"Bootloader",[91,9630,9631],{},"Application firmware",[91,9633,9634],{},"Network stack",[91,9636,9637],{},"Cryptographic module",[91,9639,9640],{},"Key storage",[91,9642,9643],{},"Configuration storage",[91,9645,9646],{},"Debug interfaces",[91,9648,9649],{},"Physical interfaces (USB, UART, GPIO)",[91,9651,9652],{},"Wireless interfaces (Wi-Fi, BLE, Zigbee, LoRa)",[91,9654,787],{},[91,9656,9657],{},"Sensor inputs",[11,9659,9660],{},[31,9661,9662],{},"Step 3: Apply STRIDE to each element and data flow",[11,9664,9665],{},"For each component and each data flow, ask the six STRIDE questions. Not every category applies to every element, but you need to consider each one.",[11,9667,9668],{},[31,9669,9670],{},"Step 4: Rate and prioritise",[11,9672,9673],{},"For each identified threat:",[86,9675,9676,9679,9682],{},[91,9677,9678],{},"Likelihood: How likely is this attack given your product's deployment context?",[91,9680,9681],{},"Impact: What happens if this attack succeeds?",[91,9683,9684],{},"Risk: Likelihood x Impact",[11,9686,9687],{},"Use a simple scale (High/Medium/Low) or CVSS-style scoring. The CRA doesn't mandate a specific risk rating system.",[11,9689,9690],{},[31,9691,9692],{},"Step 5: Map to mitigations and Annex I requirements",[11,9694,9695],{},"For each threat rated Medium or above, document:",[86,9697,9698,9701,9704],{},[91,9699,9700],{},"The mitigation you've implemented",[91,9702,9703],{},"Which Annex I requirement the mitigation satisfies",[91,9705,9706],{},"Test evidence that the mitigation works",[21,9708,9710],{"id":9709},"worked-example-stm32-sensor-node","Worked Example: STM32 Sensor Node",[11,9712,9713],{},"Consider a temperature/humidity sensor node based on an STM32L4 with BLE connectivity, deployed in a commercial building.",[45,9715,9717],{"id":9716},"system-context","System Context",[11,9719,9720],{},[4506,9721],{"alt":9722,"src":9723},"STM32 Sensor Node — System Context and Threat Model","/images/blog/threat-model-stm32.svg",[2358,9725,9728],{"className":9726,"code":9727,"language":2363},[2361],"┌──────────────────────────────────┐\n│         Cloud Backend            │\n│  (MQTT broker, device registry)  │\n└──────────────┬───────────────────┘\n               │ TLS/MQTT\n┌──────────────┴───────────────────┐\n│          BLE Gateway             │\n│    (Raspberry Pi, nRF dongle)    │\n└──────────────┬───────────────────┘\n               │ BLE (GATT)\n┌──────────────┴───────────────────┐\n│      STM32L4 Sensor Node         │\n│  ┌─────────┐  ┌───────────────┐  │\n│  │ Sensors │  │ BLE Radio     │  │\n│  └─────────┘  └───────────────┘  │\n│  ┌─────────┐  ┌───────────────┐  │\n│  │ Flash   │  │ JTAG/SWD Port │  │\n│  └─────────┘  └───────────────┘  │\n└──────────────────────────────────┘\n",[377,9729,9727],{"__ignoreMap":1536},[45,9731,9733],{"id":9732},"threat-analysis-selected-threats","Threat Analysis (Selected Threats)",[1097,9735,9736,9760],{},[1100,9737,9738],{},[1103,9739,9740,9742,9745,9748,9751,9754,9757],{},[1106,9741,1220],{},[1106,9743,9744],{},"Element",[1106,9746,9747],{},"STRIDE",[1106,9749,9750],{},"Threat",[1106,9752,9753],{},"Likelihood",[1106,9755,9756],{},"Impact",[1106,9758,9759],{},"Risk",[1119,9761,9762,9783,9802,9821,9839,9858,9877,9895,9913,9932],{},[1103,9763,9764,9767,9770,9772,9775,9778,9781],{},[1124,9765,9766],{},"T1",[1124,9768,9769],{},"BLE interface",[1124,9771,9518],{},[1124,9773,9774],{},"Attacker impersonates gateway to extract sensor data",[1124,9776,9777],{},"Medium",[1124,9779,9780],{},"Low",[1124,9782,9780],{},[1103,9784,9785,9788,9790,9792,9795,9798,9800],{},[1124,9786,9787],{},"T2",[1124,9789,9769],{},[1124,9791,9557],{},[1124,9793,9794],{},"Unencrypted BLE advertising leaks sensor readings",[1124,9796,9797],{},"High",[1124,9799,9780],{},[1124,9801,9777],{},[1103,9803,9804,9807,9810,9812,9815,9817,9819],{},[1124,9805,9806],{},"T3",[1124,9808,9809],{},"JTAG/SWD port",[1124,9811,9557],{},[1124,9813,9814],{},"Attacker with physical access reads firmware and keys",[1124,9816,9777],{},[1124,9818,9797],{},[1124,9820,9797],{},[1103,9822,9823,9826,9828,9830,9833,9835,9837],{},[1124,9824,9825],{},"T4",[1124,9827,9809],{},[1124,9829,9531],{},[1124,9831,9832],{},"Attacker installs malicious firmware via debug port",[1124,9834,9777],{},[1124,9836,9797],{},[1124,9838,9797],{},[1103,9840,9841,9844,9847,9849,9852,9854,9856],{},[1124,9842,9843],{},"T5",[1124,9845,9846],{},"Flash storage",[1124,9848,9557],{},[1124,9850,9851],{},"Attacker desolders flash and reads keys",[1124,9853,9780],{},[1124,9855,9797],{},[1124,9857,9777],{},[1103,9859,9860,9863,9866,9868,9871,9873,9875],{},[1124,9861,9862],{},"T6",[1124,9864,9865],{},"OTA update",[1124,9867,9531],{},[1124,9869,9870],{},"Man-in-the-middle replaces OTA image",[1124,9872,9777],{},[1124,9874,9797],{},[1124,9876,9797],{},[1103,9878,9879,9882,9884,9886,9889,9891,9893],{},[1124,9880,9881],{},"T7",[1124,9883,9865],{},[1124,9885,9531],{},[1124,9887,9888],{},"Attacker rolls back to vulnerable firmware version",[1124,9890,9777],{},[1124,9892,9797],{},[1124,9894,9797],{},[1103,9896,9897,9900,9902,9904,9907,9909,9911],{},[1124,9898,9899],{},"T8",[1124,9901,9628],{},[1124,9903,9583],{},[1124,9905,9906],{},"Attacker exploits bootloader vulnerability to execute arbitrary code",[1124,9908,9780],{},[1124,9910,9797],{},[1124,9912,9777],{},[1103,9914,9915,9918,9921,9923,9926,9928,9930],{},[1124,9916,9917],{},"T9",[1124,9919,9920],{},"Application",[1124,9922,9570],{},[1124,9924,9925],{},"Malformed BLE packets crash the network stack",[1124,9927,9777],{},[1124,9929,9777],{},[1124,9931,9777],{},[1103,9933,9934,9937,9940,9942,9945,9947,9949],{},[1124,9935,9936],{},"T10",[1124,9938,9939],{},"Supply chain",[1124,9941,9531],{},[1124,9943,9944],{},"Counterfeit MCU with modified ROM bootloader",[1124,9946,9780],{},[1124,9948,9797],{},[1124,9950,9777],{},[45,9952,9954],{"id":9953},"mitigation-mapping","Mitigation Mapping",[1097,9956,9957,9969],{},[1100,9958,9959],{},[1103,9960,9961,9963,9966],{},[1106,9962,9750],{},[1106,9964,9965],{},"Mitigation",[1106,9967,9968],{},"Annex I Requirement",[1119,9970,9971,9982,9993,10004,10015,10026,10037,10048,10059],{},[1103,9972,9973,9976,9979],{},[1124,9974,9975],{},"T2 — BLE data leakage",[1124,9977,9978],{},"BLE LE Secure Connections with encryption enabled",[1124,9980,9981],{},"Req 4 (Confidentiality), Req 10 (Secure comms)",[1103,9983,9984,9987,9990],{},[1124,9985,9986],{},"T3 — JTAG key readout",[1124,9988,9989],{},"RDP Level 2 set in production; JTAG permanently disabled",[1124,9991,9992],{},"Req 6 (Attack surface)",[1103,9994,9995,9998,10001],{},[1124,9996,9997],{},"T4 — JTAG firmware install",[1124,9999,10000],{},"RDP Level 2; secure boot verifies firmware signature",[1124,10002,10003],{},"Req 3 (Integrity), Req 6 (Attack surface)",[1103,10005,10006,10009,10012],{},[1124,10007,10008],{},"T5 — Flash readout",[1124,10010,10011],{},"Encryption keys stored in STM32 OTP, not external flash",[1124,10013,10014],{},"Req 4 (Confidentiality)",[1103,10016,10017,10020,10023],{},[1124,10018,10019],{},"T6 — OTA MITM",[1124,10021,10022],{},"OTA images signed with ECDSA P-256; verified by bootloader",[1124,10024,10025],{},"Req 3 (Integrity)",[1103,10027,10028,10031,10034],{},[1124,10029,10030],{},"T7 — Firmware rollback",[1124,10032,10033],{},"Anti-rollback counter in protected flash",[1124,10035,10036],{},"Req 2 (No known vulns), Req 3 (Integrity)",[1103,10038,10039,10042,10045],{},[1124,10040,10041],{},"T8 — Bootloader exploit",[1124,10043,10044],{},"MCUboot with minimal attack surface, verified boot chain",[1124,10046,10047],{},"Req 6 (Attack surface), Req 3 (Integrity)",[1103,10049,10050,10053,10056],{},[1124,10051,10052],{},"T9 — BLE DoS",[1124,10054,10055],{},"Input validation on BLE GATT handlers, watchdog timer",[1124,10057,10058],{},"Req 9 (Availability)",[1103,10060,10061,10064,10067],{},[1124,10062,10063],{},"T10 — Supply chain",[1124,10065,10066],{},"Incoming inspection with firmware verification, vendor qualification",[1124,10068,10069],{},"Req 1 (Appropriate cybersecurity)",[11,10071,10072],{},"This mapping is the core deliverable: it connects your identified risks to specific engineering controls and traces those controls to Annex I requirements.",[21,10074,10076],{"id":10075},"tools-for-embedded-threat-modeling","Tools for Embedded Threat Modeling",[45,10078,10080],{"id":10079},"microsoft-threat-modeling-tool","Microsoft Threat Modeling Tool",[11,10082,10083],{},"Free, GUI-based, uses data flow diagrams with STRIDE analysis. Works well for embedded systems if you create custom element types for MCU components, flash storage, and debug interfaces. The default templates are IT-focused, but custom templates are supported.",[45,10085,10087],{"id":10086},"owasp-threat-dragon","OWASP Threat Dragon",[11,10089,10090],{},"Open-source, web-based. Simpler than Microsoft's tool. Good for smaller teams. Supports STRIDE, data flow diagrams, and threat documentation. Can be self-hosted.",[45,10092,10094],{"id":10093},"attack-trees","Attack Trees",[11,10096,10097],{},"For detailed analysis of specific attack paths (e.g., \"how can an attacker extract the firmware signing key?\"), attack trees provide a more granular view than STRIDE. Each leaf node is a specific attack step; the tree shows how steps combine.",[45,10099,10101],{"id":10100},"pen-and-paper-whiteboard","Pen and Paper / Whiteboard",[11,10103,10104],{},"For small embedded teams, a whiteboard session followed by a structured document is often more practical than a specialised tool. The CRA doesn't require specific tooling — it requires a documented, structured analysis.",[21,10106,10108],{"id":10107},"annex-vii-deliverable-format","Annex VII Deliverable Format",[11,10110,10111],{},"Your threat model document should be part of the Annex VII technical documentation file. A practical structure:",[11,10113,10114],{},[31,10115,10116],{},"1. System description",[86,10118,10119,10122,10125,10128,10131],{},[91,10120,10121],{},"Product overview and intended purpose",[91,10123,10124],{},"System context diagram",[91,10126,10127],{},"Component list",[91,10129,10130],{},"Data flow diagrams",[91,10132,10133],{},"Trust boundaries",[11,10135,10136],{},[31,10137,10138],{},"2. Threat identification",[86,10140,10141,10144,10147],{},[91,10142,10143],{},"Methodology used (STRIDE, attack trees, etc.)",[91,10145,10146],{},"Identified threats with description, STRIDE category, and affected component",[91,10148,10149],{},"Likelihood and impact ratings with rationale",[11,10151,10152],{},[31,10153,10154],{},"3. Mitigation mapping",[86,10156,10157,10160],{},[91,10158,10159],{},"For each threat: mitigation implemented, Annex I requirement satisfied, evidence reference",[91,10161,10162],{},"Residual risk assessment (risks accepted without full mitigation, with justification)",[11,10164,10165],{},[31,10166,10167],{},"4. Test evidence references",[86,10169,10170,10173],{},[91,10171,10172],{},"Links to test reports that validate mitigations",[91,10174,10175],{},"Penetration testing results (where applicable)",[11,10177,10178],{},[31,10179,10180],{},"5. Maintenance plan",[86,10182,10183,10186],{},[91,10184,10185],{},"Triggers for threat model update (see below)",[91,10187,10188],{},"Review schedule",[21,10190,10192],{"id":10191},"maintenance-triggers","Maintenance Triggers",[11,10194,10195],{},"A threat model isn't a one-time document. It must be maintained. The CRA's \"appropriate to the risks\" language means your security controls must stay appropriate as the risk landscape changes.",[11,10197,10198],{},[31,10199,10200],{},"Update your threat model when:",[86,10202,10203,10209,10215,10221,10227,10233],{},[91,10204,10205,10208],{},[31,10206,10207],{},"New hardware revision:"," Changed interfaces, new components, or modified PCB layout may introduce new attack surfaces",[91,10210,10211,10214],{},[31,10212,10213],{},"New firmware feature:"," Adding a network protocol, cloud connectivity, or new peripheral interface changes the attack surface",[91,10216,10217,10220],{},[31,10218,10219],{},"New CVE in a component you use:"," A newly published vulnerability may change the likelihood or impact ratings in your threat model",[91,10222,10223,10226],{},[31,10224,10225],{},"Deployment context change:"," If your product moves into a new market (e.g., from commercial building to healthcare facility), the threat landscape changes",[91,10228,10229,10232],{},[31,10230,10231],{},"Security incident:"," If your product or a similar product is attacked, the threat model should reflect the learned attack vector",[91,10234,10235,10238],{},[31,10236,10237],{},"Annex III reclassification:"," If Annex III is updated and your product's classification changes, the assessment depth may need to increase",[11,10240,10241,10244,10245,10248],{},[31,10242,10243],{},"Recommended review cadence:"," At minimum, review the threat model annually and with every major firmware release. For ",[102,10246,10247],{"href":1179},"Class I and Class II products",", conformity assessment bodies and notified bodies will expect evidence of ongoing threat model maintenance.",[21,10250,10252],{"id":10251},"common-mistakes","Common Mistakes",[11,10254,10255,10258],{},[31,10256,10257],{},"1. Using a generic template without product-specific analysis."," Market surveillance authorities will recognise a copy-pasted threat model. The threats must be specific to your product's architecture and deployment context.",[11,10260,10261,10264],{},[31,10262,10263],{},"2. Ignoring physical attacks."," For embedded products, physical access is often the highest-impact attack vector. If your threat model doesn't cover JTAG, flash readout, and hardware tampering, it's incomplete.",[11,10266,10267,10270],{},[31,10268,10269],{},"3. Not mapping threats to Annex I."," The threat model's purpose in the CRA context is to justify your Annex I mitigations. Without this mapping, the threat model is a standalone document that doesn't demonstrate compliance.",[11,10272,10273,10276],{},[31,10274,10275],{},"4. Treating it as a one-time exercise."," If your threat model was written two years ago and never updated despite three major firmware releases, it won't hold up to scrutiny.",[11,10278,10279,10282],{},[31,10280,10281],{},"5. Overly academic scope."," You don't need to model nation-state attacks on a temperature sensor. Rate threats against your actual deployment context and attacker profile. Document your assumptions about the attacker (skill level, access, motivation).",[21,10284,10286],{"id":10285},"embedded-threat-model-checklist","Embedded Threat Model Checklist",[86,10288,10290,10296,10302,10308,10314,10320,10326,10332,10338,10347,10353,10359,10365],{"className":10289},[89],[91,10291,10293,10295],{"className":10292},[94],[96,10294],{"disabled":98,"type":99}," System context diagram created with all external entities and data flows",[91,10297,10299,10301],{"className":10298},[94],[96,10300],{"disabled":98,"type":99}," Component decomposition covers: bootloader, application, network stack, crypto, storage, debug interfaces, wireless interfaces, OTA mechanism",[91,10303,10305,10307],{"className":10304},[94],[96,10306],{"disabled":98,"type":99}," STRIDE (or equivalent) applied to each component and data flow",[91,10309,10311,10313],{"className":10310},[94],[96,10312],{"disabled":98,"type":99}," Physical attack surface covered (JTAG/SWD, flash readout, hardware tampering)",[91,10315,10317,10319],{"className":10316},[94],[96,10318],{"disabled":98,"type":99}," Supply chain threats assessed",[91,10321,10323,10325],{"className":10322},[94],[96,10324],{"disabled":98,"type":99}," Wireless-specific threats assessed (spoofing, interception, jamming)",[91,10327,10329,10331],{"className":10328},[94],[96,10330],{"disabled":98,"type":99}," Each threat rated for likelihood and impact",[91,10333,10335,10337],{"className":10334},[94],[96,10336],{"disabled":98,"type":99}," Each medium/high threat mapped to a specific mitigation",[91,10339,10341,10343,10344],{"className":10340},[94],[96,10342],{"disabled":98,"type":99}," Each mitigation mapped to an ",[102,10345,10346],{"href":3112},"Annex I requirement",[91,10348,10350,10352],{"className":10349},[94],[96,10351],{"disabled":98,"type":99}," Residual risks documented with acceptance rationale",[91,10354,10356,10358],{"className":10355},[94],[96,10357],{"disabled":98,"type":99}," Test evidence referenced for each mitigation",[91,10360,10362,10364],{"className":10361},[94],[96,10363],{"disabled":98,"type":99}," Maintenance triggers and review schedule defined",[91,10366,10368,10370],{"className":10367},[94],[96,10369],{"disabled":98,"type":99}," Threat model included in Annex VII technical documentation file",[11,10372,2150,10373,10375],{},[102,10374,1475],{"href":1474}," includes a threat model gap assessment that identifies which attack categories you need to cover based on your product's architecture and connectivity.",[1478,10377],{},[11,10379,10380],{},[1483,10381,10382],{},"Based on Regulation EU 2024/2847 Annex VII Section 2, Microsoft STRIDE methodology, OWASP Threat Modeling guidelines, and IEC 62443 (industrial cybersecurity risk assessment). This does not constitute legal advice.",[21,10384,1489],{"id":1488},[86,10386,10387,10392,10399,10405,10412,10418],{},[91,10388,10389],{},[102,10390,1499],{"href":1496,"rel":10391},[1498],[91,10393,10394],{},[102,10395,10398],{"href":10396,"rel":10397},"https://learn.microsoft.com/en-us/azure/security/develop/threat-modeling-tool-threats",[1498],"Microsoft — STRIDE threat model",[91,10400,10401],{},[102,10402,10080],{"href":10403,"rel":10404},"https://learn.microsoft.com/en-us/azure/security/develop/threat-modeling-tool",[1498],[91,10406,10407],{},[102,10408,10411],{"href":10409,"rel":10410},"https://owasp.org/www-community/Threat_Modeling",[1498],"OWASP — Threat Modeling",[91,10413,10414],{},[102,10415,10087],{"href":10416,"rel":10417},"https://owasp.org/www-project-threat-dragon/",[1498],[91,10419,10420],{},[102,10421,10424],{"href":10422,"rel":10423},"https://www.iec.ch/cyber-security",[1498],"IEC 62443 — Industrial cybersecurity standards",{"title":1536,"searchDepth":1537,"depth":1537,"links":10426},[10427,10428,10429,10433,10438,10444,10445,10446,10447,10448],{"id":9358,"depth":1537,"text":9359},{"id":9414,"depth":1537,"text":9415},{"id":9486,"depth":1537,"text":9487,"children":10430},[10431,10432],{"id":9493,"depth":1542,"text":9494},{"id":9592,"depth":1542,"text":9593},{"id":9709,"depth":1537,"text":9710,"children":10434},[10435,10436,10437],{"id":9716,"depth":1542,"text":9717},{"id":9732,"depth":1542,"text":9733},{"id":9953,"depth":1542,"text":9954},{"id":10075,"depth":1537,"text":10076,"children":10439},[10440,10441,10442,10443],{"id":10079,"depth":1542,"text":10080},{"id":10086,"depth":1542,"text":10087},{"id":10093,"depth":1542,"text":10094},{"id":10100,"depth":1542,"text":10101},{"id":10107,"depth":1537,"text":10108},{"id":10191,"depth":1537,"text":10192},{"id":10251,"depth":1537,"text":10252},{"id":10285,"depth":1537,"text":10286},{"id":1488,"depth":1537,"text":1489},"2025-12-04","Threat modeling for embedded products under CRA Annex VII: handling physical attacks, JTAG access, and constrained environments with STRIDE.","/images/blog/previews/threat-modeling.svg",[10453,10454,10455,10456,10457,10458],"CRA threat modeling","threat modeling embedded systems","CRA Annex I threat model","STRIDE embedded firmware","threat model MCU","CRA Annex VII",{},"/blog/cra-threat-modeling-embedded",{"title":9340,"description":10450},"blog/cra-threat-modeling-embedded","_BXkJhIis3TmQETbdCSn0TPs9Z00CwhCcuhkX8Ayox8",{"id":10465,"title":10466,"body":10467,"date":11212,"description":11213,"extension":1577,"image":11214,"keywords":11215,"meta":11222,"navigation":98,"path":11223,"readTime":2228,"seo":11224,"stem":11225,"__hash__":11226},"blog/blog/cra-product-classification.md","CRA Classification: Default, Class I, or Class II?",{"type":8,"value":10468,"toc":11190},[10469,10475,10478,10481,10487,10491,10495,10502,10519,10522,10528,10532,10535,10541,10547,10550,10554,10557,10566,10573,10576,10580,10584,10587,10651,10654,10658,10661,10706,10709,10713,10872,10877,10888,10892,10895,10898,10901,10905,10908,10912,10932,10936,10961,10965,10989,10993,10996,11001,11009,11014,11024,11029,11037,11042,11047,11052,11063,11068,11073,11076,11080,11083,11086,11112,11116,11119,11128,11134,11143,11148,11150,11155,11157],[11,10470,10471,10472],{},"Once you've confirmed your product is in CRA scope, the next critical question is: ",[31,10473,10474],{},"what conformity assessment route applies to your product?",[11,10476,10477],{},"The answer determines whether you can self-certify, whether you need a third-party conformity assessment body (CAB) audit, or whether you need a notified body—the most rigorous and expensive option. For embedded firmware teams managing multiple product lines, this classification decision has significant budget and timeline implications.",[11,10479,10480],{},"This post walks through the three conformity tiers, how to classify common embedded product types, and what each route actually requires.",[11,10482,10483],{},[4506,10484],{"alt":10485,"src":10486},"CRA Enforcement Timeline — Key dates from entry into force through full enforcement","/images/blog/cra-timeline.svg",[21,10488,10490],{"id":10489},"the-three-conformity-assessment-tiers","The Three Conformity Assessment Tiers",[45,10492,10494],{"id":10493},"default-category-self-declaration","Default Category: Self-Declaration",[11,10496,10497,10498,10501],{},"Products that aren't listed in Annex III (or don't fall within an Annex III category) are in the ",[31,10499,10500],{},"default category",". Under Article 24, default-category products can follow a self-assessment route:",[86,10503,10504,10507,10510,10513,10516],{},[91,10505,10506],{},"Internal production control (Module A, Annex VI)",[91,10508,10509],{},"Manufacturer assesses conformity against Annex I essential requirements",[91,10511,10512],{},"Manufacturer prepares technical documentation (Annex VII)",[91,10514,10515],{},"Manufacturer draws up EU Declaration of Conformity",[91,10517,10518],{},"Manufacturer affixes CE mark",[11,10520,10521],{},"This is the fastest and cheapest route. No third-party involvement is required, though if you implement harmonised standards (when CEN/CENELEC publish them), you get a presumption of conformity that substantially simplifies documentation.",[11,10523,10524,10527],{},[31,10525,10526],{},"Important:"," \"self-declaration\" does not mean \"no evidence required.\" Market surveillance authorities can request your technical documentation at any time, and they will scrutinize it. A credible self-assessment requires genuine engineering work—threat modelling, vulnerability testing, SBOM generation, and documented security processes.",[45,10529,10531],{"id":10530},"class-i-third-party-audit-required","Class I: Third-Party Audit Required",[11,10533,10534],{},"Class I products appear in Annex III, Part I. For these products, Article 24(2) requires either:",[11,10536,10537,10540],{},[31,10538,10539],{},"Option A:"," Assessment by a conformity assessment body (CAB) using an EU-type examination (Module B, Annex VII) followed by internal production control (Module C, Annex VIII)",[11,10542,10543,10546],{},[31,10544,10545],{},"Option B:"," Quality management system assessment (Module H, Annex IX) by a CAB",[11,10548,10549],{},"The key difference from the default category: a recognised, accredited third party must be involved in the conformity assessment. You cannot self-certify.",[45,10551,10553],{"id":10552},"class-ii-notified-body-mandatory","Class II: Notified Body Mandatory",[11,10555,10556],{},"Class II products appear in Annex III, Part II. These are considered highest-risk. Article 24(3) requires:",[11,10558,10559,10561,10562,10565],{},[31,10560,10539],{}," EU-type examination (Module B) by a ",[31,10563,10564],{},"notified body"," + internal production control (Module C)",[11,10567,10568,10570,10571],{},[31,10569,10545],{}," Full quality assurance (Module H) by a ",[31,10572,10564],{},[11,10574,10575],{},"A notified body is a conformity assessment body designated by an EU member state and notified to the European Commission. This is a significantly higher bar than a general CAB. As of early 2026, the EU notified body designation process for CRA is still being finalised, making this route the most constrained from a supply perspective.",[21,10577,10579],{"id":10578},"annex-iii-which-products-are-class-i-or-class-ii","Annex III: Which Products Are Class I or Class II?",[45,10581,10583],{"id":10582},"class-i-products-annex-iii-part-i","Class I Products (Annex III, Part I)",[11,10585,10586],{},"The following product types require third-party conformity assessment:",[86,10588,10589,10592,10595,10598,10601,10604,10607,10610,10613,10616,10619,10622,10627,10630,10635,10640,10645],{},[91,10590,10591],{},"Identity management systems and privileged access management software",[91,10593,10594],{},"Standalone and embedded browsers",[91,10596,10597],{},"Password managers",[91,10599,10600],{},"Malware detection and antivirus software",[91,10602,10603],{},"Products with digital elements with VPN functionality",[91,10605,10606],{},"Network management systems",[91,10608,10609],{},"Security information and event management (SIEM) systems",[91,10611,10612],{},"Boot managers",[91,10614,10615],{},"Public key infrastructure (PKI) and digital certificate issuers",[91,10617,10618],{},"General-purpose microprocessors",[91,10620,10621],{},"Operating systems for general-purpose use (servers, desktops, mobile)",[91,10623,10624],{},[31,10625,10626],{},"Routers, modems intended for consumers",[91,10628,10629],{},"Microcontrollers",[91,10631,10632],{},[31,10633,10634],{},"Application-specific integrated circuits (ASICs) and field-programmable gate arrays (FPGAs)",[91,10636,10637],{},[31,10638,10639],{},"Industrial automation and control systems",[91,10641,10642],{},[31,10643,10644],{},"Smart home general-purpose virtual assistants",[91,10646,10647,10650],{},[31,10648,10649],{},"Smart home products"," with security functionality (locks, alarm systems, baby monitors)",[11,10652,10653],{},"For embedded firmware teams, the items in bold are most directly relevant. If you're building industrial controllers, PLCs, HMIs, or connected smart home devices with security functions, you're likely in Class I.",[45,10655,10657],{"id":10656},"class-ii-products-annex-iii-part-ii","Class II Products (Annex III, Part II)",[11,10659,10660],{},"The highest-risk tier covers:",[86,10662,10663,10668,10674,10680,10685,10690,10695,10700],{},[91,10664,10665],{},[31,10666,10667],{},"Hypervisors and container runtime software used in industrial, critical infrastructure, or automotive applications",[91,10669,10670,10673],{},[31,10671,10672],{},"Firewalls, intrusion detection, and intrusion prevention systems"," used in industrial or critical infrastructure",[91,10675,10676,10679],{},[31,10677,10678],{},"Tamper-resistant microprocessors"," used in sensitive applications",[91,10681,10682],{},[31,10683,10684],{},"Hardware security modules (HSMs)",[91,10686,10687],{},[31,10688,10689],{},"Secure elements",[91,10691,10692],{},[31,10693,10694],{},"Smart meter gateways",[91,10696,10697,10699],{},[31,10698,10639],{}," used in critical infrastructure (power, water, transport)",[91,10701,10702,10705],{},[31,10703,10704],{},"Robot sensors and actuators"," used in safety-relevant functions",[11,10707,10708],{},"Class II products are concentrated in critical infrastructure and high-assurance security components. If you're building HSMs, smart meter gateways, or industrial controllers for power/water utilities, this is your tier.",[21,10710,10712],{"id":10711},"product-classification-map-for-embedded-teams","Product Classification Map for Embedded Teams",[1097,10714,10715,10728],{},[1100,10716,10717],{},[1103,10718,10719,10722,10725],{},[1106,10720,10721],{},"Product Type",[1106,10723,10724],{},"Likely Classification",[1106,10726,10727],{},"Rationale",[1119,10729,10730,10741,10752,10762,10773,10783,10793,10803,10813,10823,10833,10843,10853,10863],{},[1103,10731,10732,10735,10738],{},[1124,10733,10734],{},"General IoT sensor (no security function)",[1124,10736,10737],{},"Default",[1124,10739,10740],{},"Not listed in Annex III",[1103,10742,10743,10746,10749],{},[1124,10744,10745],{},"Consumer Wi-Fi router",[1124,10747,10748],{},"Class I",[1124,10750,10751],{},"Annex III Part I explicitly lists consumer routers",[1103,10753,10754,10757,10759],{},[1124,10755,10756],{},"Industrial PLC (non-critical infrastructure)",[1124,10758,10748],{},[1124,10760,10761],{},"ICS listed in Annex III Part I",[1103,10763,10764,10767,10770],{},[1124,10765,10766],{},"Industrial PLC (power/water utilities)",[1124,10768,10769],{},"Class II",[1124,10771,10772],{},"Critical infrastructure ICS",[1103,10774,10775,10778,10780],{},[1124,10776,10777],{},"Smart door lock",[1124,10779,10748],{},[1124,10781,10782],{},"Smart home with security function",[1103,10784,10785,10788,10790],{},[1124,10786,10787],{},"Baby monitor with camera",[1124,10789,10748],{},[1124,10791,10792],{},"Smart home product listed",[1103,10794,10795,10798,10800],{},[1124,10796,10797],{},"FPGA development board",[1124,10799,10748],{},[1124,10801,10802],{},"FPGAs listed in Annex III Part I",[1103,10804,10805,10808,10810],{},[1124,10806,10807],{},"Custom ASIC",[1124,10809,10748],{},[1124,10811,10812],{},"ASICs listed in Annex III Part I",[1103,10814,10815,10818,10820],{},[1124,10816,10817],{},"Hardware Security Module",[1124,10819,10769],{},[1124,10821,10822],{},"Explicitly listed",[1103,10824,10825,10828,10830],{},[1124,10826,10827],{},"Embedded RTOS (standalone, for sale)",[1124,10829,10737],{},[1124,10831,10832],{},"Not listed (RTOS ≠ general OS)",[1103,10834,10835,10838,10840],{},[1124,10836,10837],{},"General-purpose MCU",[1124,10839,10748],{},[1124,10841,10842],{},"Microcontrollers listed in Annex III Part I",[1103,10844,10845,10848,10850],{},[1124,10846,10847],{},"Wearable health tracker (non-medical)",[1124,10849,10737],{},[1124,10851,10852],{},"Not listed",[1103,10854,10855,10858,10860],{},[1124,10856,10857],{},"VPN appliance",[1124,10859,10748],{},[1124,10861,10862],{},"VPN functionality listed",[1103,10864,10865,10868,10870],{},[1124,10866,10867],{},"Smart meter gateway",[1124,10869,10769],{},[1124,10871,10822],{},[11,10873,10874],{},[31,10875,10876],{},"Important caveats:",[86,10878,10879,10882,10885],{},[91,10880,10881],{},"Annex III is subject to update via delegated acts as the Commission collects market data",[91,10883,10884],{},"Classification depends on the product's \"intended purpose\"—the same hardware with different firmware/intended use cases may classify differently",[91,10886,10887],{},"ENISA has published classification guidance, but final harmonised interpretation will emerge through market surveillance practice",[21,10889,10891],{"id":10890},"how-intended-purpose-affects-classification","How \"Intended Purpose\" Affects Classification",[11,10893,10894],{},"Article 6(2) requires classification based on the product's intended purpose as declared by the manufacturer. This gives manufacturers some flexibility, but also responsibility.",[11,10896,10897],{},"If you build a general-purpose embedded controller and position it as a \"development kit\" with \"not for safety-critical use\" disclaimers, you may be able to justify a lower classification. But if the same hardware is sold as an industrial PLC for factory automation without such restrictions, Class I likely applies.",[11,10899,10900],{},"The \"reasonably foreseeable use\" language in Article 2(1) means you can't simply use disclaimers to avoid higher-risk classification if market surveillance authorities determine that safety-critical use was foreseeable. Keep this in mind when writing your product documentation and intended purpose statements.",[21,10902,10904],{"id":10903},"conformity-assessment-routes-time-and-cost-estimates","Conformity Assessment Routes: Time and Cost Estimates",[11,10906,10907],{},"These are approximate figures based on industry experience—actual costs vary significantly by CAB and product complexity:",[45,10909,10911],{"id":10910},"default-category-module-a","Default Category (Module A)",[86,10913,10914,10920,10926],{},[91,10915,10916,10919],{},[31,10917,10918],{},"Timeline:"," 3–9 months depending on existing documentation and security maturity",[91,10921,10922,10925],{},[31,10923,10924],{},"Cost:"," Primarily internal engineering time + optional consultant review",[91,10927,10928,10931],{},[31,10929,10930],{},"Documentation required:"," Annex VII technical file (threat model, vulnerability assessment, test results, SBOM, incident handling procedures, technical description)",[45,10933,10935],{"id":10934},"class-i-module-b-c-or-module-h","Class I (Module B + C or Module H)",[86,10937,10938,10943,10949,10955],{},[91,10939,10940,10942],{},[31,10941,10918],{}," 6–18 months",[91,10944,10945,10948],{},[31,10946,10947],{},"CAB audit cost:"," €15,000–€60,000 depending on product complexity and CAB",[91,10950,10951,10954],{},[31,10952,10953],{},"Preparation cost:"," Significant internal engineering time + documentation",[91,10956,10957,10960],{},[31,10958,10959],{},"Key requirement:"," Pass EU-type examination with CAB; demonstrate Annex I conformance",[45,10962,10964],{"id":10963},"class-ii-notified-body-module-b-c-or-module-h","Class II (Notified Body, Module B + C or Module H)",[86,10966,10967,10972,10978,10983],{},[91,10968,10969,10971],{},[31,10970,10918],{}," 12–24 months (limited by notified body availability in 2026–2027)",[91,10973,10974,10977],{},[31,10975,10976],{},"Notified body cost:"," €40,000–€150,000+",[91,10979,10980,10982],{},[31,10981,10953],{}," Very high; requires extensive security testing, formal documentation",[91,10984,10985,10988],{},[31,10986,10987],{},"Key constraint:"," Notified body supply is limited; book early",[21,10990,10992],{"id":10991},"what-the-technical-documentation-must-include","What the Technical Documentation Must Include",[11,10994,10995],{},"Regardless of conformity route, Article 31 and Annex VII require manufacturers to prepare and maintain technical documentation. For firmware teams, the relevant sections are:",[11,10997,10998],{},[31,10999,11000],{},"Section 1: Product description",[86,11002,11003,11006],{},[91,11004,11005],{},"General description including intended purpose",[91,11007,11008],{},"Hardware and software version(s) to which it applies",[11,11010,11011],{},[31,11012,11013],{},"Section 2: Design and development",[86,11015,11016,11019,11021],{},[91,11017,11018],{},"Design and development drawings and diagrams",[91,11020,1060],{},[91,11022,11023],{},"Security architecture documentation",[11,11025,11026],{},[31,11027,11028],{},"Section 3: Testing",[86,11030,11031,11034],{},[91,11032,11033],{},"Test reports and vulnerability assessment results",[91,11035,11036],{},"Penetration testing methodology and results (for Class I/II)",[11,11038,11039],{},[31,11040,11041],{},"Section 4: SBOM",[86,11043,11044],{},[91,11045,11046],{},"Machine-readable SBOM of all software components",[11,11048,11049],{},[31,11050,11051],{},"Section 5: Processes",[86,11053,11054,11057,11060],{},[91,11055,11056],{},"Vulnerability handling processes",[91,11058,11059],{},"Security update delivery mechanism",[91,11061,11062],{},"End-of-life policies (for how long you'll provide security updates)",[11,11064,11065],{},[31,11066,11067],{},"Section 6: Incidents",[86,11069,11070],{},[91,11071,11072],{},"Overview of post-market monitoring processes",[11,11074,11075],{},"This documentation must be kept for 10 years after the product is placed on the market.",[21,11077,11079],{"id":11078},"handling-multi-product-portfolios","Handling Multi-Product Portfolios",[11,11081,11082],{},"If you have multiple product lines, classification needs to be done per product (or per product family where the products are substantially similar and use the same hardware/firmware platform).",[11,11084,11085],{},"A common approach for embedded product companies:",[1013,11087,11088,11094,11100,11106],{},[91,11089,11090,11093],{},[31,11091,11092],{},"Classify each product family"," against Annex III",[91,11095,11096,11099],{},[31,11097,11098],{},"Group by conformity route"," — run Module H QMS assessments for Class I products (more efficient if you have multiple similar products) rather than separate Module B + C per product",[91,11101,11102,11105],{},[31,11103,11104],{},"Prioritise by revenue and sales volume"," — start conformity assessment for your highest-volume or highest-revenue EU products first",[91,11107,11108,11111],{},[31,11109,11110],{},"Establish a common security baseline"," — implement the Annex I essential requirements once across your platform, then product-specific documentation per product family",[21,11113,11115],{"id":11114},"what-happens-after-classification","What Happens After Classification",[11,11117,11118],{},"Once you know your tier:",[11,11120,11121,11124,11125,11127],{},[31,11122,11123],{},"Default category:"," Proceed directly to implementing Annex I requirements and preparing technical documentation. Use our ",[102,11126,8204],{"href":3112}," to track your progress against every requirement. Set up your vulnerability reporting process (required regardless of tier—Article 14 applies to all manufacturers). Generate your SBOM. Write your EU Declaration of Conformity. Affix CE mark.",[11,11129,11130,11133],{},[31,11131,11132],{},"Class I:"," Do all of the above, but additionally engage a CAB for Module B examination. CABs will want to see your technical documentation in advance of the examination, so prepare thoroughly before booking the assessment.",[11,11135,11136,11139,11140,11142],{},[31,11137,11138],{},"Class II:"," Engage a notified body early—as early as 2026 if your deadline is December 2027. The current supply constraint means waiting lists are forming. Start with your ",[102,11141,105],{"href":104}," and security architecture documentation, as these are typically the first things notified bodies review.",[11,11144,2150,11145,11147],{},[102,11146,1475],{"href":1474}," will identify your likely classification and the specific gaps you need to address for your product type, based on 7 questions about your firmware and product architecture.",[1478,11149],{},[11,11151,11152],{},[1483,11153,11154],{},"Based on Regulation EU 2024/2847, Annex III, Article 6, Article 24, Annex VI–IX. ENISA classification guidance (2025). This does not constitute legal advice. Classification decisions should be validated with qualified legal counsel familiar with EU product regulation.",[21,11156,1489],{"id":1488},[86,11158,11159,11164,11170,11177,11184],{},[91,11160,11161],{},[102,11162,1499],{"href":1496,"rel":11163},[1498],[91,11165,11166],{},[102,11167,11169],{"href":1504,"rel":11168},[1498],"CRA full text (HTML) — see Annex III, Article 6, Article 24",[91,11171,11172],{},[102,11173,11176],{"href":11174,"rel":11175},"https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=OJ:L_202402847",[1498],"CRA full text (PDF)",[91,11178,11179],{},[102,11180,11183],{"href":11181,"rel":11182},"https://digital-strategy.ec.europa.eu/en/policies/cra-summary",[1498],"European Commission — Cyber Resilience Act summary",[91,11185,11186],{},[102,11187,11189],{"href":1518,"rel":11188},[1498],"ENISA — CRA implementation guidance",{"title":1536,"searchDepth":1537,"depth":1537,"links":11191},[11192,11197,11201,11202,11203,11208,11209,11210,11211],{"id":10489,"depth":1537,"text":10490,"children":11193},[11194,11195,11196],{"id":10493,"depth":1542,"text":10494},{"id":10530,"depth":1542,"text":10531},{"id":10552,"depth":1542,"text":10553},{"id":10578,"depth":1537,"text":10579,"children":11198},[11199,11200],{"id":10582,"depth":1542,"text":10583},{"id":10656,"depth":1542,"text":10657},{"id":10711,"depth":1537,"text":10712},{"id":10890,"depth":1537,"text":10891},{"id":10903,"depth":1537,"text":10904,"children":11204},[11205,11206,11207],{"id":10910,"depth":1542,"text":10911},{"id":10934,"depth":1542,"text":10935},{"id":10963,"depth":1542,"text":10964},{"id":10991,"depth":1537,"text":10992},{"id":11078,"depth":1537,"text":11079},{"id":11114,"depth":1537,"text":11115},{"id":1488,"depth":1537,"text":1489},"2025-11-20","CRA Default, Class I, and Class II tiers explained: which conformity assessment path you take and what it costs in time and money.","/images/blog/previews/classification.svg",[11216,11217,11218,11219,11220,10564,11221],"CRA product classification","CRA Class I","CRA Class II","CRA conformity assessment","Annex III","CE marking",{},"/blog/cra-product-classification",{"title":10466,"description":11213},"blog/cra-product-classification","GmbnjUyXUHLYrWbkrxT7M6L40AA0rwTAkDzzqvdcWl4",{"id":11228,"title":11229,"body":11230,"date":11757,"description":11758,"extension":1577,"image":11759,"keywords":11760,"meta":11765,"navigation":98,"path":11766,"readTime":11767,"seo":11768,"stem":11769,"__hash__":11770},"blog/blog/is-your-product-in-cra-scope.md","Is Your Embedded Product in CRA Scope?",{"type":8,"value":11231,"toc":11731},[11232,11242,11248,11251,11254,11260,11264,11267,11276,11279,11282,11297,11301,11304,11310,11318,11323,11334,11340,11343,11347,11350,11354,11357,11361,11364,11368,11371,11375,11378,11382,11389,11394,11401,11408,11413,11424,11427,11431,11434,11437,11441,11444,11448,11455,11458,11469,11473,11480,11483,11494,11500,11504,11511,11515,11518,11522,11525,11539,11546,11552,11556,11563,11574,11577,11581,11584,11598,11601,11605,11631,11634,11638,11641,11693,11699,11701,11706,11708],[11,11233,11234,11235,11237,11238,11241],{},"The EU Cyber Resilience Act (Regulation EU 2024/2847) has been in force since December 2024. Vulnerability reporting obligations begin ",[31,11236,1609],{},", with full enforcement from ",[31,11239,11240],{},"11 December 2027",". If you build embedded products that touch the EU market in any way, the clock is running.",[11,11243,11244,11245],{},"The first question every product team needs to answer isn't about SBOM formats or vulnerability disclosure timelines. It's simpler: ",[31,11246,11247],{},"does the CRA even apply to us?",[11,11249,11250],{},"Getting this wrong in either direction is expensive. Assume you're out of scope when you're not, and you're exposed to fines of up to €15 million or 2.5% of global turnover. Over-scope your assessment and you'll waste engineering cycles on conformity activities that aren't required.",[11,11252,11253],{},"This post gives you a structured decision framework based on the actual CRA text.",[11,11255,11256],{},[4506,11257],{"alt":11258,"src":11259},"CRA Scope Decision Flowchart — Is your product in scope?","/images/blog/cra-scope-flowchart.svg",[21,11261,11263],{"id":11262},"what-the-cra-covers-the-products-with-digital-elements-definition","What the CRA Covers: The \"Products with Digital Elements\" Definition",[11,11265,11266],{},"Article 2(1) sets the scope:",[8349,11268,11269],{},[11,11270,11271,11272,11275],{},"The Regulation applies to ",[31,11273,11274],{},"products with digital elements"," whose intended purpose or reasonably foreseeable use includes a direct or indirect logical or physical data connection to a device or network.",[11,11277,11278],{},"Article 3(1) defines a product with digital elements as any software or hardware product, and its remote data processing solutions, intended for use with a data connection to a device or network.",[11,11280,11281],{},"Two things jump out immediately:",[1013,11283,11284,11290],{},[91,11285,11286,11289],{},[31,11287,11288],{},"Both hardware and software"," are in scope. A firmware image sold separately from the hardware it runs on is a product with digital elements.",[91,11291,11292,11293,11296],{},"The connection can be ",[31,11294,11295],{},"indirect",". A device that doesn't itself connect to the internet but connects to a gateway device that does is still in scope.",[45,11298,11300],{"id":11299},"the-direct-vs-indirect-connection-grey-area","The Direct vs. Indirect Connection Grey Area",[11,11302,11303],{},"This is where most embedded teams get caught. Article 3(1) and Recital 14 clarify what \"indirect\" means in practice.",[11,11305,11306,11309],{},[31,11307,11308],{},"Direct connection"," examples:",[86,11311,11312,11315],{},[91,11313,11314],{},"Wi-Fi, Bluetooth, Ethernet, cellular (LTE/5G), Zigbee, Thread, Z-Wave connected devices",[91,11316,11317],{},"USB-connected devices that expose a network interface (e.g., a USB NIC)",[11,11319,11320,11309],{},[31,11321,11322],{},"Indirect connection",[86,11324,11325,11328,11331],{},[91,11326,11327],{},"A sensor node that communicates only via a proprietary RF protocol to a hub—the hub connects to the internet. The sensor is indirectly connected.",[91,11329,11330],{},"A motor controller that receives commands from a PLC, which in turn has a SCADA uplink. The controller is indirectly connected.",[91,11332,11333],{},"A Bluetooth peripheral (headset, HID device) that pairs with a smartphone. The peripheral has an indirect internet connection via the phone.",[11,11335,11336,11339],{},[31,11337,11338],{},"The practical test:"," Could data flow from your device to a network or from a network to your device, even through one or more intermediary devices? If yes, you're likely in scope.",[11,11341,11342],{},"Recital 12 specifically notes that products connecting to other products rather than directly to networks are still covered \"where such products were intended or could reasonably be expected to be connected to a network.\"",[21,11344,11346],{"id":11345},"whats-explicitly-out-of-scope","What's Explicitly Out of Scope",[11,11348,11349],{},"Article 2(2) lists explicit exclusions. The most relevant for embedded teams:",[45,11351,11353],{"id":11352},"medical-devices","Medical Devices",[11,11355,11356],{},"Products regulated under Regulation (EU) 2017/745 (MDR) or 2017/746 (IVDR) are excluded. Those regulations have their own cybersecurity requirements under MDCG guidance.",[45,11358,11360],{"id":11359},"aviation","Aviation",[11,11362,11363],{},"Products covered under Regulation (EU) 2018/1139 (EASA framework) are excluded.",[45,11365,11367],{"id":11366},"automotive","Automotive",[11,11369,11370],{},"Motor vehicles under Regulation (EU) 2019/2144 are excluded. Note this refers to the vehicle-level regulation; embedded components supplied into the automotive sector may still need CRA compliance if sold commercially outside the automotive type-approval chain.",[45,11372,11374],{"id":11373},"national-security-and-defence","National Security and Defence",[11,11376,11377],{},"Products intended exclusively for defence, national security, or classified information are out of scope.",[45,11379,11381],{"id":11380},"offline-products","Offline Products",[11,11383,11384,11385,11388],{},"Here is where many teams make a mistake. There is ",[31,11386,11387],{},"no blanket offline exemption",". Article 2(2)(h) excludes only:",[8349,11390,11391],{},[11,11392,11393],{},"Products with digital elements developed or modified exclusively for national security or defence purposes, or specifically designed to process classified information.",[11,11395,11396,11397,11400],{},"A general-purpose industrial controller that happens to be deployed offline is still in scope if it's a commercially available product with the ",[1483,11398,11399],{},"capability"," for data connection, even if a specific deployment doesn't use it.",[11,11402,11403,11404,11407],{},"The relevant test is ",[31,11405,11406],{},"intended purpose and reasonably foreseeable use",", not actual deployment configuration. If your product's datasheet lists a Modbus TCP port, or your firmware includes an Ethernet driver, market surveillance authorities may treat that as evidence of connectivity capability.",[11,11409,11410],{},[31,11411,11412],{},"When offline products are genuinely out of scope:",[86,11414,11415,11418,11421],{},[91,11416,11417],{},"The product physically cannot connect (no hardware interfaces, no radio, no comms stack in firmware)",[91,11419,11420],{},"The intended purpose explicitly excludes any data connection",[91,11422,11423],{},"The reasonably foreseeable use wouldn't involve network connectivity",[11,11425,11426],{},"If you're removing a Wi-Fi module from a product to try to get out of CRA scope, you need legal advice before proceeding—regulators are aware of this approach and the CRA's \"reasonably foreseeable use\" language was written to address it.",[21,11428,11430],{"id":11429},"the-open-source-software-question","The Open Source Software Question",[11,11432,11433],{},"Recital 18 and Article 2(3) address open source software. OSS released free of charge and not commercially exploited by its developer is out of scope. However, if a company monetises OSS (through commercial support, SaaS delivery, or integration into a commercial product), it falls within scope.",[11,11435,11436],{},"For embedded product teams, this is almost always moot—if you're shipping a product with embedded software, you're a manufacturer, and the software inside that product is subject to CRA regardless of its licensing.",[21,11438,11440],{"id":11439},"oem-and-component-manufacturer-liability","OEM and Component Manufacturer Liability",[11,11442,11443],{},"This is the area of greatest confusion, and the CRA text is more nuanced than many summaries suggest.",[45,11445,11447],{"id":11446},"article-13-manufacturer-obligations","Article 13: Manufacturer Obligations",[11,11449,11450,11451,11454],{},"Article 13 establishes that ",[31,11452,11453],{},"manufacturers"," bear primary responsibility for CRA compliance. A manufacturer is defined in Article 3(13) as \"a natural or legal person who develops or manufactures products with digital elements or has products with digital elements designed, developed or manufactured, and markets those products under their name or trademark.\"",[11,11456,11457],{},"Key implications:",[86,11459,11460,11463,11466],{},[91,11461,11462],{},"If you put your brand on a product, you are the manufacturer under the CRA, even if you didn't write the firmware",[91,11464,11465],{},"If you have firmware written by a third party and white-label it, you're the manufacturer",[91,11467,11468],{},"You can't contractually transfer manufacturer status to your ODM or firmware vendor",[45,11470,11472],{"id":11471},"supply-chain-obligations","Supply Chain Obligations",[11,11474,11475,11476,11479],{},"The CRA addresses supply chain responsibilities across several articles. Article 13 establishes the core manufacturer obligations, which include ensuring that components integrated into your product meet the essential requirements. Article 20 specifically covers ",[31,11477,11478],{},"distributor"," obligations (due diligence, CE marking verification, corrective measures for non-compliant products), while Article 19 covers importers.",[11,11481,11482],{},"For component integration, the key provisions are in Article 13 and the essential requirements themselves. When a manufacturer integrates a component (hardware or software) into a product, the integrating manufacturer is responsible for:",[86,11484,11485,11488,11491],{},[91,11486,11487],{},"Ensuring the component meets CRA essential requirements as part of the overall product",[91,11489,11490],{},"Having a process to receive vulnerability notifications from component vendors",[91,11492,11493],{},"Passing security updates through to your customers",[11,11495,11496,11497,11499],{},"The integrating manufacturer is ",[31,11498,3273],{}," exempted from responsibility by using third-party components. If your product includes third-party firmware components (e.g., a cellular module with proprietary stack, a Wi-Fi chipset with vendor firmware, a Bluetooth SoC with closed-source BLE stack), you need contractual security commitments from those vendors.",[45,11501,11503],{"id":11502},"the-integrator-vs-manufacturer-distinction","The Integrator vs. Manufacturer Distinction",[11,11505,11506,11507,11510],{},"One important nuance: Article 3(13) distinguishes manufacturers from importers (Article 3(20)) and distributors (Article 3(21)). If your company ",[1483,11508,11509],{},"only"," imports and resells products without modification, different rules apply (Article 19 for importers). But if you modify firmware, add features, or rebrand the product, you become the manufacturer.",[21,11512,11514],{"id":11513},"a-practical-decision-framework","A Practical Decision Framework",[11,11516,11517],{},"Work through these questions in order:",[45,11519,11521],{"id":11520},"step-1-is-it-a-product-with-digital-elements","Step 1: Is it a product with digital elements?",[11,11523,11524],{},"Does your product have any of the following?",[86,11526,11527,11530,11533,11536],{},[91,11528,11529],{},"A network interface (Ethernet, Wi-Fi, cellular, Zigbee, Thread, Z-Wave, LoRa, BLE, etc.)",[91,11531,11532],{},"A wired serial interface that could connect to a networked device (RS-485, CAN, Modbus, EtherCAT, PROFINET)",[91,11534,11535],{},"A USB port or interface",[91,11537,11538],{},"Any RF capability",[11,11540,11541,11542,11545],{},"If ",[31,11543,11544],{},"no"," to all of the above and the firmware has no networking stack: likely out of scope. Document this assessment.",[11,11547,11541,11548,11551],{},[31,11549,11550],{},"yes"," to any: proceed to Step 2.",[45,11553,11555],{"id":11554},"step-2-is-it-sold-or-placed-on-the-eu-market","Step 2: Is it sold or placed on the EU market?",[11,11557,11558,11559,11562],{},"The CRA applies to products ",[31,11560,11561],{},"placed on the EU market",". If you sell only in the US, Japan, or other non-EU markets and have no plans for EU sales, the CRA doesn't apply. However:",[86,11564,11565,11568,11571],{},[91,11566,11567],{},"If your distributors sell into the EU, you're on the EU market",[91,11569,11570],{},"If your end customers are based in EU countries, you're on the EU market",[91,11572,11573],{},"If a European B2B customer uses your product internally (even without resale), it may still be \"placed on the market\" depending on the commercial arrangement",[11,11575,11576],{},"If you're not on the EU market now but have EU expansion plans: start your CRA compliance programme now, as the timeline to December 2027 is not long for embedded firmware teams.",[45,11578,11580],{"id":11579},"step-3-does-an-explicit-exemption-apply","Step 3: Does an explicit exemption apply?",[11,11582,11583],{},"Check the Article 2(2) exclusion list:",[86,11585,11586,11589,11592,11595],{},[91,11587,11588],{},"Medical device under MDR/IVDR?",[91,11590,11591],{},"Aviation product under EASA regulation?",[91,11593,11594],{},"Automotive vehicle under EU 2019/2144?",[91,11596,11597],{},"National security / defence product?",[11,11599,11600],{},"If yes to any: consult the applicable sectoral regulation for its cybersecurity requirements.",[45,11602,11604],{"id":11603},"step-4-whats-your-role","Step 4: What's your role?",[86,11606,11607,11613,11619,11625],{},[91,11608,11609,11612],{},[31,11610,11611],{},"Manufacturer"," (you design/build/brand the product): full CRA obligations under Article 13",[91,11614,11615,11618],{},[31,11616,11617],{},"Importer"," (you import and sell a third-party product under your name): Article 19 obligations",[91,11620,11621,11624],{},[31,11622,11623],{},"Distributor"," (you resell without modification): Article 22 obligations (lighter, but you must verify the manufacturer has a CE mark and compliant declaration)",[91,11626,11627,11630],{},[31,11628,11629],{},"Component supplier"," (you supply a module or software that others integrate): Article 20 obligations",[11,11632,11633],{},"Most embedded product companies are manufacturers or importers with full Article 13 obligations.",[21,11635,11637],{"id":11636},"what-comes-next-if-youre-in-scope","What Comes Next If You're In Scope",[11,11639,11640],{},"If your product is in scope, your next steps are:",[1013,11642,11643,11651,11660,11669,11678,11687],{},[91,11644,11645,11648,11649,1828],{},[31,11646,11647],{},"Classify your product"," — Default (self-certify), Class I (third-party audit), or Class II (notified body). This depends on Annex III product lists. (See our post on ",[102,11650,11216],{"href":1179},[91,11652,11653,11656,11657,11659],{},[31,11654,11655],{},"Gap-assess against Annex I"," — The essential requirements cover secure design, vulnerability handling, security updates, SBOM, and technical documentation. Our ",[102,11658,8204],{"href":3112}," maps every requirement to concrete firmware engineering tasks.",[91,11661,11662,11665,11666,1828],{},[31,11663,11664],{},"Implement secure boot"," — Annex I requires firmware integrity protection. For MCU-based products, this means a verified boot chain with code signing. (See our post on ",[102,11667,11668],{"href":209},"CRA secure boot and firmware signing",[91,11670,11671,11674,11675,1828],{},[31,11672,11673],{},"Set up vulnerability reporting"," — Article 14 requires a 24-hour initial notification to ENISA for actively exploited vulnerabilities, with a 72-hour follow-up. (See our post on ",[102,11676,11677],{"href":911},"Article 14 vulnerability reporting",[91,11679,11680,11683,11684,1828],{},[31,11681,11682],{},"Generate an SBOM"," — Annex I Part II requires a machine-readable SBOM of all components. For firmware teams, this means integrating SBOM generation into your build system. (See our post on ",[102,11685,11686],{"href":152},"CRA-compliant firmware SBOMs",[91,11688,11689,11692],{},[31,11690,11691],{},"Prepare the technical documentation and EU Declaration of Conformity"," — Required before placing the CE mark.",[11,11694,11695,11696,11698],{},"The scope analysis is the foundation everything else builds on. If you're uncertain, use the ",[102,11697,1475],{"href":1474}," — it will classify your product and identify your specific gaps in about 2 minutes.",[1478,11700],{},[11,11702,11703],{},[1483,11704,11705],{},"This post is based on the final text of Regulation EU 2024/2847. It does not constitute legal advice. The CRA harmonized standards are still being developed by CEN/CENELEC; consult qualified legal counsel for definitive compliance guidance.",[21,11707,1489],{"id":1488},[86,11709,11710,11715,11720,11726],{},[91,11711,11712],{},[102,11713,1499],{"href":1496,"rel":11714},[1498],[91,11716,11717],{},[102,11718,11183],{"href":11181,"rel":11719},[1498],[91,11721,11722],{},[102,11723,11725],{"href":1504,"rel":11724},[1498],"CRA full text (HTML) — see Articles 2, 3, 13, 19, 20",[91,11727,11728],{},[102,11729,11176],{"href":11174,"rel":11730},[1498],{"title":1536,"searchDepth":1537,"depth":1537,"links":11732},[11733,11736,11743,11744,11749,11755,11756],{"id":11262,"depth":1537,"text":11263,"children":11734},[11735],{"id":11299,"depth":1542,"text":11300},{"id":11345,"depth":1537,"text":11346,"children":11737},[11738,11739,11740,11741,11742],{"id":11352,"depth":1542,"text":11353},{"id":11359,"depth":1542,"text":11360},{"id":11366,"depth":1542,"text":11367},{"id":11373,"depth":1542,"text":11374},{"id":11380,"depth":1542,"text":11381},{"id":11429,"depth":1537,"text":11430},{"id":11439,"depth":1537,"text":11440,"children":11745},[11746,11747,11748],{"id":11446,"depth":1542,"text":11447},{"id":11471,"depth":1542,"text":11472},{"id":11502,"depth":1542,"text":11503},{"id":11513,"depth":1537,"text":11514,"children":11750},[11751,11752,11753,11754],{"id":11520,"depth":1542,"text":11521},{"id":11554,"depth":1542,"text":11555},{"id":11579,"depth":1542,"text":11580},{"id":11603,"depth":1542,"text":11604},{"id":11636,"depth":1537,"text":11637},{"id":1488,"depth":1537,"text":1489},"2025-11-06","Does the EU Cyber Resilience Act apply to your embedded product? Decision framework for digital elements, offline devices, and OEM components.","/images/blog/previews/scope.svg",[11761,11762,11763,11274,11764,2225],"CRA scope","Cyber Resilience Act","embedded products","CRA Article 2",{},"/blog/is-your-product-in-cra-scope","9 min",{"title":11229,"description":11758},"blog/is-your-product-in-cra-scope","qa40OiDgjBjOgKidKuSK6OSPXP-deXs8Rh2pACAhZok",1775939691971]