The Chromium security team went back through 912 high-severity and critical security bugs found in the browser’s stable channel since 2015 and sorted them by root cause. Around 70% came down to a single category: mistakes handling memory in C and C++. Roughly half of those were one specific bug type, use-after-free. That analysis is still published on chromium.org, and the number has become one of the most-cited figures in software security.
Microsoft found almost exactly the same thing. In a 2019 post from the Microsoft Security Response Center titled “We need a safer systems programming language”, the company said roughly 70% of the vulnerabilities it patches and assigns a CVE to each year are memory safety issues, and that the proportion had barely moved in over a decade despite code review, training and static analysis.
Two of the largest engineering organizations on earth, working on completely different codebases, landed on the same number. That coincidence is why “memory safety” stopped being a niche compiler-theory topic and turned into the subject of joint advisories from the NSA, CISA and the FBI, a White House technical report, and a genuine shift in what languages new systems software gets written in.
What a memory safety bug actually is
C and C++ let a program hold a raw pointer, which is just a number that says “the data is at this address.” The language does not check, at runtime, whether that address still contains what you think it does, or whether you are allowed to read the byte you just asked for. Speed comes from skipping those checks. So do the bugs.
Buffer overflow
You allocate room for 64 bytes and write 80. The extra 16 bytes land in whatever memory sits next door: another variable, a length field, a saved return address. In the benign case the program crashes. In the exploitable case an attacker who controls the input controls what gets overwritten, and can steer execution somewhere of their choosing. Out-of-bounds reads are the same mistake in the other direction, and they leak data. Heartbleed, the 2014 OpenSSL flaw that exposed server memory to anyone who asked, was an out-of-bounds read.
Use-after-free
Memory is released back to the allocator, but some other part of the program still holds a pointer to it. Later, the allocator hands that same block to something else. Now two pieces of code disagree about what lives at that address. An attacker who can influence what gets allocated into the freed slot can often turn “stale pointer” into “I choose what this pointer points at.” This is the workhorse of browser exploitation, which is exactly why it dominates the Chromium numbers.
The rest of the family
- Double free — releasing the same block twice, corrupting the allocator’s bookkeeping.
- Null pointer dereference — usually a crash rather than a takeover, but a denial of service all the same.
- Type confusion — memory holding one kind of object gets interpreted as another kind.
- Uninitialized memory — reading a variable before anything was written to it, exposing whatever the previous occupant left behind.
What unites them is that the language will happily compile all of these. There is no diagnostic, because in C’s model you are assumed to know what you are doing.
How reliable is the 70% figure?
Reasonably, with caveats worth stating. The Microsoft and Chromium figures are internal analyzes of their own bug trackers, not peer-reviewed research, and both count only bugs serious enough to be triaged as security issues. A June 2025 joint information sheet from the NSA and CISA, Memory Safe Languages: Reducing Vulnerabilities in Modern Software Development, gathers the comparable numbers from elsewhere: a 2019 analysis attributing 66% of iOS 12 CVEs and 71% of macOS Mojave CVEs to memory safety, and a Google Project Zero estimate that around 75% of exploits observed being used in the wild relied on memory safety flaws.
Two honest qualifications. First, the ratio is a share, not a count — if a project fixes a lot of memory bugs, the percentage falls even if the absolute number of other bug classes stays flat. Second, that same NSA/CISA sheet notes Microsoft’s share has come down from the near-70% peak toward roughly half as mitigations landed. The category is shrinking. It has not disappeared.
Rust’s answer: the compiler tracks who owns what
Rust’s core idea is that every value has exactly one owner, and when the owner goes out of scope the value is freed. No garbage collector decides this at runtime; the compiler works it out at compile time and inserts the cleanup itself. That alone kills double frees and most leaks.
The harder problem is sharing. Rust handles it with borrowing: you can hand out a reference to a value without transferring ownership, under one rule that the borrow checker enforces. At any given moment you may have either any number of read-only references, or exactly one mutable reference — never both. Try to modify a vector while something else is iterating over it and the program does not compile.
That single rule is doing a lot of work. It rules out use-after-free, because a reference cannot outlive the value it points into. It rules out iterator invalidation. And because two threads cannot both hold mutable access to the same data, it rules out data races too, which is why Rust marketing talks about “fearless concurrency.”
The escape hatch is the unsafe keyword. Inside an unsafe block you can dereference raw pointers and call foreign code, and the guarantees are yours to uphold. This matters for honesty: Rust does not eliminate memory bugs, it confines them to blocks you can grep for, audit closely, and keep small. Every operating system kernel and every C library binding has some.
Go’s different bargain
Go reaches memory safety by a much older route: a garbage collector. Nothing is manually freed, bounds are checked at runtime, and pointer arithmetic is not part of the language. There is no borrow checker to argue with, and the learning curve is famously short — most working developers are productive in Go within a week.
What you pay is a runtime. Every Go binary ships a garbage collector and scheduler, memory usage is higher than an equivalent Rust or C program, and collection introduces pauses. Go’s collector is concurrent and its pause times are typically well under a millisecond, which is fine for network services and unacceptable for a kernel driver, an audio callback, or a microcontroller with 64KB of RAM. That is the actual dividing line between the two languages, far more than performance benchmarks.
One caveat that gets glossed over: Go is memory safe only for race-free programs. Go’s own memory model documentation is explicit that races on multiword values — interfaces, slices, strings, maps — can produce a mismatched pointer/length or pointer/type pair, and that this can lead to arbitrary memory corruption. Russ Cox’s write-up of the Go memory model states it plainly. Go’s design accepts this as the price of not having a borrow checker. Rust’s design does not.
Comparing the approaches
| Property | C / C++ | Rust | Go |
|---|---|---|---|
| Memory freed by | You, manually | Compiler, at scope exit | Garbage collector |
| Use-after-free possible | Yes | Only in unsafe | No |
| Bounds checked | No | Yes (elided when provable) | Yes |
| Data races prevented | No | Yes, by the type system | No — detected, not prevented |
| Runtime required | None | Minimal | GC and scheduler |
| Suits kernels, firmware, embedded | Yes | Yes | Rarely |
| Time to productivity | Long | Long | Short |
Neither Java, C#, Python, Swift nor Ruby is missing from this argument by accident — all of them are memory safe, and the NSA/CISA sheet lists them alongside Rust and Go. The reason Rust gets the attention is that it is the first widely used memory-safe language that can plausibly replace C in the places C is genuinely hard to displace.
Why governments started publishing about compilers
In December 2023, CISA, the NSA, the FBI and cybersecurity agencies from Australia, Canada, the UK and New Zealand jointly published The Case for Memory Safe Roadmaps, asking software manufacturers to publish concrete plans for moving to memory-safe languages rather than treating the issue as a research topic.
In February 2024 the White House Office of the National Cyber Director followed with Back to the Building Blocks: A Path Toward Secure and Measurable Software, which named C and C++ as the problem and Rust as one example of a viable replacement, while recommending a risk-ranked approach rather than blanket rewrites. The June 2025 NSA/CISA sheet is the most recent entry and takes the same line.
None of these documents is binding regulation. What they change is procurement conversations and board-level risk registers, which is often enough.
Where this has actually shipped
Rust support landed in the Linux kernel in version 6.1, released in December 2022, carrying an explicit “experimental” label. On 12 December 2025, kernel maintainer Miguel Ojeda posted a patch titled “rust: conclude the Rust experiment”, deleting that caveat from the documentation after the 2025 Kernel Maintainers Summit. His summary was blunt: the experiment is done, Rust is here to stay. The patch also notes plenty of unfinished work, particularly around mixed GCC and LLVM builds.
Android is the strongest available evidence that the approach works at scale. Google’s security blog reported that the share of Android vulnerabilities caused by memory safety fell from 76% in 2019 to 24% in 2024, and in a November 2025 post Google said it dropped below 20% for the first time. The same post put Rust’s memory-safety vulnerability density at roughly 0.2 per million lines of code against roughly 1,000 per million for Android’s C and C++ — a thousandfold difference — while reporting that Rust changes were rolled back about four times less often than comparable C++ changes and spent around 25% less time in code review.
Microsoft has moved more quietly. At BlueHat IL in April 2023, Windows security lead David Weston described roughly 36,000 lines of Rust in the Win32 graphics device interface and a Windows kernel system call implemented in Rust, as reported by The Register.
The part the advocacy usually skips
Rewriting working software is one of the most reliably expensive things an engineering organization can do, and memory safety does not suspend that rule. A rewrite reintroduces every logic bug the original spent a decade shaking out, and logic bugs are not the class Rust protects you from.
The tooling costs are real too. The Rust compiler performance survey published in September 2025 drew more than 3,700 responses and found 55% waiting over ten seconds for an incremental rebuild, and 45% of people who had stopped using Rust citing compile times as one reason. The 2025 State of Rust survey results, published in March 2026 with 7,156 completed responses, again put build times and language complexity near the top of the complaint list.
Hiring is a constraint as well. In the 2025 Stack Overflow Developer Survey, 14.8% of respondents reported extensive work in Rust and 16.4% in Go, against far larger pools for JavaScript, Python and Java. Rust also topped the “most admired” list at 72.4% for the tenth consecutive year, which tells you people who use it want to keep using it — not that they are easy to find.
The most useful counter-argument to rewriting comes from Google itself. Its September 2024 post Eliminating Memory Safety Vulnerabilities at the Source argues that vulnerability density decays over time in code that is not being modified, so writing only new code in a safe language drives the overall share down without touching the old code at all. Google states directly that existing memory-unsafe code does not need to be thrown away or rewritten, and that interoperability between safe and unsafe languages is the higher-value investment.
What this means for you
- Starting something new that parses untrusted input? Choose a memory-safe language. Parsers, decoders, and network protocol handlers are where these bugs concentrate.
- Picking between Rust and Go? Ask whether you can tolerate a garbage collector. If yes, Go will get you shipping sooner. If no — kernel, driver, embedded, hard real-time, or a library other languages will link against — Rust is the realistic option.
- Maintaining a large C or C++ codebase? Do not open with a rewrite proposal. Write new modules in a safe language, put safe wrappers around the riskiest parsing code, and turn on the mitigations you already have: sanitizers in CI, fuzzing, hardened allocators, and modern C++ containers instead of raw arrays.
- Buying software? Ask vendors whether they have a memory safe roadmap. The joint advisories exist precisely to make that a normal question.
- Learning Rust? Budget weeks, not days, and expect to fight the borrow checker before it starts feeling like help.
Frequently asked questions
Does Rust make software secure?
No. It removes one large category of bug. SQL injection, broken authentication, logic errors, misconfigured permissions and supply-chain compromise are all untouched by the borrow checker.
Is C++ hopeless here?
No, but its safety features are opt-in and its guarantees are weaker. Smart pointers, std::span, bounds-checked containers, AddressSanitizer and hardened standard library modes all help substantially. The C++ committee has ongoing safety profile work, though nothing yet that matches a borrow checker’s compile-time guarantee.
Is Go slower than Rust?
Usually somewhat, and more variable because of garbage collection pauses. For most network services the difference does not determine the outcome; developer throughput and operational simplicity often matter more.
Is any of this legally required?
Not in the US or Canada as of mid-2026. The CISA, ONCD and NSA documents are guidance. They increasingly show up in procurement questionnaires and security reviews, which gives them practical weight without regulatory force.
What about all the unsafe code in Rust libraries?
It is a genuine concern and the ecosystem treats it as one — tools like Miri and cargo-geiger exist to find and audit it. The argument in Rust’s favor is not zero unsafe code, it is that the unsafe surface is small, marked, and reviewable rather than spread across every line.
Where the argument stands in late 2026
The interesting debate is no longer whether memory-safe languages reduce vulnerabilities. Android’s numbers, the kernel dropping its experimental label, and three separate government advisories have effectively settled that. The open questions are about sequencing and cost: which code to move first, how to make Rust and C++ talk to each other without reintroducing the bugs at the boundary, and whether organizations can absorb the training and build-time costs while shipping.
Google’s decaying-vulnerability argument is the most practically important idea in the whole discussion, because it means the payoff does not require a rewrite. Write the new code safely, leave the old code alone unless it is genuinely high risk, and the graph bends anyway. That is a strategy a normal engineering team can actually execute.
Sources
- The Chromium Projects — Memory safety
- Microsoft Security Response Center — We need a safer systems programming language
- NSA and CISA — Memory Safe Languages: Reducing Vulnerabilities in Modern Software Development (June 2025)
- CISA — The Case for Memory Safe Roadmaps
- Office of the National Cyber Director — Back to the Building Blocks: A Path Toward Secure and Measurable Software
- Google — Rust in Android: move fast and fix things
- Google Online Security Blog — Eliminating Memory Safety Vulnerabilities at the Source
- Linux Kernel Mailing List — rust: conclude the Rust experiment
- Russ Cox — Updating the Go Memory Model
- Rust Blog — Rust compiler performance survey 2025 results
- Rust Blog — 2025 State of Rust Survey Results
- Stack Overflow — 2025 Developer Survey: Technology
- The Register — Microsoft is busy rewriting core Windows code in Rust
Image credit: Photo: Martin Vorel — CC BY-SA 4.0 (via Wikimedia Commons)
