From 405df3810f5da223ce5dc265eb6915498f98100c Mon Sep 17 00:00:00 2001 From: ESS-ENN Date: Thu, 17 Oct 2024 17:52:21 +0530 Subject: [PATCH 1/3] tokio-postgres-empty-password-rust --- .../tokio-postgres-empty-password-rust.yml | 124 ++++++++++++++++++ ...-postgres-empty-password-rust-snapshot.yml | 100 ++++++++++++++ ...okio-postgres-empty-password-rust-test.yml | 28 ++++ 3 files changed, 252 insertions(+) create mode 100644 rules/rust/security/tokio-postgres-empty-password-rust.yml create mode 100644 tests/__snapshots__/tokio-postgres-empty-password-rust-snapshot.yml create mode 100644 tests/rust/tokio-postgres-empty-password-rust-test.yml diff --git a/rules/rust/security/tokio-postgres-empty-password-rust.yml b/rules/rust/security/tokio-postgres-empty-password-rust.yml new file mode 100644 index 00000000..2cf734cf --- /dev/null +++ b/rules/rust/security/tokio-postgres-empty-password-rust.yml @@ -0,0 +1,124 @@ +id: tokio-postgres-empty-password-rust +language: rust +severity: warning +message: >- + The application uses an empty credential. This can lead to unauthorized + access by either an internal or external malicious actor. It is + recommended to rotate the secret and retrieve them from a secure secret + vault or Hardware Security Module (HSM), alternatively environment + variables can be used if allowed by your company policy. +note: >- + [CWE-287] Improper Authentication. + [REFERENCES] + - https://docs.rs/tokio-postgres/latest/tokio_postgres/ + - https://owasp.org/Top10/A07_2021-Identification_and_Authentication_Failures +utils: + MATCH_PATTERN_WITH_INSTANCE: + kind: call_expression + all: + - has: + stopBy: neighbor + kind: field_expression + all: + - has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: neighbor + kind: field_expression + all: + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: field_expression + all: + - has: + stopBy: neighbor + kind: identifier + pattern: $C + - has: + stopBy: neighbor + kind: arguments + - has: + stopBy: neighbor + kind: field_identifier + - has: + stopBy: neighbor + kind: arguments + - has: + stopBy: neighbor + kind: field_identifier + regex: "^password$" + - has: + stopBy: neighbor + kind: arguments + regex: \(\s*\"\"\s*\) + - inside: + stopBy: end + kind: expression_statement + follows: + stopBy: end + kind: let_declaration + all: + - has: + stopBy: neighbor + kind: identifier + pattern: $C + - has: + stopBy: neighbor + kind: call_expression + pattern: tokio_postgres::Config::new() + + MATCH_PATTERN_DIRECTLY: + kind: call_expression + all: + - has: + stopBy: neighbor + kind: field_expression + all: + - has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: neighbor + kind: field_expression + all: + - has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: neighbor + kind: field_expression + has: + stopBy: neighbor + kind: call_expression + pattern: tokio_postgres::Config::new() + - has: + stopBy: neighbor + kind: arguments + - has: + stopBy: neighbor + kind: field_identifier + - has: + stopBy: neighbor + kind: arguments + - has: + stopBy: neighbor + kind: field_identifier + regex: "^password$" + - has: + stopBy: neighbor + kind: arguments + regex: \(\s*\"\"\s*\) + +rule: + kind: call_expression + any: + - matches: MATCH_PATTERN_WITH_INSTANCE + - matches: MATCH_PATTERN_DIRECTLY diff --git a/tests/__snapshots__/tokio-postgres-empty-password-rust-snapshot.yml b/tests/__snapshots__/tokio-postgres-empty-password-rust-snapshot.yml new file mode 100644 index 00000000..9a478d93 --- /dev/null +++ b/tests/__snapshots__/tokio-postgres-empty-password-rust-snapshot.yml @@ -0,0 +1,100 @@ +id: tokio-postgres-empty-password-rust +snapshots: + ? | + async fn test1() -> Result<(), anyhow::Error> { + let mut config = tokio_postgres::Config::new(); + config + .host(std::env::var("HOST").expect("set HOST")) + .user(std::env::var("USER").expect("set USER")) + .password("") + .port(std::env::var("PORT").expect("set PORT")); + Ok(()) + } + : labels: + - source: |- + config + .host(std::env::var("HOST").expect("set HOST")) + .user(std::env::var("USER").expect("set USER")) + .password("") + style: primary + start: 96 + end: 212 + - source: config + style: secondary + start: 96 + end: 102 + - source: |- + config + .host + style: secondary + start: 96 + end: 108 + - source: (std::env::var("HOST").expect("set HOST")) + style: secondary + start: 108 + end: 150 + - source: |- + config + .host(std::env::var("HOST").expect("set HOST")) + style: secondary + start: 96 + end: 150 + - source: user + style: secondary + start: 152 + end: 156 + - source: |- + config + .host(std::env::var("HOST").expect("set HOST")) + .user + style: secondary + start: 96 + end: 156 + - source: (std::env::var("USER").expect("set USER")) + style: secondary + start: 156 + end: 198 + - source: |- + config + .host(std::env::var("HOST").expect("set HOST")) + .user(std::env::var("USER").expect("set USER")) + style: secondary + start: 96 + end: 198 + - source: password + style: secondary + start: 200 + end: 208 + - source: |- + config + .host(std::env::var("HOST").expect("set HOST")) + .user(std::env::var("USER").expect("set USER")) + .password + style: secondary + start: 96 + end: 208 + - source: ("") + style: secondary + start: 208 + end: 212 + - source: config + style: secondary + start: 56 + end: 62 + - source: tokio_postgres::Config::new() + style: secondary + start: 65 + end: 94 + - source: let mut config = tokio_postgres::Config::new(); + style: secondary + start: 48 + end: 95 + - source: |- + config + .host(std::env::var("HOST").expect("set HOST")) + .user(std::env::var("USER").expect("set USER")) + .password("") + .port(std::env::var("PORT").expect("set PORT")); + style: secondary + start: 96 + end: 261 diff --git a/tests/rust/tokio-postgres-empty-password-rust-test.yml b/tests/rust/tokio-postgres-empty-password-rust-test.yml new file mode 100644 index 00000000..0ee6176c --- /dev/null +++ b/tests/rust/tokio-postgres-empty-password-rust-test.yml @@ -0,0 +1,28 @@ +id: tokio-postgres-empty-password-rust +valid: + - | + let mut config = tokio_postgres::Config::new(); + config + .host(std::env::var("HOST").expect("set HOST")) + .user(std::env::var("USER").expect("set USER")) + .password(std::env::var("USER").expect("set USER")) + .port(std::env::var("PORT").expect("set PORT")); + let (client, connection) = config.connect(NoTls).await?; + tokio::spawn(async move { + if let Err(e) = connection.await { + tracing::error!("postgres db connection error: {}", e); + } + }); + Ok(()) + } +invalid: + - | + async fn test1() -> Result<(), anyhow::Error> { + let mut config = tokio_postgres::Config::new(); + config + .host(std::env::var("HOST").expect("set HOST")) + .user(std::env::var("USER").expect("set USER")) + .password("") + .port(std::env::var("PORT").expect("set PORT")); + Ok(()) + } From 2ca58b66745246503b4a89c938e333556987578c Mon Sep 17 00:00:00 2001 From: ESS-ENN Date: Thu, 17 Oct 2024 17:53:19 +0530 Subject: [PATCH 2/3] tokio-postgres-hardcoded-password-rust --- ...tokio-postgres-hardcoded-password-rust.yml | 135 ++++++++++++++++++ ...tgres-hardcoded-password-rust-snapshot.yml | 91 ++++++++++++ ...-postgres-hardcoded-password-rust-test.yml | 27 ++++ 3 files changed, 253 insertions(+) create mode 100644 rules/rust/security/tokio-postgres-hardcoded-password-rust.yml create mode 100644 tests/__snapshots__/tokio-postgres-hardcoded-password-rust-snapshot.yml create mode 100644 tests/rust/tokio-postgres-hardcoded-password-rust-test.yml diff --git a/rules/rust/security/tokio-postgres-hardcoded-password-rust.yml b/rules/rust/security/tokio-postgres-hardcoded-password-rust.yml new file mode 100644 index 00000000..62254013 --- /dev/null +++ b/rules/rust/security/tokio-postgres-hardcoded-password-rust.yml @@ -0,0 +1,135 @@ +id: tokio-postgres-hardcoded-password-rust +language: rust +severity: warning +message: >- + A secret is hard-coded in the application. Secrets stored in source + code, such as credentials, identifiers, and other types of sensitive data, + can be leaked and used by internal or external malicious actors. It is + recommended to rotate the secret and retrieve them from a secure secret + vault or Hardware Security Module (HSM), alternatively environment + variables can be used if allowed by your company policy. +note: >- + [CWE-798] Use of Hard-coded Credentials. + [REFERENCES] + - https://docs.rs/tokio-postgres/latest/tokio_postgres/ + - https://owasp.org/Top10/A07_2021-Identification_and_Authentication_Failures +utils: + MATCH_PATTERN_WITH_INSTANCE: + kind: call_expression + all: + - has: + stopBy: neighbor + kind: field_expression + all: + - has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: neighbor + kind: field_expression + all: + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: field_expression + all: + - has: + stopBy: neighbor + kind: identifier + pattern: $C + - has: + stopBy: neighbor + kind: arguments + - has: + stopBy: neighbor + kind: field_identifier + - has: + stopBy: neighbor + kind: arguments + - has: + stopBy: neighbor + kind: field_identifier + regex: "^password$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string_literal + has: + stopBy: neighbor + kind: string_content + - inside: + stopBy: end + kind: expression_statement + follows: + stopBy: end + kind: let_declaration + all: + - has: + stopBy: neighbor + kind: identifier + pattern: $C + - has: + stopBy: neighbor + kind: call_expression + pattern: tokio_postgres::Config::new() + + MATCH_PATTERN_DIRECTLY: + kind: call_expression + all: + - has: + stopBy: neighbor + kind: field_expression + all: + - has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: neighbor + kind: field_expression + all: + - has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: neighbor + kind: field_expression + has: + stopBy: neighbor + kind: call_expression + pattern: tokio_postgres::Config::new() + - has: + stopBy: neighbor + kind: arguments + - has: + stopBy: neighbor + kind: field_identifier + - has: + stopBy: neighbor + kind: arguments + - has: + stopBy: neighbor + kind: field_identifier + regex: "^password$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string_literal + has: + stopBy: neighbor + kind: string_content + +rule: + kind: call_expression + any: + - matches: MATCH_PATTERN_WITH_INSTANCE + - matches: MATCH_PATTERN_DIRECTLY diff --git a/tests/__snapshots__/tokio-postgres-hardcoded-password-rust-snapshot.yml b/tests/__snapshots__/tokio-postgres-hardcoded-password-rust-snapshot.yml new file mode 100644 index 00000000..ba49829e --- /dev/null +++ b/tests/__snapshots__/tokio-postgres-hardcoded-password-rust-snapshot.yml @@ -0,0 +1,91 @@ +id: tokio-postgres-hardcoded-password-rust +snapshots: + ? | + async fn test2() -> Result<(), anyhow::Error> { + let (client, connection) = tokio_postgres::Config::new() + .host(shard_host_name.as_str()) + .user("postgres") + .password("postgres") + .dbname("moray") + .keepalives_idle(std::time::Duration::from_secs(30)) + .connect(NoTls) + .await + .map_err(|e| { + error!(log, "failed to connect to {}: {}", &shard_host_name, e); + Error::new(ErrorKind::Other, e) + })?; + : labels: + - source: |- + tokio_postgres::Config::new() + .host(shard_host_name.as_str()) + .user("postgres") + .password("postgres") + style: primary + start: 75 + end: 176 + - source: tokio_postgres::Config::new() + style: secondary + start: 75 + end: 104 + - source: |- + tokio_postgres::Config::new() + .host + style: secondary + start: 75 + end: 110 + - source: (shard_host_name.as_str()) + style: secondary + start: 110 + end: 136 + - source: |- + tokio_postgres::Config::new() + .host(shard_host_name.as_str()) + style: secondary + start: 75 + end: 136 + - source: user + style: secondary + start: 138 + end: 142 + - source: |- + tokio_postgres::Config::new() + .host(shard_host_name.as_str()) + .user + style: secondary + start: 75 + end: 142 + - source: ("postgres") + style: secondary + start: 142 + end: 154 + - source: |- + tokio_postgres::Config::new() + .host(shard_host_name.as_str()) + .user("postgres") + style: secondary + start: 75 + end: 154 + - source: password + style: secondary + start: 156 + end: 164 + - source: |- + tokio_postgres::Config::new() + .host(shard_host_name.as_str()) + .user("postgres") + .password + style: secondary + start: 75 + end: 164 + - source: postgres + style: secondary + start: 166 + end: 174 + - source: '"postgres"' + style: secondary + start: 165 + end: 175 + - source: ("postgres") + style: secondary + start: 164 + end: 176 diff --git a/tests/rust/tokio-postgres-hardcoded-password-rust-test.yml b/tests/rust/tokio-postgres-hardcoded-password-rust-test.yml new file mode 100644 index 00000000..935d067d --- /dev/null +++ b/tests/rust/tokio-postgres-hardcoded-password-rust-test.yml @@ -0,0 +1,27 @@ +id: tokio-postgres-hardcoded-password-rust +valid: + - | + async fn test1() -> Result<(), anyhow::Error> { + let mut config = tokio_postgres::Config::new(); + config + .host(std::env::var("HOST").expect("set HOST")) + .user(std::env::var("USER").expect("set USER")) + .password("") + .port(std::env::var("PORT").expect("set PORT")); + Ok(()) + } +invalid: + - | + async fn test2() -> Result<(), anyhow::Error> { + let (client, connection) = tokio_postgres::Config::new() + .host(shard_host_name.as_str()) + .user("postgres") + .password("postgres") + .dbname("moray") + .keepalives_idle(std::time::Duration::from_secs(30)) + .connect(NoTls) + .await + .map_err(|e| { + error!(log, "failed to connect to {}: {}", &shard_host_name, e); + Error::new(ErrorKind::Other, e) + })?; From 9080e1dcaec57eae851405e3e49d3b6885b770d9 Mon Sep 17 00:00:00 2001 From: ESS-ENN Date: Fri, 18 Oct 2024 17:56:47 +0530 Subject: [PATCH 3/3] changes in tokio-postgres-empty-password-rust rule --- tests/rust/tokio-postgres-empty-password-rust-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rust/tokio-postgres-empty-password-rust-test.yml b/tests/rust/tokio-postgres-empty-password-rust-test.yml index 0ee6176c..a8909265 100644 --- a/tests/rust/tokio-postgres-empty-password-rust-test.yml +++ b/tests/rust/tokio-postgres-empty-password-rust-test.yml @@ -5,7 +5,7 @@ valid: config .host(std::env::var("HOST").expect("set HOST")) .user(std::env::var("USER").expect("set USER")) - .password(std::env::var("USER").expect("set USER")) + .password(std::env::var("PASSWORD").expect("set PASSWORD")) .port(std::env::var("PORT").expect("set PORT")); let (client, connection) = config.connect(NoTls).await?; tokio::spawn(async move {