From 5a04691b435d01e20bc18901b118c44f3f53bd31 Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Thu, 18 Jun 2026 01:45:40 +0200 Subject: [PATCH 1/2] ref(store): Validate database_name before CREATE DATABASE `CREATE DATABASE` cannot use bind parameters for the database name, so the name is interpolated into the statement. Restrict it to a safe identifier charset (ASCII alphanumerics and underscores) to rule out SQL injection. ref STREAM-1125 Co-Authored-By: Claude Opus 4.8 --- src/store/adapters/postgres.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/store/adapters/postgres.rs b/src/store/adapters/postgres.rs index cd3c4d4a..2462f920 100644 --- a/src/store/adapters/postgres.rs +++ b/src/store/adapters/postgres.rs @@ -51,6 +51,21 @@ pub async fn migrate(config: &StoreConfig) -> Result<()> { .await?; if !row.0 { + // `CREATE DATABASE` does not accept bind parameters for the database + // name, so it has to be interpolated into the statement. Restrict it to + // a safe identifier charset to rule out SQL injection. + if !config + .pg + .database_name + .chars() + .all(|c| matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_')) + { + return Err(anyhow!( + "invalid database_name {:?}: only ASCII alphanumerics and underscores are allowed", + &config.pg.database_name + )); + } + println!("Creating database {}", &config.pg.database_name); sqlx::query(format!("CREATE DATABASE {}", &config.pg.database_name).as_str()) .execute(&default_pool) From 3a02a21207232ea19c6f36c3e5af9dd7e3efeac2 Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Thu, 18 Jun 2026 16:00:01 +0200 Subject: [PATCH 2/2] update comment --- src/store/adapters/postgres.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/store/adapters/postgres.rs b/src/store/adapters/postgres.rs index 2462f920..05d5e59d 100644 --- a/src/store/adapters/postgres.rs +++ b/src/store/adapters/postgres.rs @@ -52,8 +52,8 @@ pub async fn migrate(config: &StoreConfig) -> Result<()> { if !row.0 { // `CREATE DATABASE` does not accept bind parameters for the database - // name, so it has to be interpolated into the statement. Restrict it to - // a safe identifier charset to rule out SQL injection. + // name. but this is not a critical SQL injection as the database name is not untrusted + // user input. nevertheless, let's validate DB identifiers to prevent the worst. if !config .pg .database_name