---
id: RUSTSEC-2026-0300
aliases:
  - GHSA-x6j6-3ffp-qrfr
title: Use-after-free in `clear` and `retain` when an element's `Drop` panics
summary: Use-after-free in `clear` and `retain` when an element's `Drop` panics
severity: none
vendor: skiplist
product: skiplist
ecosystem: rust
affected:
  - 'skiplist >= 0.0.0-0, < 1.1.1'
patched:
  - skiplist 1.1.1
published: '2026-09-02'
updated: '2026-09-22'
sourceUpdated: '2026-09-22T07:45:03.895629896Z'
source: OSV
sourceUrl: 'https://osv.dev/vulnerability/RUSTSEC-2026-0300'
references:
  - url: 'https://crates.io/crates/skiplist'
  - url: 'https://rustsec.org/advisories/RUSTSEC-2026-0300.html'
  - url: 'https://github.com/JP-Ellis/rust-skiplist/pull/334'
tags:
  - osv
  - rust
ingestedAt: '2026-09-24T07:16:01.871Z'
---

## Overview

`SkipList::clear` drops the node chain and only then resets `tail` and `len`.
The drop runs each element's `Drop`, and `T` carries no bounds excluding a
panicking one. If it unwinds, `tail` still points at the freed node while `len`
stays non-zero.

`back()`, `back_mut()`, `last_key_value()` and `last()` dereference `tail`
through `unsafe`, so reading the container after the unwind is a use-after-free
(CWE-416). `Drop for SkipList` calls `Box::from_raw` on `self.head`, which
`clear` already destroyed, so dropping the container is a double free
(CWE-415).

`retain`, `retain_mut` and `dedup_by` reach the same state through
`Node::filter_rebuild`, which frees nodes and runs a user predicate before the
caller commits `tail` and `len`. There the head links are left partially
rewired, so traversal can also reach freed nodes.

## Mitigation

Update to 1.1.1.

## Affected packages

- `skiplist >= 0.0.0-0, < 1.1.1`

## Remediation

Upgrade to a patched release:

- `skiplist 1.1.1`
