From f37934be1b6e39a71dd40a34cd31ad24df6b6333 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2026 09:53:19 +0000 Subject: [PATCH] Fix SQL Injection vulnerability in `std.sqlite` module by supporting parameterized queries Co-authored-by: Tcode-Motion <188012755+Tcode-Motion@users.noreply.github.com> --- compiler/llvm_backend/src/jit.rs | 4 +-- stdlib/src/sqlite.rs | 61 ++++++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/compiler/llvm_backend/src/jit.rs b/compiler/llvm_backend/src/jit.rs index 9005daa3..e05cbfe8 100644 --- a/compiler/llvm_backend/src/jit.rs +++ b/compiler/llvm_backend/src/jit.rs @@ -5,8 +5,8 @@ #![cfg(feature = "llvm")] use llvm_sys::core::*; -use llvm_sys::orc2::*; use llvm_sys::orc2::lljit::*; +use llvm_sys::orc2::*; use std::collections::HashMap; use std::ffi::CString; use std::ptr; @@ -60,7 +60,7 @@ impl LLVMJitEngine { // 3. Set host target triple let _host_triple = LLVMOrcLLJITGetExecutionSession(self.jit); // session triple fallback - // We can just keep the default LLVM target triple + // We can just keep the default LLVM target triple // 4. Wrap Module in ThreadSafeModule let tsm = LLVMOrcCreateNewThreadSafeModule(ctx.module, self.ts_ctx); diff --git a/stdlib/src/sqlite.rs b/stdlib/src/sqlite.rs index c2b0313f..e56ddc5c 100644 --- a/stdlib/src/sqlite.rs +++ b/stdlib/src/sqlite.rs @@ -52,11 +52,39 @@ impl StdlibRegistry { ) })?; let sql = args[1].to_string(); + let params_list = if args.len() > 2 { + if let RuntimeValue::List { items, .. } = &args[2] { + items.borrow().clone() + } else { + Vec::new() + } + } else { + Vec::new() + }; CONNECTIONS.with(|m| { let mut map = m.borrow_mut(); if let Some(conn) = map.get_mut(&id) { - conn.execute(&sql, []).map_err(|e| { + let params_converted: Vec = params_list + .iter() + .map(|p| match p { + RuntimeValue::Null => rusqlite::types::Value::Null, + RuntimeValue::Bool(b) => { + rusqlite::types::Value::Integer(if *b { 1 } else { 0 }) + } + RuntimeValue::Int(i) => rusqlite::types::Value::Integer(*i), + RuntimeValue::Float(f) => rusqlite::types::Value::Real(*f), + RuntimeValue::Str(s) => rusqlite::types::Value::Text(s.clone()), + _ => rusqlite::types::Value::Null, + }) + .collect(); + + let params_refs: Vec<&dyn rusqlite::types::ToSql> = params_converted + .iter() + .map(|p| p as &dyn rusqlite::types::ToSql) + .collect(); + + conn.execute(&sql, params_refs.as_slice()).map_err(|e| { RuntimeError::new( RuntimeErrorKind::InvalidOperation(e.to_string()), None, @@ -93,6 +121,15 @@ impl StdlibRegistry { ) })?; let sql = args[1].to_string(); + let params_list = if args.len() > 2 { + if let RuntimeValue::List { items, .. } = &args[2] { + items.borrow().clone() + } else { + Vec::new() + } + } else { + Vec::new() + }; let rows = CONNECTIONS.with(|m| { let mut map = m.borrow_mut(); @@ -108,9 +145,29 @@ impl StdlibRegistry { let col_names: Vec = (0..col_count) .map(|i| stmt.column_name(i).unwrap_or("?").to_string()) .collect(); + + let params_converted: Vec = params_list + .iter() + .map(|p| match p { + RuntimeValue::Null => rusqlite::types::Value::Null, + RuntimeValue::Bool(b) => { + rusqlite::types::Value::Integer(if *b { 1 } else { 0 }) + } + RuntimeValue::Int(i) => rusqlite::types::Value::Integer(*i), + RuntimeValue::Float(f) => rusqlite::types::Value::Real(*f), + RuntimeValue::Str(s) => rusqlite::types::Value::Text(s.clone()), + _ => rusqlite::types::Value::Null, + }) + .collect(); + + let params_refs: Vec<&dyn rusqlite::types::ToSql> = params_converted + .iter() + .map(|p| p as &dyn rusqlite::types::ToSql) + .collect(); + let mut rows = Vec::new(); let row_iter = stmt - .query_map([], |row| { + .query_map(params_refs.as_slice(), |row| { let mut map = IndexMap::new(); for i in 0..col_count { let name = col_names[i].clone();