{"id":"GHSA-m9qr-4rcq-3jhc","aliases":["RUSTSEC-2026-0454"],"status":"published","title":"Data race and double free via unsound `Send`/`Sync` in `reblessive`","description":"`dbs::Executor` drives every SurrealQL statement through `reblessive::tree::TreeStack`. In `reblessive 0.4.3` the runtime types unconditionally assert `Send`/`Sync` (`unsafe impl Send/Sync for Stack`, `TreeStack` and `Runner`), while the public entry points accept any future without a `Send` bound and store it type-erased in a bump allocator.\n\nTwo safe-code consequences follow. First, `Runner::step_async`/`finish_async` return driver futures tied to the stack borrow rather than to `\u0026mut self`, so a driver future can be duplicated; because `Stack` is `Sync` those futures are `Send`, and polling two copies on different threads runs `drive_top_task` concurrently — racy `Cell`/`UnsafeCell` access, double `pop_task()`/`pop_dealloc()` (double drop / double free) and a non-atomic `Option::take`. Second, `TreeStack: Send` lets safe code move a driver whose type-erased future captures `!Send` state (`Rc`, `RefCell`) to another thread while the creating thread keeps an alias of that state.\n\nNo `unsafe` is needed at the call site. `surrealdb-core`'s own query futures are `Send` only because of the unsound `unsafe impl Send for TreeStack`, while the captured `\u0026mut tree::Stk` is deliberately `!Send`.\n\nThe unsound dependency was removed in 4.0.0 and the parser now uses plain recursion (commit `75407c4bcc`).","severity":{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H","level":"high","from":"osv"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"published":"2026-11-03T12:00:00Z","modified":"2026-11-06T15:45:02Z","fixes":[{"ecosystem":"crates.io","package":"surrealdb-core","fixed_in":["4.0.0"],"sources":["osv"]}],"affected":[{"source":"osv","ecosystem":"crates.io","package":"surrealdb-core","ranges":[{"type":"SEMVER","events":[{"introduced":"0.0.0-0"},{"fixed":"4.0.0"}]}]}],"references":[{"url":"https://crates.io/crates/surrealdb-core","tags":["package"]},{"url":"https://rustsec.org/advisories/RUSTSEC-2026-0454.html","tags":["advisory"]},{"url":"https://github.com/surrealdb/surrealdb/commit/75407c4bccc6d6679d7d6e7a18af0065afdded7d","tags":["web"]}],"sources":{"osv":[{"id":"RUSTSEC-2026-0454","title":"Data race and double free via unsound `Send`/`Sync` in `reblessive`","description":"`dbs::Executor` drives every SurrealQL statement through `reblessive::tree::TreeStack`. In `reblessive 0.4.3` the runtime types unconditionally assert `Send`/`Sync` (`unsafe impl Send/Sync for Stack`, `TreeStack` and `Runner`), while the public entry points accept any future without a `Send` bound and store it type-erased in a bump allocator.\n\nTwo safe-code consequences follow. First, `Runner::step_async`/`finish_async` return driver futures tied to the stack borrow rather than to `\u0026mut self`, so a driver future can be duplicated; because `Stack` is `Sync` those futures are `Send`, and polling two copies on different threads runs `drive_top_task` concurrently — racy `Cell`/`UnsafeCell` access, double `pop_task()`/`pop_dealloc()` (double drop / double free) and a non-atomic `Option::take`. Second, `TreeStack: Send` lets safe code move a driver whose type-erased future captures `!Send` state (`Rc`, `RefCell`) to another thread while the creating thread keeps an alias of that state.\n\nNo `unsafe` is needed at the call site. `surrealdb-core`'s own query futures are `Send` only because of the unsound `unsafe impl Send for TreeStack`, while the captured `\u0026mut tree::Stk` is deliberately `!Send`.\n\nThe unsound dependency was removed in 4.0.0 and the parser now uses plain recursion (commit `75407c4bcc`).","status":"published","published":"2026-11-03T12:00:00Z","modified":"2026-11-06T15:45:02.400043505Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H","level":"high"}],"updated_at":"2026-11-06T15:57:48.551562Z"}]}}
