Embedded Linux & Systems Engineering
Yocto Security & CRA Compliance Checklist
What to verify in a Yocto build before it ships as a regulated product.
33 checks across 7 sections · free PDF, no email
The EU Cyber Resilience Act treats an unpatched embedded Linux image as a defect in the product, not a detail of the build. This checklist is what to verify in a Yocto build before it ships.
It assumes you already have a build that boots. Nothing here is about getting Yocto working — it is about the gap between "the image boots" and "the image is defensible."
Work through it once per release candidate, not once per project. The answers change every time a layer moves.
1. Bill of materials
-
create-spdx(orcreate-spdx-2.2) is inINHERIT, and the SPDX output lands intmp/deploy/spdx/on every image build - The SBOM is archived as a release artefact alongside the image, not left in
tmp/ - Every recipe in the image resolves to a real
LICENSEfield — noCLOSEDplaceholders on third-party code -
INCOMPATIBLE_LICENSEis set for the licences your legal position forbids, so a GPL-3.0 recipe fails the build rather than shipping - The SBOM lists the kernel and bootloader, not only userspace packages
2. Known vulnerabilities
-
cve-checkis inINHERITand the build emits a CVE report per image - The CVE database is refreshed in CI rather than reused from a stale download cache (
DL_DIR/CVE_CHECK) - Every unpatched CVE above your severity threshold has a written disposition: patched, not applicable, or accepted with a reason
-
CVE_STATUSentries carry a justification string, so an ignored CVE explains itself to an auditor - A CVE report regression fails the pipeline instead of being reviewed by hand
3. Attack surface
- The image is built from a minimal base, not
core-image-full-cmdlineor a vendor demo image -
IMAGE_FEATUREScontains nodebug-tweaks,tools-debug,dbg-pkgs, orempty-root-passwordin production - The serial console is disabled, or gated behind authentication, in production images
- No development SSH keys,
.netrc, build-host paths, or CI tokens survive into the rootfs - The package list has been read end to end at least once — every package is there because something needs it
4. Kernel and boot
- The kernel
defconfigis under version control in your own layer, not inherited unseen from the BSP - Secure boot is enabled and the chain terminates in a key you control, not a vendor test key
- The kernel and bootloader track a maintained upstream branch with a known patch cadence, and the recipe pins
SRCREVto a specific commit on it -
PREEMPT_RTis applied only where a control loop needs it, and the resulting latency has been measured rather than assumed - Boot time is measured on the production image, so a regression shows up before a customer finds it
5. Root filesystem integrity
- The root filesystem is read-only, with writable state confined to a named overlay or data partition
-
dm-verityor an equivalent protects the root filesystem from offline modification - Persistent secrets live in encrypted storage (LUKS, or the SoC's secure element), never in the image
- Log and cache directories are on a volume that can fill up without bricking the device
6. Updates in the field
- An A/B or dual-bank update mechanism is in place — RAUC, Mender, or swupdate — with a proven rollback
- Update artefacts are signed, and the device verifies the signature before applying
- Rollback has been exercised on real hardware, including a power cut mid-write
- There is a documented path from "CVE published" to "fleet updated," with an owner and a target window
- The device reports its running image version somewhere you can query across the fleet
7. Reproducibility
- Every layer is pinned to a commit SHA in the manifest, not to a branch name
- A clean build from a fresh sstate cache produces the same image the release did
- The build runs in a container with a pinned base, so the host toolchain is not part of the result
- The exact build inputs — manifest, local.conf, layer SHAs — are archived with the release artefact
Where this usually goes wrong
Three items on this list account for most of the failures we see.
cve-check enabled but never read. The report generates, nobody owns it, and the count climbs release over release. A report without a disposition step is decoration.
Layers pinned to branches. The build is reproducible until the day it is not, and the day it is not is usually the day you need to rebuild a shipped release to patch it.
Rollback never tested. Signed updates and A/B partitions are straightforward to configure and easy to get subtly wrong. The first real test should not be a field failure.
When this needs outside help
Most teams can work through this list themselves. It is worth bringing in help when the answers are expensive rather than unknown:
- The BSP is a vendor drop with no upstream, so pinning and patching mean taking on maintenance of a kernel fork
- You need a CRA conformity argument, not just a clean CVE report, and someone has to write the technical documentation an assessor will read
- Boot time or latency targets are not being met and the fix requires kernel and device-tree work rather than configuration
If any of those describe where you are, we do this work: contact@mnpsystems.ca.
Go deeper
Production Yocto Cookbook
Recipes for taking a Yocto build from boots-on-the-bench to shippable under the CRA.
- A layer of your own
- Signed A/B updates
- Cutting boot time