From cc4ff6ba380a570b5f37ce4ca4851a1c48d0033a Mon Sep 17 00:00:00 2001 From: Sakshis Date: Thu, 12 Dec 2024 04:48:50 +0000 Subject: [PATCH 1/3] hardcoded-password-rust --- .../rust/security/hardcoded-password-rust.yml | 312 +++++++++ .../hardcoded-password-rust-snapshot.yml | 654 ++++++++++++++++++ tests/rust/hardcoded-password-rust-test.yml | 54 ++ 3 files changed, 1020 insertions(+) create mode 100644 rules/rust/security/hardcoded-password-rust.yml create mode 100644 tests/__snapshots__/hardcoded-password-rust-snapshot.yml create mode 100644 tests/rust/hardcoded-password-rust-test.yml diff --git a/rules/rust/security/hardcoded-password-rust.yml b/rules/rust/security/hardcoded-password-rust.yml new file mode 100644 index 00000000..40b6a31c --- /dev/null +++ b/rules/rust/security/hardcoded-password-rust.yml @@ -0,0 +1,312 @@ +id: 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 + [OWASP A07:2021]: Identification and Authentication Failures + [REFERENCES] + - https://docs.rs/sqlx/latest/sqlx/ + - https://owasp.org/Top10/A07_2021-Identification_and_Authentication_Failures +utils: + match_call_expression_MySqlConnectOptions: + kind: call_expression + all: + - has: + stopBy: end + kind: field_expression + has: + kind: call_expression + all: + - has: + kind: scoped_identifier + all: + - has: + kind: identifier + field: path + regex: "^MySqlConnectOptions$" + - has: + kind: identifier + field: name + regex: "^new$" + - has: + kind: arguments + - has: + kind: arguments + has: + kind: string_literal + has: + kind: string_content + + inside: + kind: field_expression + has: + kind: field_identifier + inside: + kind: call_expression + has: + kind: arguments + inside: + kind: field_expression + has: + kind: field_identifier + inside: + kind: call_expression + has: + kind: arguments + inside: + kind: await_expression + inside: + kind: try_expression + inside: + kind: let_declaration + inside: + stopBy: end + kind: function_item + follows: + stopBy: end + kind: use_declaration + has: + kind: scoped_use_list + field: argument + all: + - has: + kind: scoped_identifier + field: path + all: + - has: + kind: identifier + field: path + regex: "^sqlx$" + - has: + kind: identifier + field: name + regex: "^mysql$" + - has: + kind: use_list + field: list + all: + - has: + kind: identifier + regex: "^MySqlConnectOptions$" + - has: + kind: identifier + regex: "^MySqlConnection$" + - has: + kind: identifier + regex: "^MySqlPool$" + - has: + kind: identifier + regex: "^MySqlSslMode$" + match_call_expression_PgConnectOptions: + kind: call_expression + all: + - has: + kind: field_expression + has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: end + kind: scoped_identifier + all: + - has: + stopBy: end + kind: identifier + field: path + regex: "^PgConnectOptions$" + - has: + stopBy: end + field: name + kind: identifier + regex: "^new$" + - has: + kind: arguments + - has: + kind: arguments + has: + stopBy: end + kind: string_literal + has: + stopBy: end + kind: string_content + inside: + kind: field_expression + has: + kind: field_identifier + inside: + kind: call_expression + has: + kind: arguments + inside: + kind: field_expression + has: + kind: field_identifier + inside: + kind: call_expression + has: + kind: arguments + inside: + kind: await_expression + inside: + kind: try_expression + inside: + kind: let_declaration + inside: + stopBy: end + kind: function_item + follows: + stopBy: end + kind: use_declaration + has: + kind: scoped_use_list + field: argument + all: + - has: + kind: scoped_identifier + field: path + all: + - has: + kind: identifier + field: path + regex: "^sqlx$" + - has: + kind: identifier + field: name + regex: "^postgres$" + - has: + kind: use_list + field: list + all: + - has: + kind: identifier + regex: "^PgConnectOptions$" + - has: + kind: identifier + regex: "^PgConnection$" + - has: + kind: identifier + regex: "^PgPool$" + - has: + kind: identifier + regex: "^PgSslMode$" + match_call_expression_PgConnectOptions_above_instance: + kind: call_expression + all: + - has: + kind: field_expression + all: + - has: + kind: call_expression + has: + kind: field_expression + all: + - has: + stopBy: end + kind: identifier + field: value + pattern: $PG + - has: + kind: field_identifier + - has: + kind: field_identifier + - has: + kind: arguments + has: + stopBy: end + kind: string_literal + has: + stopBy: end + kind: string_content + inside: + kind: field_expression + inside: + kind: call_expression + has: + kind: arguments + inside: + kind: field_expression + has: + kind: field_identifier + inside: + kind: call_expression + has: + kind: arguments + inside: + kind: await_expression + inside: + kind: try_expression + inside: + kind: let_declaration + follows: + stopBy: end + kind: let_declaration + all: + - has: + kind: identifier + pattern: $PG + - has: + kind: call_expression + all: + - has: + kind: scoped_identifier + all: + - has: + kind: identifier + field: path + regex: "^PgConnectOptions$" + - has: + kind: identifier + field: name + regex: "^new$" + - has: + kind: arguments + inside: + stopBy: end + kind: function_item + follows: + stopBy: end + kind: use_declaration + has: + kind: scoped_use_list + all: + - has: + kind: scoped_identifier + field: path + all: + - has: + kind: identifier + field: path + regex: "^sqlx$" + - has: + kind: identifier + field: name + regex: "^postgres$" + - has: + kind: use_list + field: list + all: + - has: + kind: identifier + regex: "^PgConnectOptions$" + - has: + kind: identifier + regex: "^PgConnection$" + - has: + kind: identifier + regex: "^PgPool$" + - has: + kind: identifier + regex: "^PgSslMode$" +rule: + any: + - matches: match_call_expression_MySqlConnectOptions + - matches: match_call_expression_PgConnectOptions + - matches: match_call_expression_PgConnectOptions_above_instance diff --git a/tests/__snapshots__/hardcoded-password-rust-snapshot.yml b/tests/__snapshots__/hardcoded-password-rust-snapshot.yml new file mode 100644 index 00000000..10937984 --- /dev/null +++ b/tests/__snapshots__/hardcoded-password-rust-snapshot.yml @@ -0,0 +1,654 @@ +id: hardcoded-password-rust +snapshots: + ? | + use sqlx::mysql::{MySqlConnectOptions, MySqlConnection, MySqlPool, MySqlSslMode}; + async fn test1() -> Result<(), sqlx::Error> { + let conn = MySqlConnectOptions::new() + .host("localhost") + .username("root") + .password("password") + .database("db") + .connect().await?; + use_connection(conn); + Ok(()) + } + : labels: + - source: |- + MySqlConnectOptions::new() + .host("localhost") + .username("root") + .password("password") + style: primary + start: 139 + end: 224 + - source: MySqlConnectOptions + style: secondary + start: 139 + end: 158 + - source: new + style: secondary + start: 160 + end: 163 + - source: MySqlConnectOptions::new + style: secondary + start: 139 + end: 163 + - source: () + style: secondary + start: 163 + end: 165 + - source: MySqlConnectOptions::new() + style: secondary + start: 139 + end: 165 + - source: |- + MySqlConnectOptions::new() + .host + style: secondary + start: 139 + end: 171 + - source: password + style: secondary + start: 214 + end: 222 + - source: '"password"' + style: secondary + start: 213 + end: 223 + - source: ("password") + style: secondary + start: 212 + end: 224 + - source: sqlx + style: secondary + start: 4 + end: 8 + - source: mysql + style: secondary + start: 10 + end: 15 + - source: sqlx::mysql + style: secondary + start: 4 + end: 15 + - source: MySqlConnectOptions + style: secondary + start: 18 + end: 37 + - source: MySqlConnection + style: secondary + start: 39 + end: 54 + - source: MySqlPool + style: secondary + start: 56 + end: 65 + - source: MySqlSslMode + style: secondary + start: 67 + end: 79 + - source: '{MySqlConnectOptions, MySqlConnection, MySqlPool, MySqlSslMode}' + style: secondary + start: 17 + end: 80 + - source: sqlx::mysql::{MySqlConnectOptions, MySqlConnection, MySqlPool, MySqlSslMode} + style: secondary + start: 4 + end: 80 + - source: use sqlx::mysql::{MySqlConnectOptions, MySqlConnection, MySqlPool, MySqlSslMode}; + style: secondary + start: 0 + end: 81 + - source: |- + async fn test1() -> Result<(), sqlx::Error> { + let conn = MySqlConnectOptions::new() + .host("localhost") + .username("root") + .password("password") + .database("db") + .connect().await?; + use_connection(conn); + Ok(()) + } + style: secondary + start: 82 + end: 292 + - source: |- + let conn = MySqlConnectOptions::new() + .host("localhost") + .username("root") + .password("password") + .database("db") + .connect().await?; + style: secondary + start: 128 + end: 259 + - source: |- + MySqlConnectOptions::new() + .host("localhost") + .username("root") + .password("password") + .database("db") + .connect().await? + style: secondary + start: 139 + end: 258 + - source: |- + MySqlConnectOptions::new() + .host("localhost") + .username("root") + .password("password") + .database("db") + .connect().await + style: secondary + start: 139 + end: 257 + - source: () + style: secondary + start: 249 + end: 251 + - source: |- + MySqlConnectOptions::new() + .host("localhost") + .username("root") + .password("password") + .database("db") + .connect() + style: secondary + start: 139 + end: 251 + - source: connect + style: secondary + start: 242 + end: 249 + - source: |- + MySqlConnectOptions::new() + .host("localhost") + .username("root") + .password("password") + .database("db") + .connect + style: secondary + start: 139 + end: 249 + - source: ("db") + style: secondary + start: 234 + end: 240 + - source: |- + MySqlConnectOptions::new() + .host("localhost") + .username("root") + .password("password") + .database("db") + style: secondary + start: 139 + end: 240 + - source: database + style: secondary + start: 226 + end: 234 + - source: |- + MySqlConnectOptions::new() + .host("localhost") + .username("root") + .password("password") + .database + style: secondary + start: 139 + end: 234 + ? | + use sqlx::postgres::{PgConnectOptions, PgConnection, PgPool, PgSslMode}; + async fn test2() -> Result<(), sqlx::Error> { + let conn = PgConnectOptions::new() + .host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect() + .await?; + use_connection(conn); + Ok(()) + } + : labels: + - source: |- + PgConnectOptions::new() + .host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + style: primary + start: 130 + end: 240 + - source: PgConnectOptions + style: secondary + start: 130 + end: 146 + - source: new + style: secondary + start: 148 + end: 151 + - source: PgConnectOptions::new + style: secondary + start: 130 + end: 151 + - source: ("secret-user") + style: secondary + start: 196 + end: 211 + - source: |- + PgConnectOptions::new() + .host("secret-host") + .port(2525) + .username("secret-user") + style: secondary + start: 130 + end: 211 + - source: |- + PgConnectOptions::new() + .host("secret-host") + .port(2525) + .username("secret-user") + .password + style: secondary + start: 130 + end: 221 + - source: secret-password + style: secondary + start: 223 + end: 238 + - source: '"secret-password"' + style: secondary + start: 222 + end: 239 + - source: ("secret-password") + style: secondary + start: 221 + end: 240 + - source: sqlx + style: secondary + start: 4 + end: 8 + - source: postgres + style: secondary + start: 10 + end: 18 + - source: sqlx::postgres + style: secondary + start: 4 + end: 18 + - source: PgConnectOptions + style: secondary + start: 21 + end: 37 + - source: PgConnection + style: secondary + start: 39 + end: 51 + - source: PgPool + style: secondary + start: 53 + end: 59 + - source: PgSslMode + style: secondary + start: 61 + end: 70 + - source: '{PgConnectOptions, PgConnection, PgPool, PgSslMode}' + style: secondary + start: 20 + end: 71 + - source: sqlx::postgres::{PgConnectOptions, PgConnection, PgPool, PgSslMode} + style: secondary + start: 4 + end: 71 + - source: use sqlx::postgres::{PgConnectOptions, PgConnection, PgPool, PgSslMode}; + style: secondary + start: 0 + end: 72 + - source: |- + async fn test2() -> Result<(), sqlx::Error> { + let conn = PgConnectOptions::new() + .host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect() + .await?; + use_connection(conn); + Ok(()) + } + style: secondary + start: 73 + end: 321 + - source: |- + let conn = PgConnectOptions::new() + .host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect() + .await?; + style: secondary + start: 119 + end: 290 + - source: |- + PgConnectOptions::new() + .host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect() + .await? + style: secondary + start: 130 + end: 289 + - source: |- + PgConnectOptions::new() + .host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect() + .await + style: secondary + start: 130 + end: 288 + - source: () + style: secondary + start: 279 + end: 281 + - source: |- + PgConnectOptions::new() + .host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect() + style: secondary + start: 130 + end: 281 + - source: connect + style: secondary + start: 272 + end: 279 + - source: |- + PgConnectOptions::new() + .host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect + style: secondary + start: 130 + end: 279 + - source: (PgSslMode::Require) + style: secondary + start: 250 + end: 270 + - source: |- + PgConnectOptions::new() + .host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + style: secondary + start: 130 + end: 270 + - source: ssl_mode + style: secondary + start: 242 + end: 250 + - source: |- + PgConnectOptions::new() + .host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode + style: secondary + start: 130 + end: 250 + ? | + use sqlx::postgres::{PgConnectOptions, PgConnection, PgPool, PgSslMode}; + async fn test3() -> Result<(), sqlx::Error> { + let pg = PgConnectOptions::new(); + let conn = pg.host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect() + .await?; + use_connection(conn); + Ok(()) + } + : labels: + - source: |- + pg.host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + style: primary + start: 164 + end: 252 + - source: pg + style: secondary + start: 164 + end: 166 + - source: username + style: secondary + start: 200 + end: 208 + - source: |- + pg.host("secret-host") + .port(2525) + .username + style: secondary + start: 164 + end: 208 + - source: |- + pg.host("secret-host") + .port(2525) + .username("secret-user") + style: secondary + start: 164 + end: 223 + - source: password + style: secondary + start: 225 + end: 233 + - source: |- + pg.host("secret-host") + .port(2525) + .username("secret-user") + .password + style: secondary + start: 164 + end: 233 + - source: secret-password + style: secondary + start: 235 + end: 250 + - source: '"secret-password"' + style: secondary + start: 234 + end: 251 + - source: ("secret-password") + style: secondary + start: 233 + end: 252 + - source: pg + style: secondary + start: 123 + end: 125 + - source: PgConnectOptions + style: secondary + start: 128 + end: 144 + - source: new + style: secondary + start: 146 + end: 149 + - source: PgConnectOptions::new + style: secondary + start: 128 + end: 149 + - source: () + style: secondary + start: 149 + end: 151 + - source: PgConnectOptions::new() + style: secondary + start: 128 + end: 151 + - source: sqlx + style: secondary + start: 4 + end: 8 + - source: postgres + style: secondary + start: 10 + end: 18 + - source: sqlx::postgres + style: secondary + start: 4 + end: 18 + - source: PgConnectOptions + style: secondary + start: 21 + end: 37 + - source: PgConnection + style: secondary + start: 39 + end: 51 + - source: PgPool + style: secondary + start: 53 + end: 59 + - source: PgSslMode + style: secondary + start: 61 + end: 70 + - source: '{PgConnectOptions, PgConnection, PgPool, PgSslMode}' + style: secondary + start: 20 + end: 71 + - source: sqlx::postgres::{PgConnectOptions, PgConnection, PgPool, PgSslMode} + style: secondary + start: 4 + end: 71 + - source: use sqlx::postgres::{PgConnectOptions, PgConnection, PgPool, PgSslMode}; + style: secondary + start: 0 + end: 72 + - source: |- + async fn test3() -> Result<(), sqlx::Error> { + let pg = PgConnectOptions::new(); + let conn = pg.host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect() + .await?; + use_connection(conn); + Ok(()) + } + style: secondary + start: 73 + end: 333 + - source: let pg = PgConnectOptions::new(); + style: secondary + start: 119 + end: 152 + - source: |- + let conn = pg.host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect() + .await?; + style: secondary + start: 153 + end: 302 + - source: |- + pg.host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect() + .await? + style: secondary + start: 164 + end: 301 + - source: |- + pg.host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect() + .await + style: secondary + start: 164 + end: 300 + - source: () + style: secondary + start: 291 + end: 293 + - source: |- + pg.host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect() + style: secondary + start: 164 + end: 293 + - source: connect + style: secondary + start: 284 + end: 291 + - source: |- + pg.host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect + style: secondary + start: 164 + end: 291 + - source: (PgSslMode::Require) + style: secondary + start: 262 + end: 282 + - source: |- + pg.host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + style: secondary + start: 164 + end: 282 + - source: |- + pg.host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode + style: secondary + start: 164 + end: 262 diff --git a/tests/rust/hardcoded-password-rust-test.yml b/tests/rust/hardcoded-password-rust-test.yml new file mode 100644 index 00000000..68e467b2 --- /dev/null +++ b/tests/rust/hardcoded-password-rust-test.yml @@ -0,0 +1,54 @@ +id: hardcoded-password-rust +valid: + - | + async fn ok_test1() -> Result<(), sqlx::Error> { + let conn = MySqlConnectOptions::new() + .host("localhost") + .username("root") + .password(env!("pwd")) + .database("db") + .connect().await?; + use_connection(conn); + Ok(()) + } +invalid: + - | + use sqlx::mysql::{MySqlConnectOptions, MySqlConnection, MySqlPool, MySqlSslMode}; + async fn test1() -> Result<(), sqlx::Error> { + let conn = MySqlConnectOptions::new() + .host("localhost") + .username("root") + .password("password") + .database("db") + .connect().await?; + use_connection(conn); + Ok(()) + } + - | + use sqlx::postgres::{PgConnectOptions, PgConnection, PgPool, PgSslMode}; + async fn test2() -> Result<(), sqlx::Error> { + let conn = PgConnectOptions::new() + .host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect() + .await?; + use_connection(conn); + Ok(()) + } + - | + use sqlx::postgres::{PgConnectOptions, PgConnection, PgPool, PgSslMode}; + async fn test3() -> Result<(), sqlx::Error> { + let pg = PgConnectOptions::new(); + let conn = pg.host("secret-host") + .port(2525) + .username("secret-user") + .password("secret-password") + .ssl_mode(PgSslMode::Require) + .connect() + .await?; + use_connection(conn); + Ok(()) + } From fd36816fedcebb9fd0627484e7f3920fe13aa9ef Mon Sep 17 00:00:00 2001 From: Sakshis Date: Thu, 12 Dec 2024 04:51:51 +0000 Subject: [PATCH 2/3] ruby-cassandra-hardcoded-secret-ruby --- .../ruby-cassandra-hardcoded-secret-ruby.yml | 127 ++++++++++++++++++ ...ssandra-hardcoded-secret-ruby-snapshot.yml | 120 +++++++++++++++++ ...y-cassandra-hardcoded-secret-ruby-test.yml | 12 ++ 3 files changed, 259 insertions(+) create mode 100644 rules/ruby/security/ruby-cassandra-hardcoded-secret-ruby.yml create mode 100644 tests/__snapshots__/ruby-cassandra-hardcoded-secret-ruby-snapshot.yml create mode 100644 tests/ruby/ruby-cassandra-hardcoded-secret-ruby-test.yml diff --git a/rules/ruby/security/ruby-cassandra-hardcoded-secret-ruby.yml b/rules/ruby/security/ruby-cassandra-hardcoded-secret-ruby.yml new file mode 100644 index 00000000..41b1e39b --- /dev/null +++ b/rules/ruby/security/ruby-cassandra-hardcoded-secret-ruby.yml @@ -0,0 +1,127 @@ +id: ruby-cassandra-hardcoded-secret-ruby +language: ruby +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. Use + environment variables to securely provide credentials and other secrets or + retrieve them from a secure vault or Hardware Security Module (HSM). +note: >- + [CWE-798] Use of Hard-coded Credentials. + [REFERENCES] + - https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html +utils: + Cassandra.cluster(): + # Cassandra.cluster(..., password: "", ...) + kind: call + all: + - has: + stopBy: neighbor + kind: constant + regex: ^Cassandra$ + - has: + stopBy: neighbor + regex: ^.$ + - has: + stopBy: neighbor + kind: identifier + regex: ^cluster$ + - has: + stopBy: neighbor + kind: argument_list + has: + stopBy: end + kind: pair + all: + - has: + stopBy: neighbor + kind: hash_key_symbol + regex: ^password$ + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_content + - inside: + stopBy: end + kind: program + has: + stopBy: end + kind: call + pattern: require 'cassandra' + Cassandra.cluster()_with_instance: + # Cassandra.cluster(..., password: "", ...) + kind: call + all: + - has: + stopBy: neighbor + kind: constant + regex: ^Cassandra$ + - has: + stopBy: neighbor + regex: ^.$ + - has: + stopBy: neighbor + kind: identifier + regex: ^cluster$ + - has: + stopBy: neighbor + kind: argument_list + has: + stopBy: end + kind: pair + all: + - has: + stopBy: neighbor + kind: hash_key_symbol + regex: ^password$ + - has: + stopBy: neighbor + kind: identifier + pattern: $SECRET + - inside: + stopBy: end + kind: program + has: + stopBy: end + kind: call + pattern: require 'cassandra' + - any: + - follows: + stopBy: end + kind: assignment + all: + - has: + stopBy: neighbor + kind: identifier + pattern: $SECRET + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_content + - inside: + stopBy: end + kind: assignment + follows: + stopBy: end + kind: assignment + all: + - has: + stopBy: neighbor + kind: identifier + pattern: $SECRET + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_content +rule: + kind: call + any: + - matches: Cassandra.cluster() + - matches: Cassandra.cluster()_with_instance diff --git a/tests/__snapshots__/ruby-cassandra-hardcoded-secret-ruby-snapshot.yml b/tests/__snapshots__/ruby-cassandra-hardcoded-secret-ruby-snapshot.yml new file mode 100644 index 00000000..ccac9aab --- /dev/null +++ b/tests/__snapshots__/ruby-cassandra-hardcoded-secret-ruby-snapshot.yml @@ -0,0 +1,120 @@ +id: ruby-cassandra-hardcoded-secret-ruby +snapshots: + ? | + require 'cassandra' + cluster = Cassandra.cluster( username: 'user',password: 'password') + : labels: + - source: 'Cassandra.cluster( username: ''user'',password: ''password'')' + style: primary + start: 30 + end: 87 + - source: Cassandra + style: secondary + start: 30 + end: 39 + - source: . + style: secondary + start: 39 + end: 40 + - source: cluster + style: secondary + start: 40 + end: 47 + - source: password + style: secondary + start: 66 + end: 74 + - source: password + style: secondary + start: 77 + end: 85 + - source: '''password''' + style: secondary + start: 76 + end: 86 + - source: 'password: ''password''' + style: secondary + start: 66 + end: 86 + - source: '( username: ''user'',password: ''password'')' + style: secondary + start: 47 + end: 87 + - source: require 'cassandra' + style: secondary + start: 0 + end: 19 + - source: | + require 'cassandra' + cluster = Cassandra.cluster( username: 'user',password: 'password') + style: secondary + start: 0 + end: 88 + ? | + require 'cassandra' + password = 'password' + cluster = Cassandra.cluster( username: 'user',password: password) + : labels: + - source: 'Cassandra.cluster( username: ''user'',password: password)' + style: primary + start: 52 + end: 107 + - source: Cassandra + style: secondary + start: 52 + end: 61 + - source: . + style: secondary + start: 61 + end: 62 + - source: cluster + style: secondary + start: 62 + end: 69 + - source: password + style: secondary + start: 88 + end: 96 + - source: password + style: secondary + start: 98 + end: 106 + - source: 'password: password' + style: secondary + start: 88 + end: 106 + - source: '( username: ''user'',password: password)' + style: secondary + start: 69 + end: 107 + - source: require 'cassandra' + style: secondary + start: 0 + end: 19 + - source: | + require 'cassandra' + password = 'password' + cluster = Cassandra.cluster( username: 'user',password: password) + style: secondary + start: 0 + end: 108 + - source: password + style: secondary + start: 20 + end: 28 + - source: password + style: secondary + start: 32 + end: 40 + - source: '''password''' + style: secondary + start: 31 + end: 41 + - source: password = 'password' + style: secondary + start: 20 + end: 41 + - source: 'cluster = Cassandra.cluster( username: ''user'',password: password)' + style: secondary + start: 42 + end: 107 diff --git a/tests/ruby/ruby-cassandra-hardcoded-secret-ruby-test.yml b/tests/ruby/ruby-cassandra-hardcoded-secret-ruby-test.yml new file mode 100644 index 00000000..6b68c674 --- /dev/null +++ b/tests/ruby/ruby-cassandra-hardcoded-secret-ruby-test.yml @@ -0,0 +1,12 @@ +id: ruby-cassandra-hardcoded-secret-ruby +valid: + - | + cluster = Cassandra.cluster(username: 'user',password: '') +invalid: + - | + require 'cassandra' + cluster = Cassandra.cluster( username: 'user',password: 'password') + - | + require 'cassandra' + password = 'password' + cluster = Cassandra.cluster( username: 'user',password: password) From 77415f818a18dd7a27bf740836c497d091869ec6 Mon Sep 17 00:00:00 2001 From: Sakshis Date: Thu, 12 Dec 2024 04:54:34 +0000 Subject: [PATCH 3/3] insufficient-rsa-key-size-ruby --- .../insufficient-rsa-key-size-ruby.yml | 91 +++++++++++++++++++ ...nsufficient-rsa-key-size-ruby-snapshot.yml | 29 ++++++ .../insufficient-rsa-key-size-ruby-test.yml | 7 ++ 3 files changed, 127 insertions(+) create mode 100644 rules/ruby/security/insufficient-rsa-key-size-ruby.yml create mode 100644 tests/__snapshots__/insufficient-rsa-key-size-ruby-snapshot.yml create mode 100644 tests/ruby/insufficient-rsa-key-size-ruby-test.yml diff --git a/rules/ruby/security/insufficient-rsa-key-size-ruby.yml b/rules/ruby/security/insufficient-rsa-key-size-ruby.yml new file mode 100644 index 00000000..5510e724 --- /dev/null +++ b/rules/ruby/security/insufficient-rsa-key-size-ruby.yml @@ -0,0 +1,91 @@ +id: insufficient-rsa-key-size-ruby +language: ruby +severity: warning +message: >- + The RSA key size $SIZE is insufficent by NIST standards. It is + recommended to use a key length of 2048 or higher. +note: >- + [CWE-326] Inadequate Encryption Strength. + [REFERENCES] + - https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57Pt3r1.pdf +utils: + OpenSSL::PKey::RSA.generate($SIZE,...): + # OpenSSL::PKey::RSA.generate($SIZE,...) + kind: call + all: + - has: + stopBy: neighbor + kind: scope_resolution + regex: ^OpenSSL::PKey::RSA$ + - has: + stopBy: neighbor + regex: ^.$ + - has: + stopBy: neighbor + kind: identifier + regex: ^new|generate$ + - has: + stopBy: neighbor + kind: argument_list + any: + - has: + stopBy: neighbor + kind: integer + pattern: $KEY + - has: + stopBy: neighbor + kind: float + pattern: $KEY + - has: + stopBy: neighbor + kind: unary + all: + - has: + stopBy: neighbor + regex: ^-$ + - any: + - has: + stopBy: neighbor + kind: float + pattern: $KEY + - has: + stopBy: neighbor + kind: integer + pattern: $KEY + OpenSSL::PKey::RSA.new($ASSIGN, ...): + # $ASSIGN = $SIZE + # OpenSSL::PKey::RSA.new($ASSIGN, ...) + kind: call + all: + - has: + stopBy: neighbor + kind: scope_resolution + regex: ^OpenSSL::PKey::RSA$ + - has: + stopBy: neighbor + regex: ^.$ + - has: + stopBy: neighbor + kind: identifier + regex: ^new|generate$ + - has: + stopBy: neighbor + kind: argument_list + has: + stopBy: neighbor + pattern: $BIT + - inside: + stopBy: end + kind: class + has: + stopBy: end + kind: assignment + pattern: $BIT = $KEY +rule: + kind: call + any: + - matches: OpenSSL::PKey::RSA.generate($SIZE,...) + - matches: OpenSSL::PKey::RSA.new($ASSIGN, ...) +constraints: + KEY: + regex: '^(-?(0|[1-9][0-9]?|[1-9][0-9]{2}|1[0-9]{3}|20[0-3][0-9]|204[0-7])(\.[0-9]+)?|0|-[1-9][0-9]*|-[1-9][0-9]{2,}|-1[0-9]{3}|-20[0-3][0-9]|-204[0-7])$' diff --git a/tests/__snapshots__/insufficient-rsa-key-size-ruby-snapshot.yml b/tests/__snapshots__/insufficient-rsa-key-size-ruby-snapshot.yml new file mode 100644 index 00000000..6a44747d --- /dev/null +++ b/tests/__snapshots__/insufficient-rsa-key-size-ruby-snapshot.yml @@ -0,0 +1,29 @@ +id: insufficient-rsa-key-size-ruby +snapshots: + ? | + key = OpenSSL::PKey::RSA.new(204) + : labels: + - source: OpenSSL::PKey::RSA.new(204) + style: primary + start: 6 + end: 33 + - source: OpenSSL::PKey::RSA + style: secondary + start: 6 + end: 24 + - source: . + style: secondary + start: 24 + end: 25 + - source: new + style: secondary + start: 25 + end: 28 + - source: '204' + style: secondary + start: 29 + end: 32 + - source: (204) + style: secondary + start: 28 + end: 33 diff --git a/tests/ruby/insufficient-rsa-key-size-ruby-test.yml b/tests/ruby/insufficient-rsa-key-size-ruby-test.yml new file mode 100644 index 00000000..798e95a2 --- /dev/null +++ b/tests/ruby/insufficient-rsa-key-size-ruby-test.yml @@ -0,0 +1,7 @@ +id: insufficient-rsa-key-size-ruby +valid: + - | + key = OpenSSL::PKey::RSA.new(2048) +invalid: + - | + key = OpenSSL::PKey::RSA.new(204)