Skip to content
Tech News
← Back to articles

Bugs Rust won't catch

read original get Rust Programming Language Book → more articles
Why This Matters

This article highlights that even in a modern, safety-focused language like Rust, critical security bugs can still slip through in production code, especially in system-level applications. For the tech industry and consumers, it underscores the importance of rigorous testing and audits when deploying Rust in security-sensitive environments, as well as the need for ongoing improvements in language tooling and best practices.

Key Takeaways

In April 2026, Canonical disclosed 44 CVEs in uutils, the Rust reimplementation of GNU coreutils that ships by default since 25.10. Most of them came out of an external audit commissioned ahead of the 26.04 LTS.

I read through the list and thought there’s a lot to learn from it.

What’s notable is that all of these bugs landed in a production Rust codebase, written by people who knew what they were doing, and none of them were caught by the borrow checker, clippy lints, or cargo audit.

I’m not writing this to criticize the uutils team. Quite the contrary; I actually want to thank them for sharing the audit results in such detail so that we can all learn from them.

We also had Jon Seager, VP Engineering for Ubuntu, on our ‘Rust in Production’ podcast recently and a lot of listeners appreciated his honesty about the state of Rust at Canonical.

If you write systems code in Rust, this is the most concentrated look at where Rust’s safety ends that you’ll likely find anywhere right now.

This is the largest cluster of bugs in the audit. It’s also the reason cp , mv , and rm are still GNU in Ubuntu 26.04 LTS. :(

The pattern is always the same. You do one syscall to check something about a path, then another syscall to act on the same 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 re-resolves the path from scratch on the second call, and the privileged action lands on the attacker’s chosen target.

Rust’s standard library makes this easy to get wrong. The ergonomic APIs you reach for first ( fs::metadata , File::create , fs::remove_file , fs::set_permissions ) all take a path and re-resolve it every time, rather than taking a file descriptor and operating relative to that. That’s fine for a normal program, but if you’re writing a privileged tool that needs to be secure against local attackers, you have to be careful.

Here’s the bug, simplified from src/uu/install/src/install.rs .

... continue reading