SYLEN
AboutNewsConferenceMembershipDonate

Email updates

Conference, news, and membership updates by email.

Site

  • About
  • News
  • Membership
  • Waitlist
  • Donate

Conference

  • Conference 2027
  • Call for papers

Account

  • Create account
  • Membership details

SYLEN

  • Guidelines
  • Privacy
  • Terms

© 2026 Systems Leadership and Engineering Network. sylen.org.

Membership details →
Back to news
Formal MethodsSource: github.comOctober 13, 2026

Rust Borrow Checker Bug Allows Lifetime Bound Bypasses via Covariant Field Assignment

A newly disclosed unsoundness issue in the Rust compiler permits programs to bypass struct lifetime requirements such as `T: 'static` via covariant field assignment. Present in compiler releases dating back 11 years, the hole allows short-lived references to escape scope checking through tailored `Drop` implementations.

Vulnerability Overview

A soundness hole tracked in Rust compiler issues #164250 and #164277 allows code to bypass lifetime bounds declared on struct definitions. By constructing a struct with generic parameters or constraints (such as `T: 'static` or `'a: 'static`) and subsequently overwriting a covariant struct field via assignment, the borrow checker fails to enforce the required static lifetime constraints on the assigned value.

The issue impacts current nightly builds as well as stable releases dating down to at least Rust 1.85.0, with minimal working reproductions confirming functionality on compiler versions back to Rust 1.4.

Mechanism of Unsoundness

The defect emerges from the interaction between field mutation, type variance, and destructor execution. In a standard reproduction, a structure with a static bound is defined alongside a custom `Drop` implementation:

```rust struct Q(Option);

impl Drop for Q { fn drop(&mut self) { if let Some(t) = self.0.take() { KEPT.lock().unwrap().push(Box::new(t)); } } } ```

The bug is triggered by initializing the struct with a compliant state (`Q(None)`) and then directly assigning a reference to a local variable into the inner `Option`:

```rust let l = String::from("hello world, this is long enough"); let mut q = Q(None); q.0 = Some(&l); ```

Because covariance permits the assignment without forcing the borrow checker to re-evaluate `'static` constraints on the newly assigned reference `&l`, the compiler treats `&l` as satisfying `'static`. When `q` goes out of scope, its `Drop` implementation executes with access to `&l`, stashing the reference into global static storage (`KEPT`). Once the stack frame for `l` is torn down, reads from the retained reference result in reading deallocated memory and trigger `AddressSanitizer: stack-use-after-scope` crashes.

Alternative variants demonstrate similar behavior using closure-based destructors without explicit `Any` downcasting, allowing dangling references to be captured directly into outer reference variables.

Compiler Team Triage and Impact

The issue has been assigned a `P-high` priority by the Rust Types Team under the `I-unsound`, `A-borrow-checker`, `A-destructors`, `A-lifetimes`, and `A-variance` labels.

According to Types Team member `@lcnr`, the defect is categorized as `P-high` rather than critical primarily due to its 11-year existence in the compiler codebase without being hit in wild production code. Triggering memory unsafety through this hole requires an intentionally crafted `Drop` implementation, making accidental occurrences in standard codebases unlikely.

Fixing this class of structural unsoundness is tied to ongoing, long-term compiler architecture initiatives managed by the Types Team, including the next-generation trait solver, the region constraint rework, and Project Zero.

Read the original article at github.com.