diff --git a/assets/queries/common/passwords_and_secrets/regex_rules.json b/assets/queries/common/passwords_and_secrets/regex_rules.json index 4620f0285cd..e1787e9b3f5 100644 --- a/assets/queries/common/passwords_and_secrets/regex_rules.json +++ b/assets/queries/common/passwords_and_secrets/regex_rules.json @@ -40,6 +40,10 @@ { "description": "Allow password retrieved from ARM parameters", "regex": "(?i)['\"]?password['\"]?\\s*[:=]\\s*['\"]?\\s*,\\s*parameters\\(['\"]([a-zA-Z][a-zA-Z0-9_-]*)['\"]['\"]?\\)" + }, + { + "description": "Avoiding Proto File fields", + "regex": "(?i)password\\s*=\\s*(0|[1-9][0-9]{0,8})\\s*(\\[.+=.+\\]\\s*;|\\[.+=.+,\\s*$|\\[\\s*$|;)" } ], "specialMask": "(?i)['\"]?password['\"]?\\s*[:=]\\s*" @@ -83,6 +87,10 @@ { "description": "Allow secrets retrieved from Bicep getSecret built in function", "regex": "(?i)['\"]?secret[_]?(key|value)?['\"]?\\s*(:|=)\\s*[a-zA-Z]*\\.getSecret\\(\\s*[\"']([A-Za-z0-9/~^_!@#&%(){};=?*+-<>,:;[\\]%$]+)[\"']\\)" + }, + { + "description": "Avoiding Proto File fields", + "regex": "(?i)secret[_]?(key|value)?\\s*=\\s*(0|[1-9][0-9]{0,8})\\s*(\\[.+=.+\\]\\s*;|\\[.+=.+,\\s*$|\\[\\s*$|;)" } ], "specialMask": "(?i)['\"]?secret[_]?(key)?['\"]?\\s*(:|=)\\s*" @@ -279,6 +287,10 @@ { "description": "Avoid Docker Compose secrets paths", "regex": "(?i)['\"]?private[_]?key['\"]?\\s*[:=]\\s*['\"]?/run/secrets/\\w+['\"]?" + }, + { + "description": "Avoiding Proto File fields", + "regex": "(?i)private[_]?key\\s*=\\s*(0|[1-9][0-9]{0,8})\\s*(\\[.+=.+\\]\\s*;|\\[.+=.+,\\s*$|\\[\\s*$|;)" } ] }, @@ -350,6 +362,10 @@ { "description": "Avoiding Run After Triggers (if written in conformity with best practices)", "regex": "(?i)['\"](HTTP|Parse_JSON|Try|Catch)_-_(Get_)?OAuth_Token['\"]?\\s*[:=]\\s*['\"]?([[A-Za-z0-9/~^_!@&%()=?*+-]+)['\"]?" + }, + { + "description": "Avoiding Proto File fields", + "regex": "(?i)token(_)?(key)?\\s*=\\s*(0|[1-9][0-9]{0,8})\\s*(\\[.+=.+\\]\\s*;|\\[.+=.+,\\s*$|\\[\\s*$|;)" } ], "specialMask": "(?i)['\"]?token(_)?(key)?['\"]?\\s*[:=]\\s*" @@ -373,6 +389,10 @@ { "description": "Avoiding CLoudformation KeyName", "regex": "['\"]?EncryptionKey['\"]?\\s*[:=]\\s*['\"]?([A-Za-z0-9/~^_!@&%()=?*+-.]+)['\"]?" + }, + { + "description": "Avoiding Proto File fields", + "regex": "(?i)encryption[_]?key\\s*=\\s*(0|[1-9][0-9]{0,8})\\s*(\\[.+=.+\\]\\s*;|\\[.+=.+,\\s*$|\\[\\s*$|;)" } ], "specialMask": "(?i)['\"]?encryption[_]?key['\"]?\\s*[:=]\\s*" diff --git a/assets/queries/common/passwords_and_secrets/test/negative60.proto b/assets/queries/common/passwords_and_secrets/test/negative60.proto new file mode 100644 index 00000000000..2830123b0f7 --- /dev/null +++ b/assets/queries/common/passwords_and_secrets/test/negative60.proto @@ -0,0 +1,141 @@ +// "Generic Token" - baee238e-1921-4801-9c3f-79ae1d7b2cbc - "Avoiding Proto File fields" allow-rule-test - #1 +// "Generic Private Key" - 2f665079-c383-4b33-896e-88268c1fa258 - "Avoiding Proto File fields" allow rule test - #2 +// "Encryption Key" - 9fb1cd65-7a07-4531-9bcf-47589d0f82d6 - "Avoiding Proto File fields" allow-rule-test - #3 +// "Generic Password" - 487f4be7-3fd9-4506-a07a-eae252180c08 - "Avoiding Proto File fields" allow rule test - #4 +// "Generic Secret" - 3e2d3b2f-c22a-4df1-9cc6-a7a0aebb0c99 - "Avoiding Proto File fields" allow rule test - #5 +// Global allow rule - a88baa34-e2ad-44ea-ad6f-8cac87bc7c71 - "Avoiding Boolean's" allow-rule-test - #6 +syntax = "proto3"; +package com.example.security_test.v1; +import "google/protobuf/wrappers.proto"; +option go_package = "github.com/CheckmarxDev/router-audit/gen/presets/v1;presets"; + +// Scenario 1 - Simple attribution +message SampleMessageNegative { + google.protobuf.StringValue refresh_token = 536870911; // if value is larger - out of range error "Field numbers cannot be greater than 536870911." - Generic Token #1 + google.protobuf.StringValue sonar_token = 39;google.protobuf.StringValue codecov_token = 40;// trailing comment test - Generic Token #1 + + google.protobuf.StringValue access_token= 111111111; // Generic Token #1 + google.protobuf.StringValue api_token = 7 ; // Generic Token #1 + google.protobuf.StringValue token = 8; // Generic Token #1 + google.protobuf.StringValue aws_session_token = 9; // Generic Token #1 + google.protobuf.StringValue twilio_auth_token = 21; // Generic Token #1 + google.protobuf.StringValue test_token_ = 122 ; // Generic Token #1 + + google.protobuf.StringValue jwt_private_key = 25; // Generic Private Key #2 + google.protobuf.StringValue ssh_private_key = 26; // Generic Private Key #2 + google.protobuf.StringValue tls_private_key = 27; // Generic Private Key #2 + google.protobuf.StringValue ca_private_key = 28 ; // Generic Private Key #2 + google.protobuf.StringValue private_key = 5; // Generic Private Key #2 + + google.protobuf.StringValue encryption_key = 22; // Encryption Key #3 + google.protobuf.StringValue data_encryption_key= 23 ; // Encryption Key #3 + google.protobuf.StringValue key_encryption_key=24; // Encryption Key #3 + + google.protobuf.StringValue registry_password = 10421; // Generic Password #4 + google.protobuf.StringValue artifactory_password = 10731 ; // Generic Password #4 + google.protobuf.StringValue nexus_password = 10853; // Generic Password #4 + string password = 64114; // Generic Password #4 + + string secret_key = 123456789; // Generic Secret #5 + string secret_value = 123456790; // Generic Secret #5 + string secret = 123456791; // Generic Secret #5 +} + +// Scenario 2 - Attribution with options +message SampleMessageNegative2 { + google.protobuf.StringValue next_page_token = 5 [(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"test\""}]; // Generic Token #1 + google.protobuf.StringValue next_next_page_token = 6[(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"test\""} ] ; // Generic Token #1 + google.protobuf.StringValue api_token = 7 [(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"jira_api_token\""}]; // Generic Token #1 + + google.protobuf.StringValue next_page_private_key = 8 [(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"test\""}]; // Generic Private Key #2 + google.protobuf.StringValue next_next_page_private_key = 8[(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"test\""} ] ; // Generic Private Key #2 + google.protobuf.StringValue api_private_key = 10 [(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"jira_api_private_key\""}]; // Generic Private Key #2 + + google.protobuf.StringValue next_page_encryption_key = 11 [(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"test\""}]; // Encryption Key #3 + google.protobuf.StringValue next_next_page_encryption_key = 12[(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"test\""} ] ; // Encryption Key #3 + google.protobuf.StringValue api_encryption_key = 13 [(grpc.gateway.protoc_gen_openapiv3.options.openapiv3_field) = {example: "\"jira_api_encryption_key\""}]; // Encryption Key #3 + + google.protobuf.StringValue next_page_password = 14 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "\"test\""}]; // Generic Password #4 + google.protobuf.StringValue next_next_page_password = 15[(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "\"test\""} ] ; // Generic Password #4 + google.protobuf.StringValue api_password = 16 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "\"jira_api_password\""}]; // Generic Password #4 + + google.protobuf.StringValue next_page_secret = 17[(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "\"test\""}]; // Generic Secret #5 + google.protobuf.StringValue next_next_page_secret = 18[(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "\"test\""} ] ; // Generic Secret #5 + google.protobuf.StringValue api_secret = 19[(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {example: "\"jira_api_secret\""}]; // Generic Secret #5 +} + +message MyOptions { + string file_only_option_token = 1 [targets = TARGET_TYPE_FILE]; // Generic Token #1 + int message_and_enum_option_token = 2 [targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_ENUM]; // Generic Token #1 (line above) + + string file_only_option_private_key = 11 [targets = TARGET_TYPE_FILE]; // Generic Private Key #2 + int message_and_enum_option_private_key = 21 [targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_ENUM]; // Generic Private Key #2 (line above) + + string file_only_option_encryption_key = 13 [targets = TARGET_TYPE_FILE]; // Encryption Key #3 + int message_and_enum_option_encryption_key = 23 [targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_ENUM]; // Encryption Key #3 (line above) + + string file_only_option_password = 14 [targets = TARGET_TYPE_FILE]; // Generic Password #4 + int message_and_enum_option_password = 24 [targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_ENUM]; // Generic Password #4 (line above) + + string file_only_option_secret = 15[targets = TARGET_TYPE_FILE]; // Generic Secret #5 + int message_and_enum_option_secret = 25[targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_ENUM]; // Generic Secret #5 (line above) + + int B_message_and_enum_option_token = 2 [targets = TARGET_TYPE_MESSAGE, targets = TARGET_TYPE_ENUM]; // Generic Token #1 + + int B_message_and_enum_option_private_key = 211 [targets = TARGET_TYPE_MESSAGE, targets = TARGET_TYPE_ENUM]; // Generic Private Key #2 + + int B_message_and_enum_option_encryption_key = 232 [targets = TARGET_TYPE_MESSAGE, targets = TARGET_TYPE_ENUM]; // Encryption Key #3 + + int B_message_and_enum_option_password = 243 [targets = TARGET_TYPE_MESSAGE, targets = TARGET_TYPE_ENUM]; // Generic Password #4 + + int B_message_and_enum_option_secret = 254[targets = TARGET_TYPE_MESSAGE, targets = TARGET_TYPE_ENUM]; // Generic Secret #5 +} + +message Not_a_Token { + string token = 1 [json_name = "tk"]; // Generic Token #1 + string private_key = 4 [json_name = "pk"]; // Generic Private Key #2 + string encryption_key = 3 [json_name = "ek"]; // Encryption Key #3 + string password = 2 [json_name = "ps"]; // Generic Password #4 + string secret = 5[json_name = "se"]; // Generic Secret #5 +} + +// Scenario 3 - Enum attributions +enum Corpus { + DATA_A_UNSPECIFIED_TOKEN = 0 [ deprecated = true ] ; // Generic Token #1 + DATA_A_TOKEN = 11[deprecated=true] ; // Generic Token #1 & #6 + DATA_A_PRIVATE_KEY = 2[deprecated = false]; // Generic Private Key #2 & #6 + DATA_A_ENCRYPTION_KEY = 3[deprecated = true]; // Encryption Key #3 & #6 + DATA_A_PASSWORD = 1234 [deprecated = false]; // Generic Password #4 & #6 + DATA_A_SECRET = 5[deprecated=true]; // Generic Secret #5 & #6 + + // Generic Token #1 (line below) + DATA_B_TOKEN = 2[ + (string_name) = "display_value" + ]; + // Generic Private Key #2 (line below) + DATA_B_PRIVATE_KEY = 2 [ + (string_name) = "display_value" + ]; + // Encryption Key #3 (line below) + DATA_B_ENCRYPTION_KEY = 2 [ + (string_name) = "display_value" + ]; + // Generic Password #4 (line below) + DATA_B_PASSWORD = 28970[ + (string_name) = "display_value" + ]; + // Generic Secret #5 (line below) + DATA_B_SECRET = 123456789[ + (string_name) = "display_value" + ]; +} + +// Scenario 4 - Generic keywords in "reserved" +enum EnumAllowingAlias { + reserved "password", "api_token", "private_key", "encryption_key", "exposed_secret"; + option end_of_sample = false;}enum InlineMessageFormat{option end_of_sample = true;} \ No newline at end of file diff --git a/assets/queries/common/passwords_and_secrets/test/positive56.proto b/assets/queries/common/passwords_and_secrets/test/positive56.proto new file mode 100644 index 00000000000..8904d103b5a --- /dev/null +++ b/assets/queries/common/passwords_and_secrets/test/positive56.proto @@ -0,0 +1,38 @@ +// "Generic Password" - 487f4be7-3fd9-4506-a07a-eae252180c08 - positive-test - #1 +// "Generic Secret" - 3e2d3b2f-c22a-4df1-9cc6-a7a0aebb0c99 - positive-test - #2 +// "Generic Token" - baee238e-1921-4801-9c3f-79ae1d7b2cbc - positive-test - #3 +// "Generic Private Key" - 2f665079-c383-4b33-896e-88268c1fa258 - positive-test - #4 +// "Encryption Key" - 9fb1cd65-7a07-4531-9bcf-47589d0f82d6 - positive-test - #5 +// "Generic Password" - 487f4be7-3fd9-4506-a07a-eae252180c08 - "Avoiding Proto File fields" allow rule test - #6 +// "Generic Token" - baee238e-1921-4801-9c3f-79ae1d7b2cbc - "Avoiding Proto File fields" allow-rule-test - #7 +// "Encryption Key" - 9fb1cd65-7a07-4531-9bcf-47589d0f82d6 - "Avoiding Proto File fields" allow-rule-test - #8 + +syntax = "proto3"; + +// This sample should not flag the message defined only the exposed secrets in comments : +// "password" = "test_sample" #1 +// "secret_key" : minimum_ten_characters #2 +// "unsafe_token" : "is_this_safe" #3 + +package com.example.security_test.v1; + +import "google/protobuf/wrappers.proto"; + +message InocentMessage { + google.protobuf.StringValue safe_value = 1; + double not_a_password = 22222; // #6 + float not_a_token = 3; // #7 + string not_an_encryption_key = 4; // #8 +} + + +extend google.protobuf.FileOptions { // too generic for an allow rule + int32 source_retention_password = 12342134 //#1 + [retention = RETENTION_SOURCE]; + string source_retention_token = 12342135 //#3 + [retention = RETENTION_SOURCE]; + float source_retention_private_key = 12342137 //#4 + [retention = RETENTION_SOURCE]; + double source_retention_encryption_key = 12342136 //#5 + [retention = RETENTION_SOURCE]; +} diff --git a/assets/queries/common/passwords_and_secrets/test/positive_expected_result.json b/assets/queries/common/passwords_and_secrets/test/positive_expected_result.json index e29ad869f20..d72d6020b19 100644 --- a/assets/queries/common/passwords_and_secrets/test/positive_expected_result.json +++ b/assets/queries/common/passwords_and_secrets/test/positive_expected_result.json @@ -460,5 +460,47 @@ "severity": "HIGH", "line": 4, "fileName": "positive55.json" + }, + { + "queryName": "Passwords And Secrets - Generic Password", + "severity": "HIGH", + "line": 13, + "fileName": "positive56.proto" + }, + { + "queryName": "Passwords And Secrets - Generic Secret", + "severity": "HIGH", + "line": 14, + "fileName": "positive56.proto" + }, + { + "queryName": "Passwords And Secrets - Generic Token", + "severity": "HIGH", + "line": 15, + "fileName": "positive56.proto" + }, + { + "queryName": "Passwords And Secrets - Generic Password", + "severity": "HIGH", + "line": 30, + "fileName": "positive56.proto" + }, + { + "queryName": "Passwords And Secrets - Generic Token", + "severity": "HIGH", + "line": 32, + "fileName": "positive56.proto" + }, + { + "queryName": "Passwords And Secrets - Generic Private Key", + "severity": "HIGH", + "line": 34, + "fileName": "positive56.proto" + }, + { + "queryName": "Passwords And Secrets - Encryption Key", + "severity": "HIGH", + "line": 36, + "fileName": "positive56.proto" } ] \ No newline at end of file diff --git a/pkg/engine/secrets/inspector_test.go b/pkg/engine/secrets/inspector_test.go index 2b5bbf12b55..f642d0e1772 100644 --- a/pkg/engine/secrets/inspector_test.go +++ b/pkg/engine/secrets/inspector_test.go @@ -260,6 +260,34 @@ var OriginalData7 = `# kics-scan disable=baee238e-1921-4801-9c3f-79ae1d7b2cbc register: result ` +var OriginalData8 = ` + syntax = "proto3"; + + package com.example.security_test.v1; + + import "google/protobuf/wrappers.proto"; + + message ResultsThatFlag { + google.protobuf.StringValue refresh_token = 536870911; // if value is larger - out of range error "Field numbers cannot be greater than 536870911." - Generic Token + google.protobuf.StringValue access_token= 1; // Generic Token + google.protobuf.StringValue id_token = 3; // Generic Token + google.protobuf.StringValue bearer_toaken = 4;;; // Generic Token + google.protobuf.StringValue api_token = 7 ; // Generic Token + google.protobuf.StringValue token = 8; // Generic Token + google.protobuf.StringValue sonar_token = 39;google.protobuf.StringValue codecov_token = 40;// trailing comment test - Generic Token + google.protobuf.StringValue jwt_private_key = 25; // Generic Private Key + google.protobuf.StringValue ssh_private_key = 26; // Generic Private Key + google.protobuf.StringValue tls_private_key = 27; // Generic Private Key + google.protobuf.StringValue sp_private_key = 6; // Generic Private Key + google.protobuf.StringValue encryption_key = 22; // Encryption Key + google.protobuf.StringValue data_encryption_key= 23 ; // Encryption Key + google.protobuf.StringValue key_encryption_key=24; // Encryption Key + google.protobuf.StringValue registry_password = 104; // Generic Password + google.protobuf.StringValue artifactory_password = 107 ; // Generic Password + google.protobuf.StringValue nexus_password = 108; // Generic Password + string password = 64; // Generic Password +` + var testInspectInput = []struct { name string files model.FileMetadatas @@ -418,6 +446,21 @@ var testInspectInput = []struct { wantVuln: []model.Vulnerability{}, wantErr: false, }, + { + name: "valid_no_results", + files: model.FileMetadatas{ + { + ID: "a6fbadc6-da29-4340-8d56-aa26a8852526", + Document: model.Document{}, + OriginalData: OriginalData8, + LinesOriginalData: utils.SplitLines(OriginalData8), + Kind: "PROTO", + FilePath: "assets/queries/common/passwords_and_secrets/test/negative60.proto", + }, + }, + wantVuln: []model.Vulnerability{}, + wantErr: false, + }, } var testNewInspectorInputs = []struct {