diff --git a/rules/c/security/dont-call-system-c.yml b/rules/c/security/dont-call-system-c.yml new file mode 100644 index 00000000..1cc4810a --- /dev/null +++ b/rules/c/security/dont-call-system-c.yml @@ -0,0 +1,61 @@ +id: dont-call-system-c +language: c +severity: warning +message: >- + Don't call `system`. It's a high-level wrapper that allows for stacking + multiple commands. Always prefer a more restrictive API such as calling + `execve` from the `exec` family. +note: >- + [CWE-78] Improper Neutralization of Special Elements used in an OS + Command ('OS Command Injection'). + [REFERENCES] + - https://owasp.org/Top10/A03_2021-Injection + +ast-grep-essentials: true + +utils: + PATTERN_SYSTEM_INSIDE_IF_STATEMENT: + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: '^system$' + - has: + stopBy: neighbor + kind: argument_list + - inside: + stopBy: end + kind: parenthesized_expression + inside: + kind: if_statement + PATTERN_SYSTEM: + any: + - kind: expression_statement + - kind: return_statement + - kind: field_declaration + has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: '^system$' + - has: + stopBy: neighbor + kind: argument_list +rule: + any: + - matches: PATTERN_SYSTEM_INSIDE_IF_STATEMENT + - matches: PATTERN_SYSTEM + not: + all: + - has: + stopBy: end + kind: ERROR + - inside: + has: + stopBy: end + kind: ERROR + diff --git a/rules/cpp/dont-call-system-cpp.yml b/rules/cpp/dont-call-system-cpp.yml new file mode 100644 index 00000000..6855b9be --- /dev/null +++ b/rules/cpp/dont-call-system-cpp.yml @@ -0,0 +1,61 @@ +id: dont-call-system-cpp +language: cpp +severity: warning +message: >- + Don't call `system`. It's a high-level wrapper that allows for stacking + multiple commands. Always prefer a more restrictive API such as calling + `execve` from the `exec` family. +note: >- + [CWE-78] Improper Neutralization of Special Elements used in an OS + Command ('OS Command Injection'). + [REFERENCES] + - https://owasp.org/Top10/A03_2021-Injection + +ast-grep-essentials: true + +utils: + PATTERN_SYSTEM_INSIDE_IF_STATEMENT: + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: '^system$' + - has: + stopBy: neighbor + kind: argument_list + - inside: + stopBy: end + kind: parenthesized_expression + inside: + kind: if_statement + PATTERN_SYSTEM: + any: + - kind: expression_statement + - kind: return_statement + - kind: field_declaration + has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: '^system$' + - has: + stopBy: neighbor + kind: argument_list +rule: + any: + - matches: PATTERN_SYSTEM_INSIDE_IF_STATEMENT + - matches: PATTERN_SYSTEM + not: + all: + - has: + stopBy: end + kind: ERROR + - inside: + has: + stopBy: end + kind: ERROR + diff --git a/rules/csharp/security/jwt-tokenvalidationparameters-no-expiry-validation-csharp.yml b/rules/csharp/security/jwt-tokenvalidationparameters-no-expiry-validation-csharp.yml new file mode 100644 index 00000000..9fecd003 --- /dev/null +++ b/rules/csharp/security/jwt-tokenvalidationparameters-no-expiry-validation-csharp.yml @@ -0,0 +1,146 @@ +id: jwt-tokenvalidationparameters-no-expiry-validation-csharp +severity: warning +language: csharp +message: >- + The TokenValidationParameters.$LIFETIME is set to $FALSE, this means + the JWT tokens lifetime is not validated. This can lead to an JWT token + being used after it has expired, which has security implications. It is + recommended to validate the JWT lifetime to ensure only valid tokens are + used. +note: >- + [CWE-613] Insufficient Session Expiration. + [REFERENCES] + - https://owasp.org/Top10/A07_2021-Identification_and_Authentication_Failures/ + - https://cwe.mitre.org/data/definitions/613.html + - https://docs.microsoft.com/en-us/dotnet/api/microsoft.identitymodel.tokens.tokenvalidationparameters?view=azure-dotnet + +ast-grep-essentials: true + +utils: + MATCH_PATTERN_ONE: + kind: boolean_literal + inside: + all: + - has: + stopBy: neighbor + regex: ^(RequireExpirationTime|ValidateLifetime).* + any: + - kind: identifier + - kind: member_access_expression + - has: + stopBy: neighbor + regex: '^=$' + - has: + stopBy: neighbor + kind: boolean_literal + regex: '^false$' + - inside: + stopBy: end + kind: object_creation_expression + has: + stopBy: neighbor + kind: identifier + regex: '^TokenValidationParameters$' + + MATCH_PATTERN_TWO: + kind: boolean_literal + inside: + all: + - has: + stopBy: neighbor + kind: member_access_expression + all: + - has: + stopBy: end + kind: identifier + pattern: $T + + - has: + stopBy: neighbor + kind: identifier + regex: ^(RequireExpirationTime|ValidateLifetime).* + + - has: + stopBy: neighbor + regex: '^=$' + - has: + stopBy: neighbor + kind: boolean_literal + regex: '^false$' + - inside: + stopBy: end + kind: global_statement + follows: + stopBy: end + kind: global_statement + has: + stopBy: end + kind: variable_declaration + all: + - has: + stopBy: neighbor + kind: identifier + regex: '^TokenValidationParameters$' + - has: + stopBy: neighbor + kind: variable_declarator + has: + stopBy: neighbor + kind: identifier + pattern: $T + MATCH_PATTERN_THREE: + kind: boolean_literal + inside: + all: + - has: + stopBy: neighbor + kind: member_access_expression + all: + - has: + stopBy: end + kind: identifier + pattern: $S + + - has: + stopBy: neighbor + kind: identifier + regex: ^(RequireExpirationTime|ValidateLifetime).* + - has: + stopBy: neighbor + regex: '^=$' + - has: + stopBy: neighbor + kind: boolean_literal + regex: '^false$' + - inside: + kind: expression_statement + stopBy: end + follows: + stopBy: end + kind: local_declaration_statement + has: + stopBy: end + kind: variable_declaration + all: + - has: + stopBy: end + kind: identifier + regex: '^TokenValidationParameters$' + - has: + stopBy: neighbor + kind: variable_declarator + has: + stopBy: neighbor + kind: identifier + pattern: $S + +rule: + kind: boolean_literal + any: + - matches: MATCH_PATTERN_ONE + - matches: MATCH_PATTERN_TWO + - matches: MATCH_PATTERN_THREE + not: + has: + kind: ERROR + stopBy: end diff --git a/tests/__snapshots__/dont-call-system-c-snapshot.yml b/tests/__snapshots__/dont-call-system-c-snapshot.yml new file mode 100644 index 00000000..97ca6fda --- /dev/null +++ b/tests/__snapshots__/dont-call-system-c-snapshot.yml @@ -0,0 +1,45 @@ +id: dont-call-system-c +snapshots: + ? | + void test_002(const char *input) + { + char cmdbuf[BUFFERSIZE]; + int len_wanted = snprintf(cmdbuf, BUFFERSIZE, + "any_cmd '%s'", input); + system(cmdbuf); + } + void test_001(const char *input) + { + char cmdbuf[BUFFERSIZE]; + int len_wanted = snprintf(cmdbuf, BUFFERSIZE, + "any_cmd '%s'", input); + if (len_wanted >= BUFFERSIZE) + { + /* Handle error */ + } + else if (len_wanted < 0) + { + /* Handle error */ + } + else if (system(cmdbuf) == -1) + { + /* Handle error */ + } + } + : labels: + - source: system(cmdbuf); + style: primary + start: 156 + end: 171 + - source: system + style: secondary + start: 156 + end: 162 + - source: (cmdbuf) + style: secondary + start: 162 + end: 170 + - source: system(cmdbuf) + style: secondary + start: 156 + end: 170 diff --git a/tests/__snapshots__/dont-call-system-cpp-snapshot.yml b/tests/__snapshots__/dont-call-system-cpp-snapshot.yml new file mode 100644 index 00000000..fca691e3 --- /dev/null +++ b/tests/__snapshots__/dont-call-system-cpp-snapshot.yml @@ -0,0 +1,45 @@ +id: dont-call-system-cpp +snapshots: + ? | + void test_002(const char *input) + { + char cmdbuf[BUFFERSIZE]; + int len_wanted = snprintf(cmdbuf, BUFFERSIZE, + "any_cmd '%s'", input); + system(cmdbuf); + } + void test_001(const char *input) + { + char cmdbuf[BUFFERSIZE]; + int len_wanted = snprintf(cmdbuf, BUFFERSIZE, + "any_cmd '%s'", input); + if (len_wanted >= BUFFERSIZE) + { + /* Handle error */ + } + else if (len_wanted < 0) + { + /* Handle error */ + } + else if (system(cmdbuf) == -1) + { + /* Handle error */ + } + } + : labels: + - source: system(cmdbuf); + style: primary + start: 156 + end: 171 + - source: system + style: secondary + start: 156 + end: 162 + - source: (cmdbuf) + style: secondary + start: 162 + end: 170 + - source: system(cmdbuf) + style: secondary + start: 156 + end: 170 diff --git a/tests/__snapshots__/jwt-tokenvalidationparameters-no-expiry-validation-csharp-snapshot.yml b/tests/__snapshots__/jwt-tokenvalidationparameters-no-expiry-validation-csharp-snapshot.yml new file mode 100644 index 00000000..f7b23cff --- /dev/null +++ b/tests/__snapshots__/jwt-tokenvalidationparameters-no-expiry-validation-csharp-snapshot.yml @@ -0,0 +1,169 @@ +id: jwt-tokenvalidationparameters-no-expiry-validation-csharp +snapshots: + ? | + TokenValidationParameters parameters = new TokenValidationParameters + { + ValidateLifetime = false, + RequireExpirationTime = false, + ValidateIssuer = false, + ValidateAudience = false + }; + : labels: + - source: 'false' + style: primary + start: 90 + end: 95 + - source: ValidateLifetime + style: secondary + start: 71 + end: 87 + - source: = + style: secondary + start: 88 + end: 89 + - source: 'false' + style: secondary + start: 90 + end: 95 + - source: TokenValidationParameters + style: secondary + start: 43 + end: 68 + - source: |- + new TokenValidationParameters + { + ValidateLifetime = false, + RequireExpirationTime = false, + ValidateIssuer = false, + ValidateAudience = false + } + style: secondary + start: 39 + end: 178 + - source: ValidateLifetime = false + style: secondary + start: 71 + end: 95 + ? "TokenValidationParameters parameters = new TokenValidationParameters\n{ \nValidateLifetime = false,\nRequireExpirationTime = false,\nValidateIssuer = false,\nValidateAudience = false\n};\n" + : labels: + - source: 'false' + style: primary + start: 91 + end: 96 + - source: ValidateLifetime + style: secondary + start: 72 + end: 88 + - source: = + style: secondary + start: 89 + end: 90 + - source: 'false' + style: secondary + start: 91 + end: 96 + - source: TokenValidationParameters + style: secondary + start: 43 + end: 68 + - source: "new TokenValidationParameters\n{ \nValidateLifetime = false,\nRequireExpirationTime = false,\nValidateIssuer = false,\nValidateAudience = false\n}" + style: secondary + start: 39 + end: 179 + - source: ValidateLifetime = false + style: secondary + start: 72 + end: 96 + ? | + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateLifetime = true, + RequireExpirationTime = false, + ValidateIssuer = false, + ValidateAudience = false + }; + : labels: + - source: 'false' + style: primary + start: 125 + end: 130 + - source: RequireExpirationTime + style: secondary + start: 101 + end: 122 + - source: = + style: secondary + start: 123 + end: 124 + - source: 'false' + style: secondary + start: 125 + end: 130 + - source: TokenValidationParameters + style: secondary + start: 40 + end: 65 + - source: |- + new TokenValidationParameters + { + ValidateLifetime = true, + RequireExpirationTime = false, + ValidateIssuer = false, + ValidateAudience = false + } + style: secondary + start: 36 + end: 190 + - source: RequireExpirationTime = false + style: secondary + start: 101 + end: 130 + ? | + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateLifetime = false, + RequireSignedTokens = true, + ValidateIssuer = false, + ValidateAudience = false, + RequireExpirationTime = false + }; + TokenValidationParameters parameters = new TokenValidationParameters(); + parameters.RequireExpirationTime = false; + parameters.ValidateLifetime = false; + : labels: + - source: 'false' + style: primary + start: 87 + end: 92 + - source: ValidateLifetime + style: secondary + start: 68 + end: 84 + - source: = + style: secondary + start: 85 + end: 86 + - source: 'false' + style: secondary + start: 87 + end: 92 + - source: TokenValidationParameters + style: secondary + start: 40 + end: 65 + - source: |- + new TokenValidationParameters + { + ValidateLifetime = false, + RequireSignedTokens = true, + ValidateIssuer = false, + ValidateAudience = false, + RequireExpirationTime = false + } + style: secondary + start: 36 + end: 203 + - source: ValidateLifetime = false + style: secondary + start: 68 + end: 92 diff --git a/tests/cpp/dont-call-system-cpp-test.yml b/tests/cpp/dont-call-system-cpp-test.yml new file mode 100644 index 00000000..846b4fcc --- /dev/null +++ b/tests/cpp/dont-call-system-cpp-test.yml @@ -0,0 +1,34 @@ +id: dont-call-system-cpp +valid: + - | + void test_003(const char *input) + { + storer->store_binary(Clocks->system()); + } +invalid: + - | + void test_002(const char *input) + { + char cmdbuf[BUFFERSIZE]; + int len_wanted = snprintf(cmdbuf, BUFFERSIZE, + "any_cmd '%s'", input); + system(cmdbuf); + } + void test_001(const char *input) + { + char cmdbuf[BUFFERSIZE]; + int len_wanted = snprintf(cmdbuf, BUFFERSIZE, + "any_cmd '%s'", input); + if (len_wanted >= BUFFERSIZE) + { + /* Handle error */ + } + else if (len_wanted < 0) + { + /* Handle error */ + } + else if (system(cmdbuf) == -1) + { + /* Handle error */ + } + } diff --git a/tests/csharp/jwt-tokenvalidationparameters-no-expiry-validation-csharp-test.yml b/tests/csharp/jwt-tokenvalidationparameters-no-expiry-validation-csharp-test.yml new file mode 100644 index 00000000..c6a2689d --- /dev/null +++ b/tests/csharp/jwt-tokenvalidationparameters-no-expiry-validation-csharp-test.yml @@ -0,0 +1,42 @@ +id: jwt-tokenvalidationparameters-no-expiry-validation-csharp +valid: + - | + parameters.ValidateLifetime = true; + parameters.RequireExpirationTime = true +invalid: + - | + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateLifetime = false, + RequireSignedTokens = true, + ValidateIssuer = false, + ValidateAudience = false, + RequireExpirationTime = false + }; + TokenValidationParameters parameters = new TokenValidationParameters(); + parameters.RequireExpirationTime = false; + parameters.ValidateLifetime = false; + - | + TokenValidationParameters parameters = new TokenValidationParameters + { + ValidateLifetime = false, + RequireExpirationTime = false, + ValidateIssuer = false, + ValidateAudience = false + }; + - | + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateLifetime = true, + RequireExpirationTime = false, + ValidateIssuer = false, + ValidateAudience = false + }; + - | + TokenValidationParameters parameters = new TokenValidationParameters + { + ValidateLifetime = false, + RequireExpirationTime = false, + ValidateIssuer = false, + ValidateAudience = false + }; diff --git a/tests/java/dont-call-system-c-test.yml b/tests/java/dont-call-system-c-test.yml new file mode 100644 index 00000000..89689983 --- /dev/null +++ b/tests/java/dont-call-system-c-test.yml @@ -0,0 +1,34 @@ +id: dont-call-system-c +valid: + - | + void test_003(const char *input) + { + storer->store_binary(Clocks->system()); + } +invalid: + - | + void test_002(const char *input) + { + char cmdbuf[BUFFERSIZE]; + int len_wanted = snprintf(cmdbuf, BUFFERSIZE, + "any_cmd '%s'", input); + system(cmdbuf); + } + void test_001(const char *input) + { + char cmdbuf[BUFFERSIZE]; + int len_wanted = snprintf(cmdbuf, BUFFERSIZE, + "any_cmd '%s'", input); + if (len_wanted >= BUFFERSIZE) + { + /* Handle error */ + } + else if (len_wanted < 0) + { + /* Handle error */ + } + else if (system(cmdbuf) == -1) + { + /* Handle error */ + } + }