Key Takeaways

- 44 CVEs were found in uutils, the Rust reimplementation of GNU coreutils shipping in Ubuntu
- Time-of-check to time-of-use (TOCTOU) race conditions formed the largest cluster of bugs
- Rust's standard library APIs make path resolution vulnerabilities easy to introduce
In April 2026, Canonical disclosed 44 CVEs in uutils, the Rust reimplementation of GNU coreutils that ships by default in Ubuntu 25.10. The vulnerabilities came from an external audit commissioned ahead of the 26.04 LTS release. Every single one of them landed in production code written by experienced Rust developers. None were caught by the borrow checker, clippy lints, or cargo audit.
Matthias Endler, who analyzed the audit results, writes that this is the most concentrated look at where Rust's safety ends that you'll find anywhere right now. The uutils team shared their audit results in detail, giving the community a rare chance to learn from real production bugs.
The Core Problem: Path Resolution Between Syscalls
The largest cluster of bugs in the audit follows one pattern. You make a syscall to check something about a file path. Then you make another syscall to act on that path. Between those two calls, an attacker with write access to a parent directory can swap the path component for a symbolic link. The kernel resolves the path from scratch on the second call, and the privileged action lands on the attacker's chosen target.
This is called a time-of-check to time-of-use (TOCTOU) race condition. It's a classic security bug that has nothing to do with memory safety. Rust's borrow checker prevents use-after-free, double-free, and data races. It does not prevent logic errors in how you sequence system calls.
These bugs are serious enough that cp, mv, and rm are still GNU implementations in Ubuntu 26.04 LTS. The Rust versions weren't safe for privileged operations.
How Rust's Standard Library Makes This Easy to Get Wrong
Rust's standard library provides ergonomic APIs like fs::metadata, File::create, fs::remove_file, and fs::set_permissions. These are the functions you reach for first. They all take a path and resolve it every time, rather than taking a file descriptor and operating relative to that.
For a normal program, this is fine. For a privileged tool that needs to be secure against local attackers, it's a trap. The safe-looking API does the unsafe thing.
Case Study: CVE-2026-35355
Here's a simplified version of the bug from the install command implementation:
// 1. Clear the destination
fs::remove_file(to)?;
// ...
// 2. Create the destination. The path is re-resolved here!
let mut dest = File::create(to)?; // follows symlinks, truncates
copy(from, &mut dest)?;Between step 1 and step 2, anyone with write access to the parent directory can plant a symlink at the destination path. Point it to /etc/shadow. File::create follows the symlink, and the privileged process overwrites /etc/shadow with whatever the source file contained.
The fix uses OpenOptions::create_new(true):
fs::remove_file(to)?;
let mut dest = OpenOptions::new()
.write(true)
.create_new(true)
.open(to)?;
copy(from, &mut dest)?;The documentation for create_new says: "No file is allowed to exist at the target location, also no (dangling) symlink." If the call succeeds, the file was created atomically. There's no window for an attacker to slip in a symlink.
What Rust Safety Actually Means
Rust guarantees memory safety in safe code. No use-after-free. No buffer overflows. No data races. These are significant wins. Memory corruption bugs are responsible for roughly 70% of critical vulnerabilities in C and C++ codebases.
But memory safety is not the same as "correct" or "secure." Rust doesn't prevent:
- Race conditions in business logic
- TOCTOU vulnerabilities in filesystem operations
- Incorrect permission checks
- Logic errors in cryptographic implementations
- SQL injection (in unsafe database code)
- Denial of service through algorithmic complexity
The uutils audit is a reminder that "rewrite it in Rust" fixes one class of bugs. It doesn't fix all bugs.
Lessons for Systems Programmers
If you're writing privileged tools in Rust, Endler's analysis suggests several practices:
- Prefer file descriptor operations over path operations when security matters
- Use OpenOptions::create_new(true) instead of File::create when creating files atomically
- Audit any code that makes multiple syscalls on the same path
- Don't assume the borrow checker catches all security bugs
Jon Seager, VP Engineering for Ubuntu, discussed Canonical's Rust adoption on the 'Rust in Production' podcast. Listeners appreciated his honesty about where Rust helps and where it doesn't.
Another critical infrastructure vulnerability disclosure affecting enterprise security
The Bigger Picture
Rust's adoption in systems programming continues to grow. The Linux kernel includes Rust. Android uses it. Microsoft and Google have both invested heavily. This is good. Memory safety bugs are a real and serious problem.
But the uutils audit shows that security requires more than memory safety. It requires correct logic. It requires understanding the threat model. It requires knowing which APIs are safe for privileged operations and which aren't.
The uutils team deserves credit for publishing the audit results. Most organizations would quietly fix the bugs and say nothing. Sharing the details lets everyone learn.
Logicity's Take
Frequently Asked Questions
What are TOCTOU vulnerabilities?
Time-of-check to time-of-use vulnerabilities occur when a program checks a condition and then acts on it, but an attacker changes the state between the check and the action. In filesystem operations, this often involves swapping a file for a symlink.
Does Rust prevent all security vulnerabilities?
No. Rust prevents memory safety bugs like buffer overflows and use-after-free. It does not prevent logic errors, race conditions, incorrect permission checks, or vulnerabilities in how syscalls are sequenced.
Why are cp, mv, and rm still GNU in Ubuntu 26.04?
The TOCTOU vulnerabilities in the Rust implementations made them unsafe for privileged operations. Until those bugs are fixed and verified, Ubuntu is shipping the GNU versions for these commands.
How do you prevent TOCTOU bugs in Rust filesystem code?
Use file descriptor operations instead of path operations where possible. Use OpenOptions::create_new(true) for atomic file creation. Avoid sequences where you check a path's properties and then act on the same path separately.
Need Help Implementing This?
Source: Hacker News: Best / Corrode Rust Consulting
Huma Shazia
Senior AI & Tech Writer
Produced with AI assistance and reviewed by the Logicity editorial team. Learn more in our Editorial Policy.
Related Articles
More in Trending Tech
Humanity Just Went Farther Into Space Than Ever Before — And Made It Back Alive
Four astronauts splashed down in the Pacific Ocean on April 10, 2026, after traveling farther from Earth than any human beings in history. The Artemis II crew shattered a 56-year-old distance record set by Apollo 13, journeying nearly 253,000 miles from our planet during their 10-day lunar flyby mission. This marks the first time humans have ventured beyond low Earth orbit since 1972.

Amflow's Electric Bikes Are Blowing The Competition Away
Amflow, the e-bike brand spun out of DJI, has just released two impressive new electric mountain bikes that are breaking the mold with unprecedented power, range, and lightness. The flagship bikes are powered by the innovative Avinox motors and come with features like onboard navigation and heart rate control.

Canva Just Made a Power Play: Here's What It Means for the Future of Design and Marketing
Canva has made a bold move by acquiring two companies, Simtheory and Ortto, to boost its AI and marketing automation capabilities. This strategic move is set to revolutionize the way teams work on design and marketing projects. With these acquisitions, Canva is poised to become an all-in-one platform for businesses and individuals alike.


