Memory Safety Is Not a Silver Bullet: A Rational Look at New Vulnerabilities in Rewritten Components
When a system-level privilege escalation component rewritten in a memory-safe language disclosed two vulnerabilities, some coverage inflated them into "multiple critical flaws," sparking debate over whether memory safety is overrated. This article presents a practical method for independently judging vulnerability severity using CVSS scores, EPSS exploitation predictions, and known exploited vulnerability catalogs. It then examines the real security gains of rewriting legacy components—shrinking the attack surface, enforcing secure defaults, and eliminating entire bug classes—and clarifies where memory safety helps and where it cannot. It closes with four actionable recommendations for engineers on vulnerability triage, adopting rewritten components, and responsible security communication.
Background: A Security Debate Amplified by Headlines
A system-level privilege escalation component rewritten in a memory-safe language recently disclosed two vulnerabilities, yet some coverage condensed the story into “multiple critical vulnerabilities.” The community promptly erupted into arguments over whether “memory safety is overrated” and whether “rewriting actually makes things less secure.” Stripped down to the technical facts, the episode works better as a mirror on an industry weakness: many engineers are used to repeating conclusions but lack a method for independently judging how severe a vulnerability really is. This article first explains how to investigate a vulnerability on your own, then discusses what rewrites and memory safety genuinely deliver—and where their limits lie.
Assessing a Vulnerability on Your Own: Start with Three Quantitative Metrics
When news breaks that “a component has a critical vulnerability,” the right move is to verify, not to forward. Public vulnerability intelligence platforms typically provide the following for each entry:
1. CVSS score (0–10 scale)
This measures the theoretical worst-case impact, weighted across dimensions such as attack vector, attack complexity, required privileges, user interaction, scope, and damage to confidentiality, integrity, and availability. The industry-standard bands are 9.0–10.0 for “Critical” and 7.0–8.9 for “High.” Note what it answers: “how bad is it if exploited,” not “how likely is exploitation.”
2. EPSS exploitation prediction score (0–100%)
Produced by a model that factors in vulnerability characteristics, exposure, and the availability of exploit code, EPSS estimates the probability that a vulnerability will be exploited in the wild within the next 30 days. The vast majority of vulnerability entries sit in an extremely low band. The vulnerabilities disclosed in this incident carried exploitation probabilities on the order of one in ten thousand—among the least likely to ever be exploited.
3. Presence on known exploited vulnerability catalogs
Security agencies maintain catalogs of vulnerabilities that have already been used in real-world attacks. Inclusion in such a catalog is what signals active exploitation and maximum patch priority.
From these, a practical triage rule emerges: low CVSS + extremely low EPSS + absent from exploited catalogs ≈ limited theoretical risk and very low real-world risk. The two vulnerabilities in this incident fall squarely into that category. What does a genuine “red alert” look like? Browse the historical vulnerability record of the component’s traditional implementation and you will find entries that simultaneously score above 9 on CVSS, exceed 20% on EPSS, and appear on exploited catalogs. Between “having a vulnerability” and “having a critical vulnerability” lie several orders of magnitude.
One caveat: a low EPSS score does not license never patching—critical assets still deserve evaluation against their own exposure. But on the question of whether panic is warranted, quantitative metrics beat headlines every time.
The Real Value of a Rewrite: Far More Than Switching Languages
Sort the historical vulnerabilities of the old and new implementations side by side, and the payoff of the rewrite shows up on at least four levels.
1. Feature trimming equals attack surface reduction
A rewrite is an opportunity to re-examine requirements. Some historical features of the traditional implementation have been superseded by better solutions. The legacy isolation mechanism based on root directory switching, for instance, has had few remaining use cases since container-based isolation became widespread. The new implementation simply does not offer that capability, and an entire class of vulnerabilities vanishes at the root. Ironically, the traditional implementation itself only hurriedly removed that feature after it had already produced vulnerabilities.
This is the same principle behind a garbage collector cleaning up unreachable objects: engineering evolution also needs to sweep out “unreachable legacy features.” No feature means no defects from that feature—the most thorough fix there is.
2. Secure defaults beat after-the-fact patching
The new implementation clears dangerous environment variables by default and allocates a pseudo-terminal to sessions by default; those two default policies alone would have prevented multiple historical environment-injection and terminal-related vulnerabilities in the traditional implementation. The old implementation, saddled with heavy compatibility obligations, could only keep patching. Secure-by-default is a far cheaper defense than patches.
3. A classified inventory of historical vulnerabilities
Roughly classifying the component’s twenty-plus historical vulnerabilities makes it clearer why “the new implementation having vulnerabilities” is no surprise:
- Vulnerabilities tied to features that were never implemented or have been trimmed: the new implementation does not offer them, so it is naturally immune;
- Memory corruption: heap overflows, stack overflows, buffer overflows, double frees—eliminated outright at the language and compiler level by memory-safe languages;
- TOCTOU (time-of-check to time-of-use) races: such as a file being swapped after it has been verified—significantly mitigated through ownership management of resource objects and RAII-style lifecycle control;
- Configuration and environment issues: prevented by secure defaults.
4. Understanding language-level prevention through illustrative code
Under an ownership model, a double-free is rejected at compile time:
// Illustrative pseudocode: once ownership is transferred, the original handle becomes invalidhandle = open(path)handle2 = handle // Ownership is transferredrelease(handle) // Compile error: the resource has been moved; a double free cannot occur
The “resource swapped after verification” race can be narrowed by binding the verification result and the resource inside the same immutable object:
// Illustrative pseudocode: opening and verification complete together at constructionfile = open_and_verify(path)process(file.content()) // Later uses operate on the verified, immutable view
These snippets are illustrative, and real systems are far more complex—but the conclusion holds: good abstractions turn entire classes of bugs from “runtime incidents” into “compile-time errors,” or make them structurally impossible outright.
The Boundaries of Memory Safety: What It Prevents and What It Doesn’t
Multiple widely cited industry statistics indicate that a large share of historical critical vulnerabilities—commonly put at around 70%—originate in memory corruption. Memory-safe languages aim squarely at that 70%. The remaining 30%—logic errors, permission-check flaws, race conditions, configuration mistakes, supply-chain risks—remain beyond the reach of language-level guarantees.
The right conclusions from this incident, then, are not “memory safety has failed,” but three others:
- The vulnerability mix has shifted: once memory corruption is suppressed, what surfaces are logic and design problems. That is the normal sign of a defensive line advancing, not collapsing.
- Having vulnerabilities is not failure: any software complex enough will have vulnerabilities. What deserves comparison is vulnerability density, severity distribution, and response speed.
- “Over-reliance on memory safety breeds more vulnerabilities” is closer to a false proposition: the accurate framing is that memory safety changes the shape of the underwater iceberg as it surfaces—and recognizing it takes exactly the quantitative method described above.
Security has always been defense in depth: memory-safe languages eliminate a whole class of low-level yet fatal errors; secure defaults and least privilege compress the attack surface; sandboxing and isolation cap the blast radius; vulnerability intelligence and rapid response form the safety net. No single layer should be deified, and none should be unfairly blamed.
Four Practical Recommendations for Engineers
- Build a habit of reading vulnerability intelligence: when you see “critical vulnerability,” check the CVE identifier, CVSS, EPSS, whether it is being exploited in the wild, and the fixed versions—then decide your upgrade cadence.
- When evaluating whether to adopt a rewritten component, look past language features to whether the default configuration is secure, whether deprecated features were decisively cut, and how fast and transparent vulnerability response has been.
- For your own code: prefer memory-safe languages for new modules; enable compiler and runtime protections for existing systems (stack protection, address space layout randomization, and the like); periodically retire unused features and dependencies.
- For external communication: when writing or sharing security advisories, ground the message in quantitative metrics and skip rhetoric like “nuclear-grade” or “devastating”—it buys traffic, not security.
Conclusion
What deserves vigilance in this episode is not the fact that “the rewritten version has vulnerabilities too,” but that public judgment of vulnerability severity has long stayed at the headline level. Rewriting a foundational component in a memory-safe language is not a finish line; it is a chance to redesign: it eliminates a class of errors, trims a batch of outdated features, and uses default policies to close the pits the past kept falling into. As for the vulnerabilities that still appear, they are a reminder: software security has no graduation ceremony—only an ongoing process of measuring and improving.
