From dc08274aa294bae0d404573370d6221dcca3e89b Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 17 Jun 2025 14:55:45 +0100 Subject: [PATCH 1/6] Rust: Update SqlxQuery, SqlxExecute from getResolvedPath -> getCanonicalPath. --- rust/ql/lib/codeql/rust/frameworks/Sqlx.qll | 14 +++++++----- .../security/CWE-089/SqlInjection.expected | 12 ---------- .../test/query-tests/security/CWE-089/sqlx.rs | 22 +++++++++---------- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/rust/ql/lib/codeql/rust/frameworks/Sqlx.qll b/rust/ql/lib/codeql/rust/frameworks/Sqlx.qll index 5504993ab744..5b33f72fdf68 100644 --- a/rust/ql/lib/codeql/rust/frameworks/Sqlx.qll +++ b/rust/ql/lib/codeql/rust/frameworks/Sqlx.qll @@ -5,6 +5,8 @@ private import rust private import codeql.rust.Concepts private import codeql.rust.dataflow.DataFlow +private import codeql.rust.internal.TypeInference +private import codeql.rust.internal.Type /** * A call to `sqlx::query` and variations. @@ -14,11 +16,12 @@ private class SqlxQuery extends SqlConstruction::Range { SqlxQuery() { this.asExpr().getExpr() = call and - call.getFunction().(PathExpr).getResolvedPath() = + call.getStaticTarget().(Addressable).getCanonicalPath() = [ - "crate::query::query", "crate::query_as::query_as", "crate::query_with::query_with", - "crate::query_as_with::query_as_with", "crate::query_scalar::query_scalar", - "crate::query_scalar_with::query_scalar_with", "crate::raw_sql::raw_sql" + "sqlx_core::query::query", "sqlx_core::query_as::query_as", + "sqlx_core::query_with::query_with", "sqlx_core::query_as_with::query_as_with", + "sqlx_core::query_scalar::query_scalar", "sqlx_core::query_scalar_with::query_scalar_with", + "sqlx_core::raw_sql::raw_sql" ] } @@ -33,7 +36,8 @@ private class SqlxExecute extends SqlExecution::Range { SqlxExecute() { this.asExpr().getExpr() = call and - call.(Resolvable).getResolvedPath() = "crate::executor::Executor::execute" + call.getStaticTarget().(Addressable).getCanonicalPath() = + "sqlx_core::executor::Executor::execute" } override DataFlow::Node getSql() { result.asExpr().getExpr() = call.getArgList().getArg(0) } diff --git a/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected b/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected index ab8e995be762..fcfa77cfda0f 100644 --- a/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected +++ b/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected @@ -1,8 +1,4 @@ #select -| sqlx.rs:66:26:66:46 | safe_query_3.as_str() | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:66:26:66:46 | safe_query_3.as_str() | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | -| sqlx.rs:67:26:67:48 | unsafe_query_1.as_str() | sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:67:26:67:48 | unsafe_query_1.as_str() | This query depends on a $@. | sqlx.rs:47:22:47:35 | ...::args | user-provided value | -| sqlx.rs:69:30:69:52 | unsafe_query_2.as_str() | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:69:30:69:52 | unsafe_query_2.as_str() | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | -| sqlx.rs:71:30:71:52 | unsafe_query_4.as_str() | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:71:30:71:52 | unsafe_query_4.as_str() | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | This query depends on a $@. | sqlx.rs:47:22:47:35 | ...::args | user-provided value | | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | @@ -24,22 +20,18 @@ edges | sqlx.rs:49:9:49:21 | remote_number | sqlx.rs:52:32:52:87 | MacroExpr | provenance | | | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | provenance | MaD:7 | | sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | sqlx.rs:49:9:49:21 | remote_number | provenance | | -| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:66:26:66:46 | safe_query_3.as_str() | provenance | MaD:3 | | sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:3 | | sqlx.rs:52:24:52:88 | res | sqlx.rs:52:32:52:87 | { ... } | provenance | | | sqlx.rs:52:32:52:87 | ...::format(...) | sqlx.rs:52:24:52:88 | res | provenance | | | sqlx.rs:52:32:52:87 | ...::must_use(...) | sqlx.rs:52:9:52:20 | safe_query_3 | provenance | | | sqlx.rs:52:32:52:87 | MacroExpr | sqlx.rs:52:32:52:87 | ...::format(...) | provenance | MaD:4 | | sqlx.rs:52:32:52:87 | { ... } | sqlx.rs:52:32:52:87 | ...::must_use(...) | provenance | MaD:9 | -| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:67:26:67:48 | unsafe_query_1.as_str() | provenance | MaD:3 | | sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | provenance | MaD:3 | | sqlx.rs:53:26:53:36 | &arg_string [&ref] | sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | provenance | | | sqlx.rs:53:27:53:36 | arg_string | sqlx.rs:53:26:53:36 | &arg_string [&ref] | provenance | | -| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:69:30:69:52 | unsafe_query_2.as_str() | provenance | MaD:3 | | sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | provenance | MaD:3 | | sqlx.rs:54:26:54:39 | &remote_string [&ref] | sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | provenance | | | sqlx.rs:54:27:54:39 | remote_string | sqlx.rs:54:26:54:39 | &remote_string [&ref] | provenance | | -| sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:71:30:71:52 | unsafe_query_4.as_str() | provenance | MaD:3 | | sqlx.rs:56:9:56:22 | unsafe_query_4 | sqlx.rs:82:29:82:51 | unsafe_query_4.as_str() | provenance | MaD:3 | | sqlx.rs:59:9:59:73 | res | sqlx.rs:59:17:59:72 | { ... } | provenance | | | sqlx.rs:59:17:59:72 | ...::format(...) | sqlx.rs:59:9:59:73 | res | provenance | | @@ -91,10 +83,6 @@ nodes | sqlx.rs:59:17:59:72 | ...::must_use(...) | semmle.label | ...::must_use(...) | | sqlx.rs:59:17:59:72 | MacroExpr | semmle.label | MacroExpr | | sqlx.rs:59:17:59:72 | { ... } | semmle.label | { ... } | -| sqlx.rs:66:26:66:46 | safe_query_3.as_str() | semmle.label | safe_query_3.as_str() | -| sqlx.rs:67:26:67:48 | unsafe_query_1.as_str() | semmle.label | unsafe_query_1.as_str() | -| sqlx.rs:69:30:69:52 | unsafe_query_2.as_str() | semmle.label | unsafe_query_2.as_str() | -| sqlx.rs:71:30:71:52 | unsafe_query_4.as_str() | semmle.label | unsafe_query_4.as_str() | | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | semmle.label | safe_query_3.as_str() | | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | semmle.label | unsafe_query_1.as_str() | | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | semmle.label | unsafe_query_2.as_str() | diff --git a/rust/ql/test/query-tests/security/CWE-089/sqlx.rs b/rust/ql/test/query-tests/security/CWE-089/sqlx.rs index 3de58350f20c..291b04257d5a 100644 --- a/rust/ql/test/query-tests/security/CWE-089/sqlx.rs +++ b/rust/ql/test/query-tests/security/CWE-089/sqlx.rs @@ -61,14 +61,14 @@ async fn test_sqlx_mysql(url: &str, enable_remote: bool) -> Result<(), sqlx::Err let prepared_query_1 = String::from("SELECT * FROM people WHERE firstname=?"); // (prepared arguments are safe) // direct execution - let _ = conn.execute(safe_query_1.as_str()).await?; // $ sql-sink - let _ = conn.execute(safe_query_2.as_str()).await?; // $ sql-sink - let _ = conn.execute(safe_query_3.as_str()).await?; // $ sql-sink SPURIOUS: Alert[rust/sql-injection]=remote1 - let _ = conn.execute(unsafe_query_1.as_str()).await?; // $ sql-sink Alert[rust/sql-injection]=args1 + let _ = conn.execute(safe_query_1.as_str()).await?; // $ MISSING: sql-sink + let _ = conn.execute(safe_query_2.as_str()).await?; // $ MISSING: sql-sink + let _ = conn.execute(safe_query_3.as_str()).await?; // $ MISSING: sql-sink + let _ = conn.execute(unsafe_query_1.as_str()).await?; // $ MISSING: sql-sink Alert[rust/sql-injection]=args1 if enable_remote { - let _ = conn.execute(unsafe_query_2.as_str()).await?; // $ sql-sink Alert[rust/sql-injection]=remote1 - let _ = conn.execute(unsafe_query_3.as_str()).await?; // $ sql-sink MISSING: Alert[rust/sql-injection]=remote1 - let _ = conn.execute(unsafe_query_4.as_str()).await?; // $ sql-sink Alert[rust/sql-injection]=remote1 + let _ = conn.execute(unsafe_query_2.as_str()).await?; // $ MISSING: sql-sink Alert[rust/sql-injection]=remote1 + let _ = conn.execute(unsafe_query_3.as_str()).await?; // $ MISSING: sql-sink Alert[rust/sql-injection]=remote1 + let _ = conn.execute(unsafe_query_4.as_str()).await?; // $ MISSING: sql-sink Alert[rust/sql-injection]=remote1 } // prepared queries @@ -103,9 +103,9 @@ async fn test_sqlx_sqlite(url: &str, enable_remote: bool) -> Result<(), sqlx::Er let prepared_query_1 = String::from("SELECT * FROM people WHERE firstname=?"); // (prepared arguments are safe) // direct execution (with extra variants) - let _ = conn.execute(safe_query_1.as_str()).await?; // $ sql-sink + let _ = conn.execute(safe_query_1.as_str()).await?; // $ MISSING: sql-sink if enable_remote { - let _ = conn.execute(unsafe_query_1.as_str()).await?; // $ sql-sink MISSING: Alert[rust/sql-injection]=remote2 + let _ = conn.execute(unsafe_query_1.as_str()).await?; // $ MISSING: sql-sink Alert[rust/sql-injection]=remote2 } // ... let _ = sqlx::raw_sql(safe_query_1.as_str()).execute(&mut conn).await?; // $ sql-sink @@ -176,9 +176,9 @@ async fn test_sqlx_postgres(url: &str, enable_remote: bool) -> Result<(), sqlx:: let prepared_query_1 = String::from("SELECT * FROM people WHERE firstname=$1"); // (prepared arguments are safe) // direct execution - let _ = conn.execute(safe_query_1.as_str()).await?; // $ sql-sink + let _ = conn.execute(safe_query_1.as_str()).await?; // $ MISSING: sql-sink if enable_remote { - let _ = conn.execute(unsafe_query_1.as_str()).await?; // $ sql-sink MISSING: Alert[rust/sql-injection]=remote3 + let _ = conn.execute(unsafe_query_1.as_str()).await?; // $ MISSING: sql-sink Alert[rust/sql-injection]=remote3 } // prepared queries From 87deab861fc6c6f09a1b8af1cdac3b8dd9d51ce7 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 16 Jul 2025 16:23:50 +0100 Subject: [PATCH 2/6] Rust: Remove Sqlx.qll. --- rust/ql/lib/codeql/rust/Frameworks.qll | 1 - rust/ql/lib/codeql/rust/frameworks/Sqlx.qll | 44 --------- .../security/CWE-089/SqlInjection.expected | 90 ++----------------- .../security/CWE-089/SqlSinks.expected | 39 ++++++++ 4 files changed, 45 insertions(+), 129 deletions(-) delete mode 100644 rust/ql/lib/codeql/rust/frameworks/Sqlx.qll diff --git a/rust/ql/lib/codeql/rust/Frameworks.qll b/rust/ql/lib/codeql/rust/Frameworks.qll index 0e91ed427ba4..317746f2d186 100644 --- a/rust/ql/lib/codeql/rust/Frameworks.qll +++ b/rust/ql/lib/codeql/rust/Frameworks.qll @@ -4,6 +4,5 @@ private import codeql.rust.frameworks.rustcrypto.RustCrypto private import codeql.rust.frameworks.Poem -private import codeql.rust.frameworks.Sqlx private import codeql.rust.frameworks.stdlib.Clone private import codeql.rust.frameworks.stdlib.Stdlib diff --git a/rust/ql/lib/codeql/rust/frameworks/Sqlx.qll b/rust/ql/lib/codeql/rust/frameworks/Sqlx.qll deleted file mode 100644 index 5b33f72fdf68..000000000000 --- a/rust/ql/lib/codeql/rust/frameworks/Sqlx.qll +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Provides modeling for the `SQLx` library. - */ - -private import rust -private import codeql.rust.Concepts -private import codeql.rust.dataflow.DataFlow -private import codeql.rust.internal.TypeInference -private import codeql.rust.internal.Type - -/** - * A call to `sqlx::query` and variations. - */ -private class SqlxQuery extends SqlConstruction::Range { - CallExpr call; - - SqlxQuery() { - this.asExpr().getExpr() = call and - call.getStaticTarget().(Addressable).getCanonicalPath() = - [ - "sqlx_core::query::query", "sqlx_core::query_as::query_as", - "sqlx_core::query_with::query_with", "sqlx_core::query_as_with::query_as_with", - "sqlx_core::query_scalar::query_scalar", "sqlx_core::query_scalar_with::query_scalar_with", - "sqlx_core::raw_sql::raw_sql" - ] - } - - override DataFlow::Node getSql() { result.asExpr().getExpr() = call.getArgList().getArg(0) } -} - -/** - * A call to `sqlx::Executor::execute`. - */ -private class SqlxExecute extends SqlExecution::Range { - MethodCallExpr call; - - SqlxExecute() { - this.asExpr().getExpr() = call and - call.getStaticTarget().(Addressable).getCanonicalPath() = - "sqlx_core::executor::Executor::execute" - } - - override DataFlow::Node getSql() { result.asExpr().getExpr() = call.getArgList().getArg(0) } -} diff --git a/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected b/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected index eea48df8d5b0..1570cd211c8f 100644 --- a/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected +++ b/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected @@ -1,88 +1,10 @@ #select -| sqlx.rs:77:25:77:45 | safe_query_3.as_str() | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | -| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | This query depends on a $@. | sqlx.rs:47:22:47:35 | ...::args | user-provided value | -| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | edges -| sqlx.rs:47:9:47:18 | arg_string | sqlx.rs:53:27:53:36 | arg_string | provenance | | -| sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:47:22:47:37 | ...::args(...) [element] | provenance | Src:MaD:2 | -| sqlx.rs:47:22:47:37 | ...::args(...) [element] | sqlx.rs:47:22:47:44 | ... .nth(...) [Some] | provenance | MaD:3 | -| sqlx.rs:47:22:47:44 | ... .nth(...) [Some] | sqlx.rs:47:22:47:77 | ... .unwrap_or(...) | provenance | MaD:5 | -| sqlx.rs:47:22:47:77 | ... .unwrap_or(...) | sqlx.rs:47:9:47:18 | arg_string | provenance | | -| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | provenance | MaD:9 | -| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | provenance | MaD:9 | -| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:54:27:54:39 | remote_string | provenance | | -| sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | provenance | Src:MaD:1 | -| sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | sqlx.rs:48:25:48:78 | ... .unwrap() | provenance | MaD:6 | -| sqlx.rs:48:25:48:78 | ... .unwrap() | sqlx.rs:48:25:48:85 | ... .text() [Ok] | provenance | MaD:10 | -| sqlx.rs:48:25:48:85 | ... .text() [Ok] | sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | provenance | MaD:7 | -| sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | sqlx.rs:48:9:48:21 | remote_string | provenance | | -| sqlx.rs:49:9:49:21 | remote_number | sqlx.rs:52:32:52:87 | MacroExpr | provenance | | -| sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | provenance | MaD:7 | -| sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | sqlx.rs:49:9:49:21 | remote_number | provenance | | -| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:36 | safe_query_3 | provenance | | -| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:8 | -| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:4 | -| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:8 | -| sqlx.rs:52:24:52:88 | res | sqlx.rs:52:32:52:87 | { ... } | provenance | | -| sqlx.rs:52:32:52:87 | ...::format(...) | sqlx.rs:52:24:52:88 | res | provenance | | -| sqlx.rs:52:32:52:87 | ...::must_use(...) | sqlx.rs:52:9:52:20 | safe_query_3 | provenance | | -| sqlx.rs:52:32:52:87 | MacroExpr | sqlx.rs:52:32:52:87 | ...::format(...) | provenance | MaD:11 | -| sqlx.rs:52:32:52:87 | { ... } | sqlx.rs:52:32:52:87 | ...::must_use(...) | provenance | MaD:12 | -| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | provenance | MaD:8 | -| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | provenance | MaD:4 | -| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | provenance | MaD:8 | -| sqlx.rs:53:26:53:36 | &arg_string [&ref] | sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | provenance | | -| sqlx.rs:53:27:53:36 | arg_string | sqlx.rs:53:26:53:36 | &arg_string [&ref] | provenance | | -| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | provenance | MaD:8 | -| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | provenance | MaD:4 | -| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | provenance | MaD:8 | -| sqlx.rs:54:26:54:39 | &remote_string [&ref] | sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | provenance | | -| sqlx.rs:54:27:54:39 | remote_string | sqlx.rs:54:26:54:39 | &remote_string [&ref] | provenance | | -| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:8 | -| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:4 | -| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:8 | -models -| 1 | Source: reqwest::blocking::get; ReturnValue.Field[core::result::Result::Ok(0)]; remote | -| 2 | Source: std::env::args; ReturnValue.Element; commandargs | -| 3 | Summary: <_ as core::iter::traits::iterator::Iterator>::nth; Argument[self].Element; ReturnValue.Field[core::option::Option::Some(0)]; value | -| 4 | Summary: ::as_str; Argument[self]; ReturnValue; value | -| 5 | Summary: ::unwrap_or; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value | -| 6 | Summary: ::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | -| 7 | Summary: ::unwrap_or; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | -| 8 | Summary: ::as_str; Argument[self]; ReturnValue; value | -| 9 | Summary: ::parse; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | -| 10 | Summary: ::text; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | -| 11 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | -| 12 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value | nodes -| sqlx.rs:47:9:47:18 | arg_string | semmle.label | arg_string | -| sqlx.rs:47:22:47:35 | ...::args | semmle.label | ...::args | -| sqlx.rs:47:22:47:37 | ...::args(...) [element] | semmle.label | ...::args(...) [element] | -| sqlx.rs:47:22:47:44 | ... .nth(...) [Some] | semmle.label | ... .nth(...) [Some] | -| sqlx.rs:47:22:47:77 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) | -| sqlx.rs:48:9:48:21 | remote_string | semmle.label | remote_string | -| sqlx.rs:48:25:48:46 | ...::get | semmle.label | ...::get | -| sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | semmle.label | ...::get(...) [Ok] | -| sqlx.rs:48:25:48:78 | ... .unwrap() | semmle.label | ... .unwrap() | -| sqlx.rs:48:25:48:85 | ... .text() [Ok] | semmle.label | ... .text() [Ok] | -| sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) | -| sqlx.rs:49:9:49:21 | remote_number | semmle.label | remote_number | -| sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | semmle.label | remote_string.parse() [Ok] | -| sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) | -| sqlx.rs:52:9:52:20 | safe_query_3 | semmle.label | safe_query_3 | -| sqlx.rs:52:24:52:88 | res | semmle.label | res | -| sqlx.rs:52:32:52:87 | ...::format(...) | semmle.label | ...::format(...) | -| sqlx.rs:52:32:52:87 | ...::must_use(...) | semmle.label | ...::must_use(...) | -| sqlx.rs:52:32:52:87 | MacroExpr | semmle.label | MacroExpr | -| sqlx.rs:52:32:52:87 | { ... } | semmle.label | { ... } | -| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | semmle.label | unsafe_query_1 [&ref] | -| sqlx.rs:53:26:53:36 | &arg_string [&ref] | semmle.label | &arg_string [&ref] | -| sqlx.rs:53:27:53:36 | arg_string | semmle.label | arg_string | -| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | semmle.label | unsafe_query_2 [&ref] | -| sqlx.rs:54:26:54:39 | &remote_string [&ref] | semmle.label | &remote_string [&ref] | -| sqlx.rs:54:27:54:39 | remote_string | semmle.label | remote_string | -| sqlx.rs:77:25:77:36 | safe_query_3 | semmle.label | safe_query_3 | -| sqlx.rs:77:25:77:45 | safe_query_3.as_str() | semmle.label | safe_query_3.as_str() | -| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() | semmle.label | unsafe_query_1.as_str() | -| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() | semmle.label | unsafe_query_2.as_str() | subpaths +testFailures +| sqlx.rs:47:80:47:96 | //... | Missing result: Source=args1 | +| sqlx.rs:48:121:48:139 | //... | Missing result: Source=remote1 | +| sqlx.rs:77:71:77:129 | //... | Fixed spurious result: Alert[rust/sql-injection]=remote1 | +| sqlx.rs:78:73:78:117 | //... | Missing result: Alert[rust/sql-injection]=args1 | +| sqlx.rs:80:77:80:123 | //... | Missing result: Alert[rust/sql-injection]=remote1 | diff --git a/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected b/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected index e69de29bb2d1..9c3ebb3fe83a 100644 --- a/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected +++ b/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected @@ -0,0 +1,39 @@ +| sqlx.rs:75:71:75:83 | //... | Missing result: sql-sink | +| sqlx.rs:76:71:76:83 | //... | Missing result: sql-sink | +| sqlx.rs:77:71:77:129 | //... | Missing result: sql-sink | +| sqlx.rs:78:73:78:117 | //... | Missing result: sql-sink | +| sqlx.rs:80:77:80:123 | //... | Missing result: sql-sink | +| sqlx.rs:81:77:81:132 | //... | Missing result: sql-sink | +| sqlx.rs:82:77:82:132 | //... | Missing result: sql-sink | +| sqlx.rs:84:94:84:106 | //... | Missing result: sql-sink | +| sqlx.rs:85:92:85:104 | //... | Missing result: sql-sink | +| sqlx.rs:87:99:87:111 | //... | Missing result: sql-sink | +| sqlx.rs:88:99:88:111 | //... | Missing result: sql-sink | +| sqlx.rs:111:77:111:89 | //... | Missing result: sql-sink | +| sqlx.rs:113:83:113:138 | //... | Missing result: sql-sink | +| sqlx.rs:117:75:117:87 | //... | Missing result: sql-sink | +| sqlx.rs:118:99:118:111 | //... | Missing result: sql-sink | +| sqlx.rs:120:81:120:136 | //... | Missing result: sql-sink | +| sqlx.rs:121:104:121:116 | //... | Missing result: sql-sink | +| sqlx.rs:124:66:124:78 | //... | Missing result: sql-sink | +| sqlx.rs:125:90:125:102 | //... | Missing result: sql-sink | +| sqlx.rs:127:72:127:127 | //... | Missing result: sql-sink | +| sqlx.rs:128:95:128:107 | //... | Missing result: sql-sink | +| sqlx.rs:131:106:131:118 | //... | Missing result: sql-sink | +| sqlx.rs:133:130:133:142 | //... | Missing result: sql-sink | +| sqlx.rs:136:109:136:164 | //... | Missing result: sql-sink | +| sqlx.rs:137:132:137:144 | //... | Missing result: sql-sink | +| sqlx.rs:140:129:140:141 | //... | Missing result: sql-sink | +| sqlx.rs:142:153:142:165 | //... | Missing result: sql-sink | +| sqlx.rs:145:132:145:189 | //... | Missing result: sql-sink | +| sqlx.rs:146:155:146:167 | //... | Missing result: sql-sink | +| sqlx.rs:149:77:149:89 | //... | Missing result: sql-sink | +| sqlx.rs:150:101:150:113 | //... | Missing result: sql-sink | +| sqlx.rs:151:116:151:128 | //... | Missing result: sql-sink | +| sqlx.rs:153:83:153:138 | //... | Missing result: sql-sink | +| sqlx.rs:154:106:154:118 | //... | Missing result: sql-sink | +| sqlx.rs:155:121:155:133 | //... | Missing result: sql-sink | +| sqlx.rs:185:71:185:83 | //... | Missing result: sql-sink | +| sqlx.rs:186:95:186:107 | //... | Missing result: sql-sink | +| sqlx.rs:188:77:188:132 | //... | Missing result: sql-sink | +| sqlx.rs:189:100:189:112 | //... | Missing result: sql-sink | From 62b7d84638056b101dac70534d0da8211c1cea37 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 16 Jul 2025 16:36:42 +0100 Subject: [PATCH 3/6] Rust: Add Sqlx as MaD sinks instead. --- .../lib/codeql/rust/frameworks/sqlx.model.yml | 13 +++ .../security/CWE-089/SqlInjection.expected | 99 +++++++++++++++++-- .../security/CWE-089/SqlSinks.expected | 39 -------- 3 files changed, 106 insertions(+), 45 deletions(-) create mode 100644 rust/ql/lib/codeql/rust/frameworks/sqlx.model.yml diff --git a/rust/ql/lib/codeql/rust/frameworks/sqlx.model.yml b/rust/ql/lib/codeql/rust/frameworks/sqlx.model.yml new file mode 100644 index 000000000000..b3ca9d89299e --- /dev/null +++ b/rust/ql/lib/codeql/rust/frameworks/sqlx.model.yml @@ -0,0 +1,13 @@ +extensions: + - addsTo: + pack: codeql/rust-all + extensible: sinkModel + data: + - ["sqlx_core::query::query", "Argument[0]", "sql-injection", "manual"] + - ["sqlx_core::query_as::query_as", "Argument[0]", "sql-injection", "manual"] + - ["sqlx_core::query_with::query_with", "Argument[0]", "sql-injection", "manual"] + - ["sqlx_core::query_as_with::query_as_with", "Argument[0]", "sql-injection", "manual"] + - ["sqlx_core::query_scalar::query_scalar", "Argument[0]", "sql-injection", "manual"] + - ["sqlx_core::query_scalar_with::query_scalar_with", "Argument[0]", "sql-injection", "manual"] + - ["sqlx_core::raw_sql::raw_sql", "Argument[0]", "sql-injection", "manual"] + - ["sqlx_core::executor::Executor::execute", "Argument[0]", "sql-injection", "manual"] diff --git a/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected b/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected index 1570cd211c8f..cc00a44d9fc4 100644 --- a/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected +++ b/rust/ql/test/query-tests/security/CWE-089/SqlInjection.expected @@ -1,10 +1,97 @@ #select +| sqlx.rs:77:13:77:23 | ...::query | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:77:13:77:23 | ...::query | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | +| sqlx.rs:78:13:78:23 | ...::query | sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:78:13:78:23 | ...::query | This query depends on a $@. | sqlx.rs:47:22:47:35 | ...::args | user-provided value | +| sqlx.rs:80:17:80:27 | ...::query | sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:80:17:80:27 | ...::query | This query depends on a $@. | sqlx.rs:48:25:48:46 | ...::get | user-provided value | edges +| sqlx.rs:47:9:47:18 | arg_string | sqlx.rs:53:27:53:36 | arg_string | provenance | | +| sqlx.rs:47:22:47:35 | ...::args | sqlx.rs:47:22:47:37 | ...::args(...) [element] | provenance | Src:MaD:3 | +| sqlx.rs:47:22:47:37 | ...::args(...) [element] | sqlx.rs:47:22:47:44 | ... .nth(...) [Some] | provenance | MaD:4 | +| sqlx.rs:47:22:47:44 | ... .nth(...) [Some] | sqlx.rs:47:22:47:77 | ... .unwrap_or(...) | provenance | MaD:6 | +| sqlx.rs:47:22:47:77 | ... .unwrap_or(...) | sqlx.rs:47:9:47:18 | arg_string | provenance | | +| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | provenance | MaD:10 | +| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | provenance | MaD:10 | +| sqlx.rs:48:9:48:21 | remote_string | sqlx.rs:54:27:54:39 | remote_string | provenance | | +| sqlx.rs:48:25:48:46 | ...::get | sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | provenance | Src:MaD:2 | +| sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | sqlx.rs:48:25:48:78 | ... .unwrap() | provenance | MaD:7 | +| sqlx.rs:48:25:48:78 | ... .unwrap() | sqlx.rs:48:25:48:85 | ... .text() [Ok] | provenance | MaD:11 | +| sqlx.rs:48:25:48:85 | ... .text() [Ok] | sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | provenance | MaD:8 | +| sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | sqlx.rs:48:9:48:21 | remote_string | provenance | | +| sqlx.rs:49:9:49:21 | remote_number | sqlx.rs:52:32:52:87 | MacroExpr | provenance | | +| sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | provenance | MaD:8 | +| sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | sqlx.rs:49:9:49:21 | remote_number | provenance | | +| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:36 | safe_query_3 | provenance | | +| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:9 | +| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:5 | +| sqlx.rs:52:9:52:20 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() | provenance | MaD:9 | +| sqlx.rs:52:24:52:88 | res | sqlx.rs:52:32:52:87 | { ... } | provenance | | +| sqlx.rs:52:32:52:87 | ...::format(...) | sqlx.rs:52:24:52:88 | res | provenance | | +| sqlx.rs:52:32:52:87 | ...::must_use(...) | sqlx.rs:52:9:52:20 | safe_query_3 | provenance | | +| sqlx.rs:52:32:52:87 | MacroExpr | sqlx.rs:52:32:52:87 | ...::format(...) | provenance | MaD:12 | +| sqlx.rs:52:32:52:87 | { ... } | sqlx.rs:52:32:52:87 | ...::must_use(...) | provenance | MaD:13 | +| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | provenance | MaD:9 | +| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | provenance | MaD:5 | +| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | provenance | MaD:9 | +| sqlx.rs:53:26:53:36 | &arg_string [&ref] | sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | provenance | | +| sqlx.rs:53:27:53:36 | arg_string | sqlx.rs:53:26:53:36 | &arg_string [&ref] | provenance | | +| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | provenance | MaD:9 | +| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | provenance | MaD:5 | +| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | provenance | MaD:9 | +| sqlx.rs:54:26:54:39 | &remote_string [&ref] | sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | provenance | | +| sqlx.rs:54:27:54:39 | remote_string | sqlx.rs:54:26:54:39 | &remote_string [&ref] | provenance | | +| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:9 | +| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:5 | +| sqlx.rs:77:25:77:36 | safe_query_3 | sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | provenance | MaD:9 | +| sqlx.rs:77:25:77:45 | safe_query_3.as_str() | sqlx.rs:77:13:77:23 | ...::query | provenance | MaD:1 Sink:MaD:1 | +| sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | sqlx.rs:77:13:77:23 | ...::query | provenance | MaD:1 Sink:MaD:1 | +| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | sqlx.rs:78:13:78:23 | ...::query | provenance | MaD:1 Sink:MaD:1 | +| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | sqlx.rs:80:17:80:27 | ...::query | provenance | MaD:1 Sink:MaD:1 | +models +| 1 | Sink: sqlx_core::query::query; Argument[0]; sql-injection | +| 2 | Source: reqwest::blocking::get; ReturnValue.Field[core::result::Result::Ok(0)]; remote | +| 3 | Source: std::env::args; ReturnValue.Element; commandargs | +| 4 | Summary: <_ as core::iter::traits::iterator::Iterator>::nth; Argument[self].Element; ReturnValue.Field[core::option::Option::Some(0)]; value | +| 5 | Summary: ::as_str; Argument[self]; ReturnValue; value | +| 6 | Summary: ::unwrap_or; Argument[self].Field[core::option::Option::Some(0)]; ReturnValue; value | +| 7 | Summary: ::unwrap; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | +| 8 | Summary: ::unwrap_or; Argument[self].Field[core::result::Result::Ok(0)]; ReturnValue; value | +| 9 | Summary: ::as_str; Argument[self]; ReturnValue; value | +| 10 | Summary: ::parse; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | +| 11 | Summary: ::text; Argument[self]; ReturnValue.Field[core::result::Result::Ok(0)]; taint | +| 12 | Summary: alloc::fmt::format; Argument[0]; ReturnValue; taint | +| 13 | Summary: core::hint::must_use; Argument[0]; ReturnValue; value | nodes +| sqlx.rs:47:9:47:18 | arg_string | semmle.label | arg_string | +| sqlx.rs:47:22:47:35 | ...::args | semmle.label | ...::args | +| sqlx.rs:47:22:47:37 | ...::args(...) [element] | semmle.label | ...::args(...) [element] | +| sqlx.rs:47:22:47:44 | ... .nth(...) [Some] | semmle.label | ... .nth(...) [Some] | +| sqlx.rs:47:22:47:77 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) | +| sqlx.rs:48:9:48:21 | remote_string | semmle.label | remote_string | +| sqlx.rs:48:25:48:46 | ...::get | semmle.label | ...::get | +| sqlx.rs:48:25:48:69 | ...::get(...) [Ok] | semmle.label | ...::get(...) [Ok] | +| sqlx.rs:48:25:48:78 | ... .unwrap() | semmle.label | ... .unwrap() | +| sqlx.rs:48:25:48:85 | ... .text() [Ok] | semmle.label | ... .text() [Ok] | +| sqlx.rs:48:25:48:118 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) | +| sqlx.rs:49:9:49:21 | remote_number | semmle.label | remote_number | +| sqlx.rs:49:25:49:52 | remote_string.parse() [Ok] | semmle.label | remote_string.parse() [Ok] | +| sqlx.rs:49:25:49:65 | ... .unwrap_or(...) | semmle.label | ... .unwrap_or(...) | +| sqlx.rs:52:9:52:20 | safe_query_3 | semmle.label | safe_query_3 | +| sqlx.rs:52:24:52:88 | res | semmle.label | res | +| sqlx.rs:52:32:52:87 | ...::format(...) | semmle.label | ...::format(...) | +| sqlx.rs:52:32:52:87 | ...::must_use(...) | semmle.label | ...::must_use(...) | +| sqlx.rs:52:32:52:87 | MacroExpr | semmle.label | MacroExpr | +| sqlx.rs:52:32:52:87 | { ... } | semmle.label | { ... } | +| sqlx.rs:53:9:53:22 | unsafe_query_1 [&ref] | semmle.label | unsafe_query_1 [&ref] | +| sqlx.rs:53:26:53:36 | &arg_string [&ref] | semmle.label | &arg_string [&ref] | +| sqlx.rs:53:27:53:36 | arg_string | semmle.label | arg_string | +| sqlx.rs:54:9:54:22 | unsafe_query_2 [&ref] | semmle.label | unsafe_query_2 [&ref] | +| sqlx.rs:54:26:54:39 | &remote_string [&ref] | semmle.label | &remote_string [&ref] | +| sqlx.rs:54:27:54:39 | remote_string | semmle.label | remote_string | +| sqlx.rs:77:13:77:23 | ...::query | semmle.label | ...::query | +| sqlx.rs:77:25:77:36 | safe_query_3 | semmle.label | safe_query_3 | +| sqlx.rs:77:25:77:45 | safe_query_3.as_str() | semmle.label | safe_query_3.as_str() | +| sqlx.rs:77:25:77:45 | safe_query_3.as_str() [&ref] | semmle.label | safe_query_3.as_str() [&ref] | +| sqlx.rs:78:13:78:23 | ...::query | semmle.label | ...::query | +| sqlx.rs:78:25:78:47 | unsafe_query_1.as_str() [&ref] | semmle.label | unsafe_query_1.as_str() [&ref] | +| sqlx.rs:80:17:80:27 | ...::query | semmle.label | ...::query | +| sqlx.rs:80:29:80:51 | unsafe_query_2.as_str() [&ref] | semmle.label | unsafe_query_2.as_str() [&ref] | subpaths -testFailures -| sqlx.rs:47:80:47:96 | //... | Missing result: Source=args1 | -| sqlx.rs:48:121:48:139 | //... | Missing result: Source=remote1 | -| sqlx.rs:77:71:77:129 | //... | Fixed spurious result: Alert[rust/sql-injection]=remote1 | -| sqlx.rs:78:73:78:117 | //... | Missing result: Alert[rust/sql-injection]=args1 | -| sqlx.rs:80:77:80:123 | //... | Missing result: Alert[rust/sql-injection]=remote1 | diff --git a/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected b/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected index 9c3ebb3fe83a..e69de29bb2d1 100644 --- a/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected +++ b/rust/ql/test/query-tests/security/CWE-089/SqlSinks.expected @@ -1,39 +0,0 @@ -| sqlx.rs:75:71:75:83 | //... | Missing result: sql-sink | -| sqlx.rs:76:71:76:83 | //... | Missing result: sql-sink | -| sqlx.rs:77:71:77:129 | //... | Missing result: sql-sink | -| sqlx.rs:78:73:78:117 | //... | Missing result: sql-sink | -| sqlx.rs:80:77:80:123 | //... | Missing result: sql-sink | -| sqlx.rs:81:77:81:132 | //... | Missing result: sql-sink | -| sqlx.rs:82:77:82:132 | //... | Missing result: sql-sink | -| sqlx.rs:84:94:84:106 | //... | Missing result: sql-sink | -| sqlx.rs:85:92:85:104 | //... | Missing result: sql-sink | -| sqlx.rs:87:99:87:111 | //... | Missing result: sql-sink | -| sqlx.rs:88:99:88:111 | //... | Missing result: sql-sink | -| sqlx.rs:111:77:111:89 | //... | Missing result: sql-sink | -| sqlx.rs:113:83:113:138 | //... | Missing result: sql-sink | -| sqlx.rs:117:75:117:87 | //... | Missing result: sql-sink | -| sqlx.rs:118:99:118:111 | //... | Missing result: sql-sink | -| sqlx.rs:120:81:120:136 | //... | Missing result: sql-sink | -| sqlx.rs:121:104:121:116 | //... | Missing result: sql-sink | -| sqlx.rs:124:66:124:78 | //... | Missing result: sql-sink | -| sqlx.rs:125:90:125:102 | //... | Missing result: sql-sink | -| sqlx.rs:127:72:127:127 | //... | Missing result: sql-sink | -| sqlx.rs:128:95:128:107 | //... | Missing result: sql-sink | -| sqlx.rs:131:106:131:118 | //... | Missing result: sql-sink | -| sqlx.rs:133:130:133:142 | //... | Missing result: sql-sink | -| sqlx.rs:136:109:136:164 | //... | Missing result: sql-sink | -| sqlx.rs:137:132:137:144 | //... | Missing result: sql-sink | -| sqlx.rs:140:129:140:141 | //... | Missing result: sql-sink | -| sqlx.rs:142:153:142:165 | //... | Missing result: sql-sink | -| sqlx.rs:145:132:145:189 | //... | Missing result: sql-sink | -| sqlx.rs:146:155:146:167 | //... | Missing result: sql-sink | -| sqlx.rs:149:77:149:89 | //... | Missing result: sql-sink | -| sqlx.rs:150:101:150:113 | //... | Missing result: sql-sink | -| sqlx.rs:151:116:151:128 | //... | Missing result: sql-sink | -| sqlx.rs:153:83:153:138 | //... | Missing result: sql-sink | -| sqlx.rs:154:106:154:118 | //... | Missing result: sql-sink | -| sqlx.rs:155:121:155:133 | //... | Missing result: sql-sink | -| sqlx.rs:185:71:185:83 | //... | Missing result: sql-sink | -| sqlx.rs:186:95:186:107 | //... | Missing result: sql-sink | -| sqlx.rs:188:77:188:132 | //... | Missing result: sql-sink | -| sqlx.rs:189:100:189:112 | //... | Missing result: sql-sink | From 944fd2aa11768f80b75bb88bcbf1fba74bab2e21 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 16 Jul 2025 17:06:52 +0100 Subject: [PATCH 4/6] Rust: Add explicit types in some (not all) of the test cases. --- rust/ql/test/query-tests/security/CWE-089/sqlx.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/ql/test/query-tests/security/CWE-089/sqlx.rs b/rust/ql/test/query-tests/security/CWE-089/sqlx.rs index ef51b1af42b7..8e1afa9f0e8f 100644 --- a/rust/ql/test/query-tests/security/CWE-089/sqlx.rs +++ b/rust/ql/test/query-tests/security/CWE-089/sqlx.rs @@ -39,8 +39,8 @@ use sqlx::Executor; async fn test_sqlx_mysql(url: &str, enable_remote: bool) -> Result<(), sqlx::Error> { // connect through a MySQL connection pool - let pool = sqlx::mysql::MySqlPool::connect(url).await?; - let mut conn = pool.acquire().await?; + let pool: sqlx::Pool = sqlx::mysql::MySqlPool::connect(url).await?; + let mut conn: sqlx::pool::PoolConnection = pool.acquire().await?; // construct queries (with extra variants) let const_string = String::from("Alice"); @@ -61,7 +61,7 @@ async fn test_sqlx_mysql(url: &str, enable_remote: bool) -> Result<(), sqlx::Err let prepared_query_1 = String::from("SELECT * FROM people WHERE firstname=?"); // (prepared arguments are safe) // direct execution - let _ = conn.execute(safe_query_1.as_str()).await?; // $ MISSING: sql-sink + let _: sqlx::mysql::MySqlQueryResult = conn.execute(safe_query_1.as_str()).await?; // $ MISSING: sql-sink let _ = conn.execute(safe_query_2.as_str()).await?; // $ MISSING: sql-sink let _ = conn.execute(safe_query_3.as_str()).await?; // $ MISSING: sql-sink let _ = conn.execute(unsafe_query_1.as_str()).await?; // $ MISSING: sql-sink Alert[rust/sql-injection]=args1 From 69064b7f7fc1981568ea1e163b9da8d12188e780 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 17 Jul 2025 12:20:34 +0100 Subject: [PATCH 5/6] Rust: Update the model. --- rust/ql/lib/codeql/rust/frameworks/sqlx.model.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/frameworks/sqlx.model.yml b/rust/ql/lib/codeql/rust/frameworks/sqlx.model.yml index b3ca9d89299e..efc6022b0c55 100644 --- a/rust/ql/lib/codeql/rust/frameworks/sqlx.model.yml +++ b/rust/ql/lib/codeql/rust/frameworks/sqlx.model.yml @@ -10,4 +10,4 @@ extensions: - ["sqlx_core::query_scalar::query_scalar", "Argument[0]", "sql-injection", "manual"] - ["sqlx_core::query_scalar_with::query_scalar_with", "Argument[0]", "sql-injection", "manual"] - ["sqlx_core::raw_sql::raw_sql", "Argument[0]", "sql-injection", "manual"] - - ["sqlx_core::executor::Executor::execute", "Argument[0]", "sql-injection", "manual"] + - ["<_ as sqlx_core::executor::Executor>::execute", "Argument[0]", "sql-injection", "manual"] From 27bea335080d3b9fa7371e7a608e87997ab70399 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 17 Jul 2025 12:44:31 +0100 Subject: [PATCH 6/6] Rust: Accept consistency check change. --- .../CWE-089/CONSISTENCY/PathResolutionConsistency.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/test/query-tests/security/CWE-089/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/query-tests/security/CWE-089/CONSISTENCY/PathResolutionConsistency.expected index d8fcd1ec9f06..b5d4fea346d2 100644 --- a/rust/ql/test/query-tests/security/CWE-089/CONSISTENCY/PathResolutionConsistency.expected +++ b/rust/ql/test/query-tests/security/CWE-089/CONSISTENCY/PathResolutionConsistency.expected @@ -6,7 +6,7 @@ multipleCallTargets | sqlx.rs:51:24:51:77 | ...::from(...) | | sqlx.rs:55:26:55:79 | ...::from(...) | | sqlx.rs:61:28:61:81 | ...::from(...) | -| sqlx.rs:64:26:64:46 | safe_query_1.as_str() | +| sqlx.rs:64:57:64:77 | safe_query_1.as_str() | | sqlx.rs:65:26:65:46 | safe_query_2.as_str() | | sqlx.rs:66:26:66:46 | safe_query_3.as_str() | | sqlx.rs:67:26:67:48 | unsafe_query_1.as_str() | pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy