My Project Has 1,000 CVEs — What Now?
Running a security scan and seeing 1,000 CVEs in your project can feel like a nightmare. The number alone is enough to induce panic—but here’s the truth: In reality, this is a common situation and there are practical, structured ways to make sense of it and bring it under control.
In today’s fast-paced development environment, vulnerabilities are inevitable. Modern software relies on countless dependencies—each one a potential attack surface.
This guide outlines how to respond rationally and effectively when faced with a mountain of reported CVEs . While the recommendations are generally applicable to any embedded development stack, we’ll focus primarily on Linux-based systems built with the Yocto Project, as it’s a widely used and highly customizable environment for embedded development.
But What Are Actually CVEs?
CVEs—short for Common Vulnerabilities and Exposures—are standardized identifiers assigned to publicly known cybersecurity vulnerabilities in software or firmware. Each CVE entry describes a specific issue, such as a potential buffer overflow, information leak, or privilege escalation, along with references to public resources, severity scores, and potential mitigations.
For example:
CVE-2024-12345 might refer to a specific version of
libxml2
that allows random code execution under certain conditions that may be listed in the CVE descritpion.
The catalog of CVEs is managed and published by the MITRE organization, in coordination with the NVD (National Vulnerability Database), software vendors, and researchers.
But CVEs don’t apply in a vacuum. Just because a vulnerability exists doesn’t mean your system is affected in practice—it depends on your usage context, configuration, and exposure.
How CVEs Are Identified in Embedded Projects
In the world of embedded Linux, tools have emerged to help detect known vulnerabilities during the development cycle. If you’re using Yocto, one of the most powerful tools at your disposal is the built-in cve-check
class.
When you enable cve-check
in your Yocto build configuration, here’s what happens behind the scenes:
Software Inventory: During each build, Yocto collects metadata on all software components included in your image, including their precise versions and source URLs.
Database Query: It then queries one or more public CVE databases to check whether any CVEs are associated with those specific versions. Common data sources include:
The NVD (National Vulnerability Database), maintained by the NIST
Report Generation: A report is produced, usually in both machine-readable and human-readable formats, listing all CVEs found, their severity scores (e.g., CVSS), descriptions, and links to more information.
It’s not unusual for this report to list hundreds—or even thousands—of CVEs. Why?
Because the database contains every known vulnerability for each version of each package, and many of them may not be relevant to your usage. Some may already be patched in a newer upstream version, some may not be triggered unless the software is misconfigured, and others might simply not be used at runtime.
Why Your CVE Count Might Be Lying to You
Here’s something crucial to understand right away:
The tools reporting CVEs usually work purely on metadata: basically the name and version of a package.
They do not analyze how that software is configured, compiled, or actually used in your project.
This distinction is key to demystifying those overwhelming numbers.
Let’s take a common example from embedded Linux: your project includes Linux kernel version 5.10. The CVE scanner will flag every known vulnerability associated with that version—regardless of whether the affected code is even present in your build. There are 3,333 of them at the moment of this writing.
Say one CVE concerns a FireWire stack vulnerability. If your kernel configuration has CONFIG_FIREWIRE=n
, then the relevant code isn’t compiled in. That CVE? Not applicable. CVE count: minus one, at least in your own mental model.
But here’s the catch: the tool may still report it. Disabling features won’t usually make your CVE report any shorter, while removing packages will. Housekeeping doesn’t always reduce the reported number—it just makes many of those CVEs irrelevant to your specific system.
This is where disciplined configuration pays off. When you minimize what’s included in your image:
You reduce your actual attack surface.
You shrink the subset of CVEs you need to analyze.
You gain clarity: what remains is more likely to matter.
In practice, this can be dramatic. The Linux kernel is often the largest single contributor to the CVE count in an embedded project. But that count includes vulnerabilities from all subsystems and drivers, most of which are unused in a typical configuration. By comparing CVEs against your actual .config
, the number of vulnerabilities that truly need investigation can drop by 80–90%.
So do your housekeeping:
Prune unneeded kernel options.
Minimize your userland packages.
Disable unused features at every level.
But remember: this won’t necessarily reduce the number in the report dramatically. What it gives you is the ability to say, with justification: “Out of 1000 CVEs, these 800 don’t apply to my system.”
But How Do You Know Which Ones Apply?
That’s the next step: triage. Once you’ve stripped your system down to what you really need, it’s time to examine the CVE list with a critical eye and determine which issues are:
Clearly irrelevant
Technically present but non-exploitable
Legitimate risks requiring an update or a patch
We’ll walk through that process in the next section.
Triage: Sorting Out What Really Matters
Now that you’ve done your housekeeping and cut away the cruft, it’s time to face what remains: the list of reported CVEs. This is where triage begins—the process of evaluating each vulnerability and deciding whether it’s relevant, and if so, how urgent it is.
Triage is not just about technical analysis. It’s also about traceability and accountability. Every CVE must end up in one of two buckets:
Action Required: This CVE affects your actual system and needs to be fixed, mitigated, or worked around.
Irrelevant: This CVE is not applicable due to configuration, usage, or system architecture.
Here’s how to proceed.
Step 1: Identify the Component and Context
For each CVE:
What component does it affect?
What version is the CVE known to impact?
Is the affected feature compiled in and enabled in your build?
Is the component accessible or used in a way that makes the issue exploitable?
For example:
If a CVE affects the Bluetooth stack but your kernel is built with
CONFIG_BT=n
, it’s irrelevant.If a flaw is found in a web interface your system doesn’t deploy or expose, same conclusion.
Step 2: Document Your Decision
This step is critical: even if a CVE is determined to be irrelevant, that conclusion must be recorded and justified. Don’t just ignore it—prove it was reviewed.
You should maintain a CVE whitelist—a structured file (CSV, YAML, JSON, etc.) where you track:
CVE ID
Component name and version
Date of review
Decision (e.g., “Not applicable: feature disabled in config”)
Reviewer identity (optional but good practice)
Reference to configuration evidence or usage constraints
This whitelist becomes part of your project’s quality records. It shows that nothing was ignored or missed—it was all triaged.
Step 3: Focus on the Actionable Set
Once triage is complete, you’ll have a much shorter list: CVEs that are relevant and need action. These are the ones that should:
Be shown in your final security report
Trigger patching, package upgrades, or mitigations
Be tracked through your issue or defect management system
This refined list is no longer overwhelming. It’s real, manageable, and actionable. You’ve gone from 1000+ abstract warnings to a concrete set of security tasks backed by engineering judgment.
But How Do You Audit 1000 CVEs?
Let’s be realistic: manually reading and analyzing a thousand CVEs isn’t feasible in the context of a commercial project. But neither is relying blindly on a report generator. What you need is triage—real decision-making—at scale. That means using tools that help you do more than count vulnerabilities. You need tools that help you filter, classify, and justify each item, one by one.
Triage Is Not Reporting
Many CVE scanners are great at collecting data. But triage is a different task. It involves:
Understanding what each CVE actually affects
Matching it against your build configuration
Making a clear decision: does this apply or not?
Recording that decision in a traceable way
Tools like:
Yocto’s
cve-check
(paired with external tools)cve-bin-tool
Google’s OSV-Scanner
…can assist with portions of this process. But here’s the hard truth: No tool covers all cases.
The CVE descriptions are written by humans, often without consistent editorial standards. Some are precise and insightful; others are vague or lack context entirely. For example, they don’t always say:
Which kernel options or library features must be enabled for the vulnerability to apply
Whether the attack surface is local, remote, or theoretical
What mitigations might already be in place in your stack
So what do you do? You combine multiple tools—each giving you part of the puzzle—and fill the gaps with manual analysis. That’s where experience and expertise makes the difference.
What We Do at Embedded Expertise
At Embedded Expertise, we’ve developed a toolbox to accelerate and document CVE triage for embedded projects. But let’s be clear: there’s no silver bullet.
Our approach isn’t one polished product. It’s a tailored blend of scripts, lookups, and AI-driven summaries—adapted to each project’s structure and technology stack. For every customer, we tune:
Which APIs we query
How we match packages and configs
What decision logic is automated vs. manual
These tools help reduce triage time by an order of magnitude—but they still require engineering judgment.
In the end, it’s always a mix: tools to crunch the data, and people to make the call.
The result is not just a shorter list of CVEs, but a documented decision history showing which CVEs were reviewed, which were ignored (with justification), and which require real action.
What to Do with Actionable CVEs
After your configuration has been stripped down and a proper triage is complete, you’re left with a focused list of actionable CVEs—the ones that genuinely affect your system. These must now be dealt with methodically. Depending on the specifics of the CVE, there are several paths that can be followed.
Option 1: Update
The most straightforward way to fix a CVE is to update the affected component to a version where the vulnerability has been resolved. If the fix exists upstream, and you’re not locked into a specific version, this is usually your best starting point.
However, in embedded development—especially in mature or long-maintenance-cycle projects—you almost never want to blindly update to the latest version. That path often leads to:
Functional regressions
API incompatibilities
Broken builds due to dependency mismatches
➤ Be Smart: Stick to Patch-Level Updates When Possible
Most versioning schemes follow the MAJOR.MINOR.PATCH
format. Here’s what that means for you:
MAJOR version bumps may break compatibility and require significant rework.
MINOR versions add features but can still introduce subtle changes.
PATCH versions are typically safe—they’re supposed to include only bug and security fixes.
So if your system is using version 2.14.3
and a CVE is fixed in 2.14.7
, the safest and smartest choice is to update to that patch release, staying within the same MAJOR.MINOR line. This approach balances security with stability.
➤ But Never Skip the Tests
Even patch-level updates can cause side effects. That’s why every version change must be verified, ideally through automated testing. This is yet another reason to invest in a complete and fluent CI/CD and IVVQ flow.
A strong automated pipeline will:
Rebuild your image after any dependency change
Run functional, regression, and integration tests automatically
Catch side effects early, before they reach the field
Without this safety net, even the smallest update can be a risk. With it, you gain the confidence to stay secure without constantly firefighting regressions.
Option 2: Patch
If updating isn’t feasible—due to project constraints, integration risks, or regulatory certification—you can either look for an existing patch, or backport the upstream fix into your current version.
This is common in long-lived embedded platforms. The process:
Identify the upstream commit that fixes the CVE
Extract the relevant patch
Apply it via a
.bbappend
file in YoctoDocument it with references to the CVE ID and upstream source
Patching takes more effort than updating but allows you to stay secure while maintaining stability.
Option 3: Mitigate
In some cases, the vulnerable code needs to stay—but the risk can be contained through runtime constraints or system design.
Examples:
Disable the service or interface exposing the vulnerability
Restrict network access to the component
Use seccomp, SELinux, or AppArmor to limit its capabilities
Mitigations are valid, but they must be documented and maintained. A mitigation that silently breaks under future changes isn’t a mitigation at all.
Option 4: Justify and Accept (With Care)
Some vulnerabilities may remain unpatched—deliberately—because they pose no real risk in your context.
Examples:
A local DoS in a service that is never installed
A flaw in a media parser that’s not included in your build
A vulnerability in an internal-only tool never exposed to users
In these cases, it’s acceptable to whitelist the CVE—but only with a documented justification. This includes:
The CVE ID
Your rationale
References to your system’s configuration or usage
This shows auditors (and future you) that the decision was deliberate, not negligent.
The Goal: Zero Unhandled CVEs
At the end of this process, there should be no unexplained CVEs left in your reports.
Every reported CVE must fall into one of three categories:
Whitelisted – Verified as irrelevant to your system
Fixed – Patched, updated, or mitigated
Justified – Risk accepted with clear rationale
Achieving this clean state is essential. It means:
Your team is not flooded by a hundred irrelevant warnings every build
The truly important vulnerabilities stand out at the moment they show up
Your development process is secure, auditable, and professional
Bonus benefit: zero unhandled CVEs is not just a security goal—it’s a productivity goal.
Staying Clean: Long-Term CVE Hygiene
Fixing CVEs once is good. Staying on top of them continuously is better.
Security isn’t a one-time task—it’s a process. The sooner your team integrates vulnerability tracking into its normal development lifecycle, the less disruptive it becomes over time. Here’s how to make CVE management a seamless part of your workflow.
Integrate CVE Checks into Your CI Pipeline
As discussed earlier, a clean CVE report doesn’t mean zero vulnerabilities—it means zero unhandled vulnerabilities.
Track your triaged CVEs in a versioned, human-readable whitelist file:
Clearly mark which CVEs are irrelevant, patched, or justified
Store the whitelist alongside your code (e.g., in your Git repo)
Update it as your system evolves or dependencies are upgraded
This ensures traceability, audit readiness, and peace of mind.
Schedule Periodic Re-Audits
Some CVEs may not apply today—but if your configuration or threat model changes, they might become relevant later.
Schedule regular reviews of:
Your whitelist (are the justifications still valid?)
Your kernel/userland configurations (any new features enabled?)
Vulnerability databases (new CVEs for your existing versions?)
Security is never static. Treat it like a maintenance task, not a fire drill.
Automate Where Possible, Review Where Needed
Automation is your best ally for:
Fetching CVE data
Matching it to components
Generating reports and diffs
Populating baseline triage records
But tools alone aren’t enough. As discussed earlier, no tool understands your exact configuration, threat model, or deployment context. You’ll always need human judgment to make the final call.
At Embedded Expertise, we use a combination of scripted triage tools and hands-on analysis to keep our clients’ projects clean, secure, and audit-ready. Every system is different, and there’s no “one-size-fits-all” solution—but a disciplined approach always works.
A Word of Caution: CVEs Only Show Part of the Picture
It’s worth repeating: a clean CVE report is not a guarantee of system security. It simply means that—as far as known, published vulnerabilities go—you’ve handled everything that’s been documented.
But CVE-based tooling only sees the tip of the iceberg. It does not detect:
Zero-days — vulnerabilities that are not yet discovered or disclosed
Bugs in closed-source software, including:
Proprietary third-party libraries
Firmware blobs
Driver stacks or middleware delivered as binaries
Vulnerabilities in your own code, unless you’ve published them and assigned CVEs (which is rare for internal projects)
This means CVE handling is just one part of a full security strategy. To go further, you need:
Static analysis to catch bugs in your own code
Fuzzing and penetration testing to discover edge cases and exploit paths
Security reviews focused on your architecture, interfaces, and threat model
Hardening measures like sandboxing, least privilege, and secure defaults
CVEs are a useful mirror—but you still need to check the blind spots.
Key Takeaways
A thousand CVEs is not a crisis—it’s a wake-up call. It means your system is composed of real software, used in the real world, where vulnerabilities happen. The key is to cut through the noise, identify the real risks, and deal with them methodically.
By:
Stripping unneeded features,
Triage-auditing every CVE,
Fixing what matters and documenting the rest,
And maintaining a clean report at every stage of your development flow,
…you turn security from a source of fear into just another aspect of solid engineering.
The goal is not perfection. The goal is confidence.
Confidence that every CVE has been seen, understood, and handled.
Bonus: Download the CVE Workflow Cheat Sheet
Want a printable one-page summary of everything covered in this article?
👉 Download the CVE Processing Workflow Cheat Sheet (PDF)
Use it to guide your triage process, build your whitelist, and train your team.
