NIST deprecates RSA-2048 from 2030. Find every one of them before attackers do.
🦀 crates.io
Not in CISA KEV

diesel-async may expose uninitialized padding bytes for MySQL temporal columnsGHSA-ff9q-rm55-q7qr

Fix: diesel-rs/diesel_async@18f2c86

GHSA-ff9q-rm55-q7qr is a security vulnerability in diesel-async. A fix is available for diesel-async — see the affected versions and patch details below.

Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of May 7, 2026 · OSV.dev, FIRST.org (EPSS)

Real-World Exposure

1 pkg affected
🦀diesel-async

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects crates.io packages — download data is not available via public APIs for these ecosystems.

Description

Summary

diesel-async exposes uninitialized stack padding to safe code on every read of a MySQL DATE, TIME, DATETIME, or TIMESTAMP column. Reading that buffer is undefined behavior, and the leaked bytes can contain stale heap/stack contents, so this is both a soundness bug and a potential information-disclosure vector.

Details

In diesel-async/src/mysql/row.rs (lines 65-103), MysqlRow::get builds a MysqlTime from the parsed mysql_async::Value and then fabricates the byte buffer that downstream FromSql impls expect like this:

let date = MysqlTime::new(/* fields from Value::Date / Value::Time */);
let buffer = unsafe {
    let ptr = &date as *const MysqlTime as *const u8;
    let slice = std::slice::from_raw_parts(ptr, std::mem::size_of::<MysqlTime>());
    slice.to_vec()
};

MysqlTime is #[repr(C)] with 3 bytes of padding after bool neg (Linux x86_64, offsets 0x21..0x23). The literal construction leaves that padding uninitialized, and to_vec() carries it into a Vec<u8> that becomes the MysqlValue's backing buffer, reachable from safe code via MysqlValue::as_bytes() -> &[u8].

diesel itself avoids this by going through MaybeUninit::<MysqlTime>::zeroed() + ptr::copy_nonoverlapping (see diesel/src/mysql/value.rs:43-94); the same pattern would fix this. Alternatively, write the bytes diesel's FromSql reads without round-tripping through a MysqlTime value.

PoC

Cargo.toml:

[dependencies]
diesel = { version = "~2.3.0", default-features = false, features = ["mysql_backend"] }
diesel-async = { version = "=0.8.0", features = ["mysql"] }
mysql_common = { version = "0.35", default-features = false }

src/main.rs:

use diesel::row::{Field, Row};
use diesel_async::{AsyncConnectionCore, AsyncMysqlConnection};
use mysql_common::{constants::ColumnType, packets::Column, prelude::FromRow, value::Value};

type MysqlRow = <AsyncMysqlConnection as AsyncConnectionCore>::Row<'static, 'static>;

fn main() {
    let cols = std::sync::Arc::from([Column::new(ColumnType::MYSQL_TYPE_DATE)]);
    let raw = mysql_common::row::new_row(vec![Value::Date(2024, 1, 1, 0, 0, 0, 0)], cols);
    let row: MysqlRow = FromRow::from_row(raw);

    let field = row.get(0).unwrap();
    let bytes = field.value().unwrap().as_bytes();
    let _: u64 = bytes.iter().map(|&b| b as u64).sum(); // UB: hits padding
}

Miri output:

error: Undefined Behavior: reading memory at alloc844[0x21..0x22], but memory is uninitialized at [0x21..0x22], and this operation requires initialized memory
  --> src/main.rs:14:37
   |
14 |     let _: u64 = bytes.iter().map(|&b| b as u64).sum(); // UB: hits padding
   |                                     ^ Undefined Behavior occurred here
   |
   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
   = note: stack backtrace:
           0: main::{closure#0}
               at src/main.rs:14:37: 14:38
           1: std::iter::adapters::map::map_fold::<&u8, u64, u64, {closure@src/main.rs:14:35: 14:39}, {closure@<u64 as std::iter::Sum>::sum<std::iter::Map<std::slice::Iter<'_, u8>, {closure@src/main.rs:14:35: 14:39}>>::{closure#0}}>::{closure#0}
               at /home/paolobarbolini/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/adapters/map.rs:88:28: 88:34
           2: <std::slice::Iter<'_, u8> as std::iter::Iterator>::fold::<u64, {closure@std::iter::adapters::map::map_fold<&u8, u64, u64, {closure@src/main.rs:14:35: 14:39}, {closure@<u64 as std::iter::Sum>::sum<std::iter::Map<std::slice::Iter<'_, u8>, {closure@src/main.rs:14:35: 14:39}>>::{closure#0}}>::{closure#0}}>
               at /home/paolobarbolini/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/iter/macros.rs:279:27: 279:85
           3: <std::iter::Map<std::slice::Iter<'_, u8>, {closure@src/main.rs:14:35: 14:39}> as std::iter::Iterator>::fold::<u64, {closure@<u64 as std::iter::Sum>::sum<std::iter::Map<std::slice::Iter<'_, u8>, {closure@src/main.rs:14:35: 14:39}>>::{closure#0}}>
               at /home/paolobarbolini/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/adapters/map.rs:128:9: 128:50
           4: <u64 as std::iter::Sum>::sum::<std::iter::Map<std::slice::Iter<'_, u8>, {closure@src/main.rs:14:35: 14:39}>>
               at /home/paolobarbolini/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/accum.rs:52:17: 56:18
           5: <std::iter::Map<std::slice::Iter<'_, u8>, {closure@src/main.rs:14:35: 14:39}> as std::iter::Iterator>::sum::<u64>
               at /home/paolobarbolini/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:3676:9: 3676:23
           6: main
               at src/main.rs:14:18: 14:55

Uninitialized memory occurred at alloc844[0x21..0x22], in this allocation:
alloc844 (Rust heap, size: 48, align: 1) {
    0x00 │ e8 07 00 00 01 00 00 00 01 00 00 00 00 00 00 00 │ ................
    0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
    0x20 │ 00 __ __ __ 01 00 00 00 00 00 00 00 __ __ __ __ │ .░░░........░░░░
}

Impact

Soundness bug in safe API surface of diesel-async's MySQL backend. Affects every user of AsyncMysqlConnection whose queries return a temporal column.

AI disclosure: this issue was found via Claude Code running Claude Opus 4.7.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🦀crates.iodiesel-async≥ 0.1.0&&< 0.9.00.9.0cargo update -p diesel-async --precise 0.9.0

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for diesel-async, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update diesel-async to 0.9.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-ff9q-rm55-q7qr is resolved across your whole dependency graph.

  3. Workarounds

    Cap what an attacker can consume: apply request size, rate and timeout limits in front of the affected component, and run it with memory and CPU limits so exhaustion degrades one worker rather than the whole service.

Frequently Asked Questions

### Summary diesel-async exposes uninitialized stack padding to safe code on every read of a MySQL `DATE`, `TIME`, `DATETIME`, or `TIMESTAMP` column. Reading that buffer is undefined behavior, and the leaked bytes can contain stale heap/stack contents, so this is both a soundness bug and a potential information-disclosure vector. ### Details In `diesel-async/src/mysql/row.rs` (lines 65-103), `MysqlRow::get` builds a `MysqlTime` from the parsed `mysql_async::Value` and then fabricates the byte buffer that downstream `FromSql` impls expect like this: ```rust let date = MysqlTime::new(/* fiel
O3 Security · Impact-Aware SCA

Is GHSA-ff9q-rm55-q7qr in your dependencies?

Find it across crates.io, including transitive dependencies.

diesel-async may expose uninitialized padding bytes for…