VYPR
Critical severityNVD Advisory· Published Dec 31, 2020· Updated Aug 4, 2024

CVE-2020-35873

CVE-2020-35873

Description

An issue was discovered in the rusqlite crate before 0.23.0 for Rust. Memory safety can be violated because sessions.rs has a use-after-free.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Use-after-free in rusqlite's sessions.rs prior to 0.23.0 allows memory safety violation.

Vulnerability

CVE-2020-35873 is a use-after-free bug in the rusqlite crate for Rust, affecting versions before 0.23.0. The flaw exists in sessions.rs, where a reference to freed memory could be used, leading to undefined behavior. This is part of a group of memory safety issues addressed in the same release [3].

Exploitation

The vulnerability can be triggered by code that uses the sessions API provided by rusqlite. An attacker would need to craft input or control program flow to cause the dangling reference to be accessed. No special authentication is required beyond normal Rust API usage; the bug manifests purely through the crate's internal logic [1][2].

Impact

Successful exploitation could allow an attacker to read or write arbitrary memory, potentially leading to data corruption, information disclosure, or arbitrary code execution. The severity is heightened because memory safety violations in Rust are unexpected and undermine the language's guarantees [3][4].

Mitigation

The issue is fixed in rusqlite version 0.23.0 and later. Users should update their Cargo.toml dependency to "0.23.0" or newer. There is no workaround for older versions; updating is the only reliable mitigation [4].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
rusqlitecrates.io
< 0.23.00.23.0

Affected products

2

Patches

2
54043c803c83

Prep release 0.23.0

https://github.com/rusqlite/rusqliteThom ChiovoloniApr 23, 2020via osv
1 file changed · +1 1
  • Cargo.toml+1 1 modified
    @@ -1,6 +1,6 @@
     [package]
     name = "rusqlite"
    -version = "0.22.0"
    +version = "0.23.0"
     authors = ["The rusqlite developers"]
     edition = "2018"
     description = "Ergonomic wrapper for SQLite"
    
ac30e169ae51

Use SmallCString in most places

https://github.com/rusqlite/rusqliteThom ChiovoloniApr 14, 2020via ghsa
3 files changed · +16 12
  • src/inner_connection.rs+7 6 modified
    @@ -1,4 +1,4 @@
    -use std::ffi::CString;
    +use std::ffi::CStr;
     use std::os::raw::{c_char, c_int};
     #[cfg(feature = "load_extension")]
     use std::path::Path;
    @@ -8,7 +8,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
     use std::sync::{Arc, Mutex};
     
     use super::ffi;
    -use super::{str_for_sqlite, str_to_cstring};
    +use super::str_for_sqlite;
     use super::{Connection, InterruptHandle, OpenFlags, Result};
     use crate::error::{error_from_handle, error_from_sqlite_code, Error};
     use crate::raw_statement::RawStatement;
    @@ -51,9 +51,9 @@ impl InnerConnection {
         }
     
         pub fn open_with_flags(
    -        c_path: &CString,
    +        c_path: &CStr,
             flags: OpenFlags,
    -        vfs: Option<&CString>,
    +        vfs: Option<&CStr>,
         ) -> Result<InnerConnection> {
             #[cfg(not(feature = "bundled"))]
             ensure_valid_sqlite_version();
    @@ -171,7 +171,8 @@ impl InnerConnection {
         }
     
         pub fn execute_batch(&mut self, sql: &str) -> Result<()> {
    -        let c_sql = str_to_cstring(sql)?;
    +        // use CString instead of SmallCString because it's probably big.
    +        let c_sql = std::ffi::CString::new(sql)?;
             unsafe {
                 let r = ffi::sqlite3_exec(
                     self.db(),
    @@ -196,7 +197,7 @@ impl InnerConnection {
             unsafe {
                 let mut errmsg: *mut c_char = ptr::null_mut();
                 let r = if let Some(entry_point) = entry_point {
    -                let c_entry = str_to_cstring(entry_point)?;
    +                let c_entry = crate::str_to_cstring(entry_point)?;
                     ffi::sqlite3_load_extension(
                         self.db,
                         dylib_str.as_ptr(),
    
  • src/lib.rs+4 3 modified
    @@ -129,6 +129,7 @@ mod version;
     pub mod vtab;
     
     pub(crate) mod util;
    +pub(crate) use util::SmallCString;
     
     // Number of cached prepared statements we'll hold on to.
     const STATEMENT_CACHE_DEFAULT_CAPACITY: usize = 16;
    @@ -233,8 +234,8 @@ unsafe fn errmsg_to_string(errmsg: *const c_char) -> String {
         String::from_utf8_lossy(c_slice).into_owned()
     }
     
    -fn str_to_cstring(s: &str) -> Result<CString> {
    -    Ok(CString::new(s)?)
    +fn str_to_cstring(s: &str) -> Result<SmallCString> {
    +    Ok(SmallCString::new(s)?)
     }
     
     /// Returns `Ok((string ptr, len as c_int, SQLITE_STATIC | SQLITE_TRANSIENT))`
    @@ -301,7 +302,7 @@ pub enum DatabaseName<'a> {
         feature = "modern_sqlite"
     ))]
     impl DatabaseName<'_> {
    -    fn to_cstring(&self) -> Result<CString> {
    +    fn to_cstring(&self) -> Result<util::SmallCString> {
             use self::DatabaseName::{Attached, Main, Temp};
             match *self {
                 Main => str_to_cstring("main"),
    
  • src/session.rs+5 3 modified
    @@ -102,10 +102,11 @@ impl Session<'_> {
         /// Attach a table. `None` means all tables.
         pub fn attach(&mut self, table: Option<&str>) -> Result<()> {
             let table = if let Some(table) = table {
    -            str_to_cstring(table)?.as_ptr()
    +            Some(str_to_cstring(table)?)
             } else {
    -            ptr::null()
    +            None
             };
    +        let table = table.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null());
             unsafe { check!(ffi::sqlite3session_attach(self.s, table)) };
             Ok(())
         }
    @@ -156,7 +157,8 @@ impl Session<'_> {
         /// Load the difference between tables.
         pub fn diff(&mut self, from: DatabaseName<'_>, table: &str) -> Result<()> {
             let from = from.to_cstring()?;
    -        let table = str_to_cstring(table)?.as_ptr();
    +        let table = str_to_cstring(table)?;
    +        let table = table.as_ptr();
             unsafe {
                 let mut errmsg = ptr::null_mut();
                 let r =
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.