How Memory Safety CVEs Differ Between Rust and C/C++
Why do we keep measuring language security by CVE count when we know that number depends as much on installed base size as on any actual property of the language? It took years of debate and a couple of NSA and CISA papers for the ecosystem to take the question seriously — and even then, the answer circulating in most threads is too simple to be useful.
Here's my thesis: the difference in memory safety CVEs between Rust and C/C++ is real, documentable, and technically interesting. But turning it into "migrate everything to Rust" or "the borrow checker solves it all" is a category error. The useful data isn't in the headline — it's in which vulnerabilities disappear, which ones persist, and under what conditions Rust's security model has its own friction.
The real problem: not all memory CVEs are the same
When CISA, NSA, or the White House Office of the National Cyber Director publish reports recommending memory-safe languages (and they did, publicly, between 2022 and 2023), the category they're targeting is specific: vulnerabilities caused by undefined behavior in manual memory management. Use-after-free, buffer overflow, double-free, unchecked null pointer dereference — the classic C/C++ family.
The technical distinction matters:
| Vulnerability class | C/C++ | Rust (safe) | Rust (unsafe) |
|---|---|---|---|
| Use-after-free | Common | Impossible by design | Possible |
| Buffer overflow (stack/heap) | Common | Impossible by design | Possible |
| Data race in multithreading | Common | Impossible by design | Possible |
| Integer overflow | Possible | Debug: panic / Release: wrapping | Same |
| Logic bugs | Always possible | Always possible | Always possible |
| Misused unsafe block | N/A | Possible | Possible |
This table isn't a production benchmark — it's a map of what guarantees the Rust compiler gives you in safe code vs. what falls outside those guarantees. This isn't my own claim: the ownership model and borrow checker rules are formally described in repository on GitHub maintains security advisories for the Rust ecosystem. It's auditable, has categories by vulnerability type and date. You can run:
# Install cargo-audit if you don't have it
cargo install cargo-audit
# Audit dependencies of any Rust project
cargo audit
# View active advisories with detail
cargo audit --json | jq '.vulnerabilities.list[] | {id: .advisory.id, title: .advisory.title, categories: .advisory.categories}'
The output tells you not just whether there are known vulnerabilities, but what category they fall into. That data is concrete and reproducible on any machine.
2. CVE Details / NVD by CWE
The NVD (National Vulnerability Database) categorizes CVEs by CWE (Common Weakness Enumeration). CWE-119 (buffer errors), CWE-416 (use-after-free), and CWE-476 (null pointer dereference) are the categories that concentrate the bulk of historical CVEs in C/C++ projects. You can filter by language and year at .
Decision matrix: when this data changes something and when it doesn't
Before using the CVE comparison as a technical argument, run it through this checklist:
CHECKLIST: Is the Rust vs C/C++ CVE data relevant to my decision?
[ ] Does the system I'm evaluating have C/C++ with manual memory management?
→ If not, the comparison is irrelevant to you.
[ ] Is the primary attack surface memory vulnerabilities (UAF, overflow)?
→ If the dominant risk is business logic or authentication, Rust doesn't change that.
[ ] Do I have the capacity to review unsafe blocks in critical dependencies?
→ If not, the gain shrinks: you're importing opaque risk just like in C.
[ ] Does the project use extensive FFI with C?
→ The borrow checker's benefit is scoped to the safe portion of the code.
[ ] Am I evaluating new code vs. migrating existing code?
→ Migrating a large C/C++ codebase has real rewrite costs and a coexistence period.
→ New code in Rust on a well-scoped domain: the benefit is immediate and verifiable.
[ ] Does the team have experience with the ownership model?
→ The borrow checker learning curve is real. A team without Rust experience
can introduce more bugs during the transition than it avoids in the medium term.
For projects where the domain is low-level computation, parsing untrusted binary formats, system daemons, or network components with high exposure, the argument for Rust is solid and backed by public evidence. For a business backend in TypeScript or Java where the dominant risk is injection, poorly implemented authentication, or broken permissions logic, the memory safety debate is almost a distraction.
This connects to something that also applies to the , and believing a tool holistically solves security is the most elegant way to drop your guard exactly where it matters most.
This article was originally published on juanchi.dev
SOCIAL SHARE CARD GENERATOR