diff --git a/rules/c/security/small-key-size-c.yml b/rules/c/security/small-key-size-c.yml new file mode 100644 index 00000000..661c9a41 --- /dev/null +++ b/rules/c/security/small-key-size-c.yml @@ -0,0 +1,56 @@ +id: small-key-size-c +language: c +severity: warning +message: >- + $KEY_FUNCTION` is using a key size of only $KEY_BITS bits. This is + less than the recommended key size of 2048 bits. +note: >- + [CWE-326]: Inadequate Encryption Strength + [OWASP A02:2021]: Cryptographic Failures + [OWASP A03:2017]: Sensitive Data Exposure + [REFERENCES] + https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf + https://owasp.org/Top10/A02_2021-Cryptographic_Failures +utils: + Match_pattern_with_prefix_statement: + kind: expression_statement + all: + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: end + kind: identifier + pattern: $AST + - has: + stopBy: end + kind: argument_list + has: + stopby: end + kind: identifier + pattern: $Q + - follows: + stopBy: end + kind: declaration + has: + stopBy: end + kind: init_declarator + all: + - has: + stopBy: end + kind: identifier + pattern: $Q + - has: + stopBy: end + kind: number_literal + pattern: $AASS + +rule: + kind: expression_statement + matches: Match_pattern_with_prefix_statement +constraints: + AST: + regex: (DH_generate_parameters_ex|DSA_generate_parameters_ex|EVP_PKEY_CTX_set_dh_paramgen_prime_len|EVP_PKEY_CTX_set_dsa_paramgen_bits|EVP_PKEY_CTX_set_rsa_keygen_bits|RSA_generate_key_ex|RSA_generate_key_fips) + AASS: + 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/rules/c/security/std-return-data-c.yml b/rules/c/security/std-return-data-c.yml new file mode 100644 index 00000000..6f10adff --- /dev/null +++ b/rules/c/security/std-return-data-c.yml @@ -0,0 +1,109 @@ +id: std-return-data-c +language: c +severity: warning +message: >- + $FUNC` returns a pointer to the memory owned by `$VAR`. This pointer + is invalid after `$VAR` goes out of scope, which can trigger a use after + free. +note: >- + [CWE-416: Use After Free. + [REFERENCES] + - https://wiki.sei.cmu.edu/confluence/display/c/DCL30-C.+Declare+objects+with+appropriate+storage+durations +utils: + MATCH_RETURN_STATEMENT_WITH_STD: + kind: return_statement + all: + - has: + stopBy: end + kind: call_expression + has: + stopBy: end + kind: field_expression + has: + stopBy: end + kind: identifier + pattern: $R + - follows: + stopBy: end + kind: labeled_statement + all: + - has: + stopBy: end + kind: statement_identifier + regex: ^std + - has: + stopBy: end + kind: expression_statement + has: + stopBy: end + kind: binary_expression + all: + - has: + stopBy: end + kind: binary_expression + all: + - has: + stopBy: end + kind: identifier + regex: (vector|array|deque|forward_list|list|map|multimap|multiset|set|unordered_map|unordered_multimap|unordered_multiset|unordered_set) + - has: + stopBy: end + kind: identifier + - has: + stopBy: end + kind: identifier + pattern: $R + inside: + stopBy: end + kind: function_definition + has: + stopBy: end + kind: primitive_type + + MATCH_RETURN_STATEMENT_WITHOUT_STD: + kind: return_statement + all: + - has: + stopBy: end + kind: call_expression + has: + stopBy: end + kind: field_expression + has: + stopBy: end + kind: identifier + pattern: $R + - follows: + stopBy: end + kind: expression_statement + has: + stopBy: end + kind: binary_expression + all: + - has: + stopBy: end + kind: binary_expression + all: + - has: + stopBy: end + kind: identifier + regex: (vector|array|deque|forward_list|list|map|multimap|multiset|set|unordered_map|unordered_multimap|unordered_multiset|unordered_set) + - has: + stopBy: end + kind: identifier + - has: + stopBy: end + kind: identifier + pattern: $R + inside: + stopBy: end + kind: function_definition + has: + stopBy: end + kind: primitive_type + +rule: + kind: return_statement + any: + - matches: MATCH_RETURN_STATEMENT_WITH_STD + - matches: MATCH_RETURN_STATEMENT_WITHOUT_STD diff --git a/rules/cpp/security/return-c-str-cpp.yml b/rules/cpp/security/return-c-str-cpp.yml new file mode 100644 index 00000000..59bcae84 --- /dev/null +++ b/rules/cpp/security/return-c-str-cpp.yml @@ -0,0 +1,109 @@ +id: return-c-str-cpp +language: cpp +severity: warning +message: >- + "`$FUNC` returns a pointer to the memory owned by `$STR`. This pointer + is invalid after `$STR` goes out of scope, which can trigger a use after + free." +note: >- + [CWE-416] Use After Free + [REFERENCES] + - https://wiki.sei.cmu.edu/confluence/display/c/DCL30-C.+Declare+objects+with+appropriate+storage+durations + - https://wiki.sei.cmu.edu/confluence/display/cplusplus/EXP54-CPP.+Do+not+access+an+object+outside+of+its+lifetime + +utils: + util_for_declaration_inside_function: + kind: return_statement + pattern: return $STR.$METHOD(); + follows: + kind: declaration + stopBy: end + any: + - pattern: string $STR; + - pattern: wstring $STR; + - pattern: basic_string $STR; + - pattern: std::string $STR; + - pattern: std::wstring $STR; + - pattern: std::basic_string<$TYPE> $STR; + + util_for_assignment_inside_function: + kind: return_statement + pattern: return $STR.$METHOD(); + follows: + kind: declaration + stopBy: end + any: + - pattern: string $STR = string($STRING); + - pattern: wstring $STR = wstring($STRING); + - pattern: basic_string<$TYPE> $STR = basic_string<$TYPE>($STRING); + - pattern: std::string $STR = std::string($STRING); + - pattern: std::wstring $STR = std::wstring($STRING); + - pattern: std::basic_string<$TYPE> $STR = std::basic_string<$TYPE>($STRING); + + util_for_func_params: + kind: return_statement + pattern: return $STR.$METHOD(); + inside: + stopBy: end + kind: function_definition + has: + stopBy: end + kind: parameter_list + has: + stopBy: end + kind: parameter_declaration + has: + stopBy: end + kind: identifier + field: declarator + pattern: $STR + any: + - has: + any: + - kind: type_identifier + pattern: $IDENTIFIFER + - kind: qualified_identifier + any: + - all: + - has: + kind: namespace_identifier + pattern: $NAMESPACE_IDEN + - has: + kind: template_type + all: + - has: + kind: type_identifier + field: name + pattern: $BASIC_STR + precedes: + kind: template_argument_list + - pattern: $IDENTIFIFER + - kind: template_type + has: + kind: type_identifier + field: name + pattern: $BASIC_STR + precedes: + kind: template_argument_list + +rule: + any: + - matches: util_for_declaration_inside_function + - matches: util_for_assignment_inside_function + - matches: util_for_func_params + - pattern: return basic_string<$TYPE>($$$).$METHOD(); + - pattern: return std::basic_string<$TYPE>($$$).$METHOD(); + - pattern: return string($$$).$METHOD(); + - pattern: return std::string($$$).$METHOD(); + - pattern: return wstring($$$).$METHOD(); + - pattern: return std::wstring($$$).$METHOD(); + +constraints: + METHOD: + regex: ^(c_str|data)$ + IDENTIFIFER: + regex: ^(string|wstring|std::string|std::wstring)$ + BASIC_STR: + regex: ^(basic_string)$ + NAMESPACE_IDEN: + regex: ^(std)$ diff --git a/rules/cpp/security/sizeof-this-cpp.yml b/rules/cpp/security/sizeof-this-cpp.yml new file mode 100644 index 00000000..a32bbd6a --- /dev/null +++ b/rules/cpp/security/sizeof-this-cpp.yml @@ -0,0 +1,13 @@ +id: sizeof-this-cpp +language: cpp +severity: warning +message: >- + Do not use `sizeof(this)` to get the number of bytes of the object in + memory. It returns the size of the pointer, not the size of the object. +note: >- + [CWE-467]: Use of sizeof() on a Pointer Type + [REFERENCES] + - https://wiki.sei.cmu.edu/confluence/display/c/ARR01-C.+Do+not+apply+the+sizeof+operator+to+a+pointer+when+taking+the+size+of+an+array +rule: + any: + - pattern: "sizeof(this)" diff --git a/rules/cpp/security/small-key-size-cpp.yml b/rules/cpp/security/small-key-size-cpp.yml new file mode 100644 index 00000000..94a5bc48 --- /dev/null +++ b/rules/cpp/security/small-key-size-cpp.yml @@ -0,0 +1,56 @@ +id: small-key-size-cpp +language: cpp +severity: warning +message: >- + $KEY_FUNCTION` is using a key size of only $KEY_BITS bits. This is + less than the recommended key size of 2048 bits. +note: >- + [CWE-326]: Inadequate Encryption Strength + [OWASP A02:2021]: Cryptographic Failures + [OWASP A03:2017]: Sensitive Data Exposure + [REFERENCES] + https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf + https://owasp.org/Top10/A02_2021-Cryptographic_Failures +utils: + Match_pattern_with_prefix_statement: + kind: expression_statement + all: + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: end + kind: identifier + pattern: $AST + - has: + stopBy: end + kind: argument_list + has: + stopby: end + kind: identifier + pattern: $Q + - follows: + stopBy: end + kind: declaration + has: + stopBy: end + kind: init_declarator + all: + - has: + stopBy: end + kind: identifier + pattern: $Q + - has: + stopBy: end + kind: number_literal + pattern: $AASS + +rule: + kind: expression_statement + matches: Match_pattern_with_prefix_statement +constraints: + AST: + regex: (DH_generate_parameters_ex|DSA_generate_parameters_ex|EVP_PKEY_CTX_set_dh_paramgen_prime_len|EVP_PKEY_CTX_set_dsa_paramgen_bits|EVP_PKEY_CTX_set_rsa_keygen_bits|RSA_generate_key_ex|RSA_generate_key_fips) + AASS: + 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/rules/cpp/security/std-return-data-cpp.yml b/rules/cpp/security/std-return-data-cpp.yml new file mode 100644 index 00000000..e36e1637 --- /dev/null +++ b/rules/cpp/security/std-return-data-cpp.yml @@ -0,0 +1,124 @@ +id: std-return-data-cpp +language: cpp +severity: warning +message: >- + $FUNC` returns a pointer to the memory owned by `$VAR`. This pointer + is invalid after `$VAR` goes out of scope, which can trigger a use after + free. +note: >- + [CWE-416: Use After Free. + [REFERENCES] + - https://wiki.sei.cmu.edu/confluence/display/c/DCL30-C.+Declare+objects+with+appropriate+storage+durations +utils: + MATCH_RETURN_STATEMENT_WITH_STD: + kind: return_statement + has: + kind: call_expression + has: + kind: field_expression + has: + kind: identifier + pattern: $VAR + inside: + stopBy: end + kind: return_statement + follows: + stopBy: end + kind: declaration + all: + - has: + stopBy: end + kind: identifier + pattern: $VAR + - has: + stopBy: end + kind: template_type + has: + stopBy: end + kind: type_identifier + regex: (^vector|^array$|^deque$|^forward_list$|^list$|^map$|^multimap$|^multiset$|^set$|^unordered_map$|^unordered_multimap$|^unordered_multiset$|^unordered_set$) + - has: + stopBy: end + kind: qualified_identifier + has: + stopBy: end + kind: namespace_identifier + pattern: $I + inside: + stopBy: end + kind: compound_statement + all: + - follows: + stopBy: end + kind: pointer_declarator + has: + stopBy: end + kind: function_declarator + has: + stopBy: end + kind: identifier + regex: ^return.* + - follows: + stopBy: end + kind: primitive_type + pattern: $J + MATCH_RETURN_STATEMENT_WITHOUT_STD: + kind: return_statement + has: + kind: call_expression + has: + kind: field_expression + has: + kind: identifier + pattern: $VAR + inside: + stopBy: end + kind: return_statement + follows: + stopBy: end + kind: declaration + all: + - has: + stopBy: end + kind: identifier + pattern: $VAR + - has: + stopBy: end + kind: template_type + has: + stopBy: end + kind: type_identifier + regex: (^vector|^array$|^deque$|^forward_list$|^list$|^map$|^multimap$|^multiset$|^set$|^unordered_map$|^unordered_multimap$|^unordered_multiset$|^unordered_set$) + inside: + stopBy: end + kind: compound_statement + all: + - follows: + stopBy: end + kind: pointer_declarator + has: + stopBy: end + kind: function_declarator + all: + - has: + stopBy: end + kind: identifier + regex: ^return.* + - has: + stopBy: end + kind: parameter_list + - follows: + stopBy: end + kind: primitive_type + pattern: $J +rule: + kind: return_statement + any: + - matches: MATCH_RETURN_STATEMENT_WITH_STD + - matches: MATCH_RETURN_STATEMENT_WITHOUT_STD + +constraints: + I: + regex: "^std$" + J: + regex: ^(int|char|float)$ diff --git a/rules/go/grpc/grpc-client-insecure-connection-go.yml b/rules/go/grpc/grpc-client-insecure-connection-go.yml new file mode 100644 index 00000000..f77fdb12 --- /dev/null +++ b/rules/go/grpc/grpc-client-insecure-connection-go.yml @@ -0,0 +1,20 @@ +id: grpc-client-insecure-connection-go +language: go +severity: warning +message: >- + Found an insecure gRPC connection using 'grpc.WithInsecure()'. This + creates a connection without encryption to a gRPC server. A malicious + attacker could tamper with the gRPC message, which could compromise the + machine. Instead, establish a secure connection with an SSL certificate + using the 'grpc.WithTransportCredentials()' function. You can create a + create credentials using a 'tls.Config{}' struct with + 'credentials.NewTLS()'. The final fix looks like this: + 'grpc.WithTransportCredentials(credentials.NewTLS())'. +note: >- + [CWE-300] Channel Accessible by Non-Endpoint. + [REFERENCES] + - https://blog.gopheracademy.com/advent-2019/go-grps-and-tls/#connection-without-encryption +rule: + any: + - pattern: $GRPC.Dial($ADDR, $$$, $GRPC.WithInsecure($$$), $$$) + - pattern: $GRPC.Dial($ADDR, $GRPC.WithInsecure($$$)) diff --git a/rules/go/grpc/grpc-client-insecure-connection.yml b/rules/go/grpc/grpc-client-insecure-connection.yml deleted file mode 100644 index 2e4e6c99..00000000 --- a/rules/go/grpc/grpc-client-insecure-connection.yml +++ /dev/null @@ -1,21 +0,0 @@ -id: grpc-client-insecure-connection -language: go -severity: warning -message: >- - Found an insecure gRPC connection using 'grpc.WithInsecure()'. This creates a - connection without encryption to a gRPC - server. A malicious attacker could tamper with the gRPC message, which could compromise - the machine. Instead, establish - a secure connection with an - SSL certificate using the 'grpc.WithTransportCredentials()' function. You can - create a create credentials using a 'tls.Config{}' - struct with 'credentials.NewTLS()'. The final fix looks like this: 'grpc.WithTransportCredentials(credentials.NewTLS())'. -note: >- - [CWE-300] Channel Accessible by Non-Endpoint - [OWASP A07:2021] Identification and Authentication Failures - [REFERENCES] - - https://blog.gopheracademy.com/advent-2019/go-grps-and-tls/#connection-without-encryption -rule: - any: - - pattern: "$GRPC.Dial($ADDR, $$$, $GRPC.WithInsecure($$$), $$$)" - - pattern: "$GRPC.Dial($ADDR, $$$, $GRPC.WithInsecure($$$))" \ No newline at end of file diff --git a/rules/go/jwt-go/jwt-go-none-algorithm-go.yml b/rules/go/jwt-go/jwt-go-none-algorithm-go.yml new file mode 100644 index 00000000..5a40fa82 --- /dev/null +++ b/rules/go/jwt-go/jwt-go-none-algorithm-go.yml @@ -0,0 +1,38 @@ +id: jwt-go-none-algorithm-go +language: go +severity: warning +message: >- + Detected use of the 'none' algorithm in a JWT token. The 'none' + algorithm assumes the integrity of the token has already been verified. + This would allow a malicious actor to forge a JWT token that will + automatically be verified. Do not explicitly use the 'none' algorithm. + Instead, use an algorithm such as 'HS256'. +note: >- + [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm + [OWASP A03:2017]: Sensitive Data Exposure + [OWASP A02:2021]: Cryptographic Failures + [REFERENCES] + https://owasp.org/Top10/A02_2021-Cryptographic_Failures +utils: + after_declaration: + inside: + stopBy: end + kind: function_declaration + follows: + stopBy: end + kind: import_declaration + has: + stopBy: end + kind: import_spec_list + pattern: $IMPORT_MOD +rule: + kind: selector_expression + all: + - pattern: $JWT_FUNC + - matches: after_declaration + +constraints: + JWT_FUNC: + regex: (jwt.SigningMethodNone|jwt.UnsafeAllowNoneSignatureType) + IMPORT_MOD: + regex: ("github.com/golang-jwt/jwt"|"github.com/dgrijalva/jwt-go") diff --git a/rules/go/security/avoid-bind-to-all-interfaces-go.yml b/rules/go/security/avoid-bind-to-all-interfaces-go.yml new file mode 100644 index 00000000..ec13e207 --- /dev/null +++ b/rules/go/security/avoid-bind-to-all-interfaces-go.yml @@ -0,0 +1,21 @@ +id: avoid-bind-to-all-interfaces-go +language: go +severity: warning +message: >- + "Detected a network listener listening on 0.0.0.0 or an empty string. + This could unexpectedly expose the server publicly as it binds to all + available interfaces. Instead, specify another IP address that is not + 0.0.0.0 nor the empty string." +note: >- + [CWE-200] Exposure of Sensitive Information to an Unauthorized Actor + [REFERENCES] + - https://owasp.org/Top10/A01_2021-Broken_Access_Control +rule: + any: + - pattern: tls.Listen($NETWORK, $IP $$$) + - pattern: net.Listen($NETWORK, $IP $$$) + +constraints: + IP: + kind: interpreted_string_literal + regex: ^"0.0.0.0:.*"$|^":.*"$|^'0.0.0.0:.*'$|^':.*'$ diff --git a/rules/go/security/use-of-weak-rsa-key-go.yml b/rules/go/security/use-of-weak-rsa-key-go.yml new file mode 100644 index 00000000..783411a8 --- /dev/null +++ b/rules/go/security/use-of-weak-rsa-key-go.yml @@ -0,0 +1,36 @@ +id: use-of-weak-rsa-key-go +language: go +severity: warning +message: >- + RSA keys should be at least 2048 bits. +note: >- + [CWE-326] Inadequate Encryption Strength. + [REFERENCES] + - https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#algorithms +utils: + statement_match_pattern_one: + kind: expression_list + all: + - has: + stopBy: end + kind: selector_expression + pattern: $JWT + - has: + stopBy: end + kind: argument_list + - has: + stopBy: end + kind: int_literal + pattern: $BITS + +rule: + kind: expression_list + any: + - matches: statement_match_pattern_one + +constraints: + JWT: + regex: (rsa.GenerateMultiPrimeKey|rsa.GenerateKey) + + BITS: + 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/rules/java/security/documentbuilderfactory-disallow-doctype-decl-false-java.yml b/rules/java/security/documentbuilderfactory-disallow-doctype-decl-false-java.yml new file mode 100644 index 00000000..345a3663 --- /dev/null +++ b/rules/java/security/documentbuilderfactory-disallow-doctype-decl-false-java.yml @@ -0,0 +1,29 @@ +id: documentbuilderfactory-disallow-doctype-decl-false-java +language: java +severity: warning +message: >- + DOCTYPE declarations are enabled for $DBFACTORY. Without prohibiting + external entity declarations, this is vulnerable to XML external entity + attacks. Disable this by setting the feature + "http://apache.org/xml/features/disallow-doctype-decl" to true. + Alternatively, allow DOCTYPE declarations and only prohibit external + entities declarations. This can be done by setting the features + "http://xml.org/sax/features/external-general-entities" and + "http://xml.org/sax/features/external-parameter-entities" to false. +note: >- + [CWE-611]: mproper Restriction of XML External Entity Reference + [OWASP A04:2017]: XML External Entities (XXE) + [OWASP A05:2021 - Security Misconfiguration] + [REFERENCES] + https://blog.sonarsource.com/secure-xml-processor + https://xerces.apache.org/xerces2-j/features.html +rule: + any: + - pattern: $D.setFeature("http://apache.org/xml/features/disallow-doctype-decl",false); + follows: + pattern: DocumentBuilderFactory $D = $_; + stopBy: end + - pattern: $S.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false); + follows: + pattern: SAXParserFactory $S = $_; + stopBy: end diff --git a/rules/java/security/documentbuilderfactory-external-parameter-entities-true-java.yml b/rules/java/security/documentbuilderfactory-external-parameter-entities-true-java.yml new file mode 100644 index 00000000..7dcccba7 --- /dev/null +++ b/rules/java/security/documentbuilderfactory-external-parameter-entities-true-java.yml @@ -0,0 +1,13 @@ +id: documentbuilderfactory-external-parameter-entities-true-java +severity: warning +language: java +message: >- + External entities are allowed for $DBFACTORY. This is vulnerable to XML + external entity attacks. Disable this by setting the feature + "http://xml.org/sax/features/external-parameter-entities" to false. +note: >- + [CWE-611] Improper Restriction of XML External Entity Reference. + [REFERENCES] + - https://blog.sonarsource.com/secure-xml-processor +rule: + pattern: $DBFACTORY.setFeature("http://xml.org/sax/features/external-parameter-entities",true); diff --git a/rules/java/security/gcm-nonce-reuse-java.yml b/rules/java/security/gcm-nonce-reuse-java.yml new file mode 100644 index 00000000..a6cc2749 --- /dev/null +++ b/rules/java/security/gcm-nonce-reuse-java.yml @@ -0,0 +1,16 @@ +id: gcm-nonce-reuse-java +language: java +severity: warning +message: >- + GCM IV/nonce is reused: encryption can be totally useless. +note: >- + [CWE-323] Reusing a Nonce, Key Pair in Encryption. + [REFERENCES] + - https://owasp.org/Top10/A02_2021-Cryptographic_Failures +rule: + any: + - pattern: GCMParameterSpec $$$ = new GCMParameterSpec(GCM_TAG_LENGTH * 8, $A); + follows: + pattern: byte[] $A = $_; + stopBy: end + - pattern: new GCMParameterSpec($$$, "$$$".getBytes($$$), $$$) diff --git a/rules/java/security/simple-command-injection-direct-input-java.yml b/rules/java/security/simple-command-injection-direct-input-java.yml new file mode 100644 index 00000000..592c8724 --- /dev/null +++ b/rules/java/security/simple-command-injection-direct-input-java.yml @@ -0,0 +1,55 @@ +id: simple-command-injection-direct-input-java +language: java +severity: warning +message: >- + "Untrusted input might be injected into a command executed by the + application, which can lead to a command injection vulnerability. An + attacker can execute arbitrary commands, potentially gaining complete + control of the system. To prevent this vulnerability, avoid executing OS + commands with user input. If this is unavoidable, validate and sanitize + the input, and use safe methods for executing the commands. For more + information, see: [Java command injection + prevention]" +note: >- + [CWE-78] Improper Neutralization of Special Elements used in an OS + [REFERENCES] + - https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html + - https://owasp.org/Top10/A03_2021-Injection + +rule: + kind: method_invocation + pattern: Runtime.getRuntime().exec($SOURCE) + inside: + kind: method_declaration + stopBy: end + has: + stopBy: end + kind: formal_parameter + has: + kind: modifiers + any: + - has: + kind: marker_annotation + has: + kind: identifier + pattern: $REQ + - has: + kind: annotation + all: + - has: + kind: identifier + pattern: $REQ + - has: + kind: annotation_argument_list + precedes: + kind: type_identifier + pattern: $TYPE + precedes: + kind: identifier + pattern: $SOURCE + +constraints: + REQ: + regex: ^(RequestBody|PathVariable|RequestParam|RequestHeader|CookieValue|ModelAttribute) + TYPE: + regex: ^[^I].*|^I[^n].*|^In[^t].*|^Int[^e].*|^Inte[^g].*|^Integ[^e].*|^Inge[^r].*|^L[^o].*|^Lo[^n].*|^Lon[^g].*|^F[^l].*|^Fl[^o].*|^Flo[^a].*|^Floa[^t].*|^D[^o].*|^Do[^u].*|^Dou[^b].*|^Doub[^l].*|^Doubl[^e].*|^C[^h].*|^Ch[^a].*|^Cha[^r].*|^B[^o].*|^Bo[^o].*|^Boo[^l].*|^Bool[^e].*|^Boole[^a].*|^Boolea[^n].*|^i[^n].*|^in[^t].*|^l[^o].*|^lo[^n].*|^lon[^g].*|^f[^l].*|^fl[^o].*|^flo[^a].*|^floa[^t].*|^d[^o].*|^do[^u].*|^dou[^b].*|^doub[^l].*|^doubl[^e].*|^c[^h].*|^ch[^a].*|^cha[^r].*|^b[^o].*|^bo[^o].*|^boo[^l].*|^bool[^e].*|^boole[^a].*|^boolea[^n].* diff --git a/rules/javascript/jwt/jwt-none-alg-javascript.yml b/rules/javascript/jwt/jwt-none-alg-javascript.yml new file mode 100644 index 00000000..d5234c1b --- /dev/null +++ b/rules/javascript/jwt/jwt-none-alg-javascript.yml @@ -0,0 +1,46 @@ +id: jwt-none-alg-javascript +language: javascript +severity: warning +message: >- + Detected use of the 'none' algorithm in a JWT token. The 'none' + algorithm assumes the integrity of the token has already been verified. + This would allow a malicious actor to forge a JWT token that will + automatically be verified. Do not explicitly use the 'none' algorithm. + Instead, use an algorithm such as 'HS256'. +note: >- + [CWE-327] Use of a Broken or Risky Cryptographic Algorithm. + [REFERENCES] + - https://owasp.org/Top10/A02_2021-Cryptographic_Failures +rule: + any: + - pattern: const $T = JWT.verify($P, JWK.None); + follows: + pattern: const { JWK, JWT } = $JOSE; + follows: + pattern: const $JOSE = require("jose"); + - pattern: $T = JWT.verify($P, JWK.None); + follows: + pattern: const { JWK, JWT } = $JOSE; + follows: + pattern: const $JOSE = require("jose"); + - pattern: JWT.verify($P, JWK.None); + follows: + pattern: const { JWK, JWT } = $JOSE; + follows: + pattern: const $JOSE = require("jose"); + + - pattern: var $T = JWT.verify($P, JWK.None); + follows: + pattern: var { JWK, JWT } = $JOSE; + follows: + pattern: var $JOSE = require("jose"); + - pattern: $T = JWT.verify($P, JWK.None); + follows: + pattern: var { JWK, JWT } = $JOSE; + follows: + pattern: var $JOSE = require("jose"); + - pattern: JWT.verify($P, JWK.None); + follows: + pattern: var { JWK, JWT } = $JOSE; + follows: + pattern: var $JOSE = require("jose"); diff --git a/rules/javascript/jwt/jwt-simple-noverify-js.yml b/rules/javascript/jwt/jwt-simple-noverify-js.yml new file mode 100644 index 00000000..09f57f28 --- /dev/null +++ b/rules/javascript/jwt/jwt-simple-noverify-js.yml @@ -0,0 +1,45 @@ +id: jwt-simple-noverify-js +language: JavaScript +severity: warning +message: >- + "Detected the decoding of a JWT token without a verify step. JWT tokens + must be verified before use, otherwise the token's integrity is unknown. + This means a malicious actor could forge a JWT token with any claims. Set + 'verify' to `true` before using the token." +note: >- + [CWE-287] Improper Authentication + [CWE-345] Insufficient Verification of Data Authenticity + [CWE-347] Improper Verification of Cryptographic Signature + [REFERENCES] + - https://www.npmjs.com/package/jwt-simple + - https://cwe.mitre.org/data/definitions/287 + - https://cwe.mitre.org/data/definitions/345 + - https://cwe.mitre.org/data/definitions/347 +rule: + kind: call_expression + any: + - pattern: $JWT.decode($TOKEN, $SECRET, true $$$) + - pattern: $JWT.decode($TOKEN, $SECRET, "$$$" $$$) + - pattern: $JWT.decode($TOKEN, $SECRET, '$$$' $$$) + - pattern: $JWT.decode($TOKEN, $SECRET, `$$$` $$$) + inside: + kind: expression_statement + stopBy: end + follows: + stopBy: end + any: + - kind: lexical_declaration + all: + - has: + stopBy: end + kind: identifier + pattern: $JWT + - has: + stopBy: end + kind: call_expression + pattern: require('jwt-simple') + - kind: expression_statement + has: + stopBy: end + kind: assignment_expression + pattern: $JWT = require('jwt-simple') diff --git a/rules/javascript/security/detect-angular-sce-disabled-javascript.yml b/rules/javascript/security/detect-angular-sce-disabled-javascript.yml new file mode 100644 index 00000000..184059f0 --- /dev/null +++ b/rules/javascript/security/detect-angular-sce-disabled-javascript.yml @@ -0,0 +1,15 @@ +id: detect-angular-sce-disabled-javascript +language: javascript +severity: warning +message: >- + $sceProvider is set to false. Disabling Strict Contextual escaping + (SCE) in an AngularJS application could provide additional attack surface + for XSS vulnerabilities. +note: >- + [CWE-79] Improper Neutralization of Input During Web Page Generation. + [REFERENCES] + - https://docs.angularjs.org/api/ng/service/$sce + - https://owasp.org/www-chapter-london/assets/slides/OWASPLondon20170727_AngularJS.pdf +rule: + pattern: | + $sceProvider.enabled(false); diff --git a/rules/javascript/security/node-sequelize-empty-password-argument-javascript.yml b/rules/javascript/security/node-sequelize-empty-password-argument-javascript.yml new file mode 100644 index 00000000..eaabe687 --- /dev/null +++ b/rules/javascript/security/node-sequelize-empty-password-argument-javascript.yml @@ -0,0 +1,78 @@ +id: node-sequelize-empty-password-argument-javascript +language: javascript +severity: warning +message: >- + The application creates a database connection with an empty password. + This can lead to unauthorized access by either an internal or external + malicious actor. To prevent this vulnerability, enforce authentication + when connecting to a database by using environment variables to securely + provide credentials or retrieving them from a secure vault or HSM + (Hardware Security Module). +note: >- + [CWE-287] Improper Authentication. + [REFERENCES] + - https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html +utils: + MATCH_BLANK_PASSWORD: + kind: string + pattern: $Q + inside: + stopBy: end + kind: lexical_declaration + all: + - has: + stopBy: end + kind: new_expression + all: + - has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: end + kind: arguments + nthChild: 2 + has: + stopBy: end + kind: string + nthChild: 3 + pattern: $Q + not: + has: + stopBy: end + kind: string_fragment + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + has: + stopBy: end + kind: identifier + pattern: $E + - follows: + stopBy: end + kind: import_statement + has: + stopBy: end + kind: import_clause + has: + stopBy: end + kind: identifier + pattern: $E + - follows: + stopBy: end + kind: import_statement + has: + stopBy: end + kind: import_clause + has: + stopBy: end + kind: identifier + pattern: $E + +rule: + kind: string + matches: MATCH_BLANK_PASSWORD diff --git a/rules/javascript/security/node-sequelize-hardcoded-secret-argument-javascript.yml b/rules/javascript/security/node-sequelize-hardcoded-secret-argument-javascript.yml new file mode 100644 index 00000000..ae91bd16 --- /dev/null +++ b/rules/javascript/security/node-sequelize-hardcoded-secret-argument-javascript.yml @@ -0,0 +1,77 @@ +id: node-sequelize-hardcoded-secret-argument-javascript +language: javascript +severity: warning +message: >- + The application creates a database connection with an empty password. + This can lead to unauthorized access by either an internal or external + malicious actor. To prevent this vulnerability, enforce authentication + when connecting to a database by using environment variables to securely + provide credentials or retrieving them from a secure vault or HSM + (Hardware Security Module). +note: >- + [CWE-287] Improper Authentication. + [REFERENCES] + - https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html +utils: + MATCH_BLANK_PASSWORD: + kind: string + pattern: $Q + inside: + stopBy: end + kind: lexical_declaration + all: + - has: + stopBy: end + kind: new_expression + all: + - has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: end + kind: arguments + nthChild: 2 + has: + stopBy: end + kind: string + nthChild: 3 + pattern: $Q + has: + stopBy: end + kind: string_fragment + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + has: + stopBy: end + kind: identifier + pattern: $E + - follows: + stopBy: end + kind: import_statement + has: + stopBy: end + kind: import_clause + has: + stopBy: end + kind: identifier + pattern: $E + - follows: + stopBy: end + kind: import_statement + has: + stopBy: end + kind: import_clause + has: + stopBy: end + kind: identifier + pattern: $E + +rule: + kind: string + matches: MATCH_BLANK_PASSWORD diff --git a/rules/php/security/openssl-cbc-static-iv-php.yml b/rules/php/security/openssl-cbc-static-iv-php.yml new file mode 100644 index 00000000..710d8118 --- /dev/null +++ b/rules/php/security/openssl-cbc-static-iv-php.yml @@ -0,0 +1,190 @@ +id: openssl-cbc-static-iv-php +language: php +severity: warning +message: >- + Static IV used with AES in CBC mode. Static IVs enable chosen-plaintext + attacks against encrypted data. +note: >- + [CWE-329] Generation of Predictable IV with CBC Mode. + [REFERENCES] + - https://csrc.nist.gov/publications/detail/sp/800-38a/final +utils: + Match_pattern_with_prefix_openssl_encrypt: + kind: expression_statement + all: + - has: + stopBy: end + kind: function_call_expression + all: + - has: + stopBy: end + kind: name + regex: (openssl_decrypt|openssl_encrypt) + - has: + stopBy: end + kind: arguments + all: + - has: + stopBy: end + kind: argument + nthChild: 2 + has: + stopBy: end + kind: variable_name + pattern: $R + - has: + stopBy: end + kind: argument + nthChild: 5 + has: + stopBy: end + kind: variable_name + pattern: $T + + - follows: + stopBy: end + kind: expression_statement + has: + stopBy: end + kind: assignment_expression + all: + - has: + stopBy: end + kind: variable_name + pattern: $T + - has: + stopBy: end + kind: encapsed_string + + - follows: + stopBy: end + kind: expression_statement + has: + stopBy: end + kind: assignment_expression + all: + - has: + stopBy: end + kind: variable_name + pattern: $R + - has: + stopBy: end + kind: encapsed_string + regex: "^.*-CBC" + + Match_pattern_with_prefix_openssl_decrypt: + kind: return_statement + all: + - has: + stopBy: end + kind: function_call_expression + regex: (openssl_decrypt|openssl_encrypt) + has: + stopBy: end + kind: arguments + all: + - has: + stopBy: end + kind: argument + nthChild: 2 + has: + stopBy: end + kind: variable_name + pattern: $R + - has: + stopBy: end + kind: argument + nthChild: 5 + has: + stopBy: end + kind: variable_name + pattern: $T + + - follows: + stopBy: end + kind: expression_statement + has: + stopBy: end + kind: assignment_expression + all: + - has: + stopBy: end + kind: variable_name + pattern: $T + - has: + stopBy: end + kind: encapsed_string + + - follows: + stopBy: end + kind: expression_statement + has: + stopBy: end + kind: assignment_expression + all: + - has: + stopBy: end + kind: variable_name + pattern: $R + - has: + stopBy: end + kind: encapsed_string + regex: "^.*-CBC" + + Match_pattern_directly_with_prefix_openssl_encrypt: + kind: expression_statement + all: + - has: + stopBy: end + kind: function_call_expression + all: + - has: + stopBy: end + kind: name + regex: (openssl_decrypt|openssl_encrypt) + - has: + stopBy: end + kind: arguments + all: + - has: + stopBy: end + kind: argument + nthChild: 2 + has: + stopBy: end + kind: encapsed_string + regex: "^.*-CBC" + + - has: + stopBy: end + kind: argument + nthChild: 5 + has: + stopBy: end + kind: variable_name + pattern: $T + + - follows: + stopBy: end + kind: expression_statement + has: + stopBy: end + kind: assignment_expression + all: + - has: + stopBy: end + kind: variable_name + pattern: $T + - has: + stopBy: end + kind: encapsed_string + +rule: + any: + - kind: expression_statement + any: + - matches: Match_pattern_with_prefix_openssl_encrypt + - matches: Match_pattern_directly_with_prefix_openssl_encrypt + - kind: return_statement + any: + - matches: Match_pattern_with_prefix_openssl_decrypt diff --git a/rules/python/security/hashids-with-django-secret-python.yml b/rules/python/security/hashids-with-django-secret-python.yml new file mode 100644 index 00000000..d861b038 --- /dev/null +++ b/rules/python/security/hashids-with-django-secret-python.yml @@ -0,0 +1,18 @@ +id: hashids-with-django-secret-python +language: python +severity: warning +message: >- + The Django secret key is used as salt in HashIDs. The HashID mechanism + is not secure. By observing sufficient HashIDs, the salt used to construct + them can be recovered. This means the Django secret key can be obtained by + attackers, through the HashIDs. +note: >- + [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm + [OWASP A02:2021]: Cryptographic Failures + [REFERENCES] + https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-SECRET_KEY + http://carnage.github.io/2015/08/cryptanalysis-of-hashids +rule: + any: + - pattern: Hashids(salt=settings.SECRET_KEY, $$$) + - pattern: Hashids(settings.SECRET_KEY, $$$) diff --git a/rules/python/security/jwt-python-hardcoded-secret-python.yml b/rules/python/security/jwt-python-hardcoded-secret-python.yml new file mode 100644 index 00000000..eae611c3 --- /dev/null +++ b/rules/python/security/jwt-python-hardcoded-secret-python.yml @@ -0,0 +1,98 @@ +id: jwt-python-hardcoded-secret-python +severity: warning +language: python +message: >- + Hardcoded JWT secret or private key is used. This is a Insufficiently + Protected Credentials weakness: + https://cwe.mitre.org/data/definitions/522.html Consider using an + appropriate security mechanism to protect the credentials (e.g. keeping + secrets in environment variables). +note: >- + [CWE-522] Insufficiently Protected Credentials. +utils: + match_pattern_followed_by_instance: + inside: + stopBy: end + kind: function_definition + has: + stopBy: end + kind: expression_statement + pattern: $C + has: + kind: assignment + has: + kind: call + has: + kind: argument_list + has: + kind: identifier + nthChild: 2 + pattern: $S + + match_pattern_followed_by_instance_name: + inside: + stopBy: end + kind: function_definition + has: + stopBy: end + kind: expression_statement + pattern: $C + has: + kind: assignment + has: + kind: call + has: + kind: attribute + regex: ^jwt.encode + + match_pattern_followed_by_instance_value: + follows: + stopBy: end + kind: expression_statement + has: + stopBy: end + kind: assignment + all: + - has: + stopBy: end + kind: identifier + pattern: $S + - has: + stopBy: end + kind: string + + combined_utils: + all: + - matches: match_pattern_followed_by_instance + - matches: match_pattern_followed_by_instance_value + - matches: match_pattern_followed_by_instance_name + + match_pattern_followed_by_instance_value_one: + has: + kind: assignment + has: + kind: call + has: + kind: argument_list + has: + kind: string + nthChild: 2 + + match_pattern_followed_by_instance_value_two: + has: + kind: assignment + has: + kind: call + has: + kind: attribute + regex: ^jwt.encode + + combined_utils_two: + all: + - matches: match_pattern_followed_by_instance_value_one + - matches: match_pattern_followed_by_instance_value_two +rule: + kind: expression_statement + any: + - matches: combined_utils + - matches: combined_utils_two diff --git a/rules/python/security/python-cassandra-empty-password-python.yml b/rules/python/security/python-cassandra-empty-password-python.yml new file mode 100644 index 00000000..060ce96d --- /dev/null +++ b/rules/python/security/python-cassandra-empty-password-python.yml @@ -0,0 +1,51 @@ +id: python-cassandra-empty-password-python +language: python +severity: warning +message: >- + The application creates a database connection with an empty password. + This can lead to unauthorized access by either an internal or external + malicious actor. To prevent this vulnerability, enforce authentication + when connecting to a database by using environment variables to securely + provide credentials or retrieving them from a secure vault or HSM + (Hardware Security Module). +note: >- + [CWE-287]: Improper Authentication + [REFERENCES] + - https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html + +utils: + from_imported_module: + any: + - pattern: PlainTextAuthProvider($USER, $QUOTES) + - pattern: PlainTextAuthProvider($USER, $QUOTES, $$$) + - pattern: PlainTextAuthProvider($$$, password=$QUOTES) + - pattern: PlainTextAuthProvider($$$, password=$QUOTES, $$$) + - pattern: SaslAuthProvider($$$, password=$QUOTES) + - pattern: SaslAuthProvider($$$, password=$QUOTES, $$$) + - pattern: PlainTextAuthProvider(username='user', password='') + + inside_module_with_import_statement: + inside: + stopBy: end + kind: module + has: + kind: import_from_statement + pattern: from cassandra.auth import PlainTextAuthProvider + +rule: + any: + - pattern: cassandra.auth.PlainTextAuthProvider($USER, $QUOTES) + - pattern: cassandra.auth.PlainTextAuthProvider($USER, $QUOTES, $$$) + - pattern: cassandra.auth.PlainTextAuthProvider($$$, password=$QUOTES) + - pattern: cassandra.auth.PlainTextAuthProvider($$$, password=$QUOTES, $$$) + - pattern: cassandra.auth.SaslAuthProvider($$$, password=$QUOTES) + - pattern: cassandra.auth.SaslAuthProvider($$$, password=$QUOTES, $$$) + - any: + - matches: from_imported_module + follows: + stopBy: end + matches: inside_module_with_import_statement + +constraints: + QUOTES: + regex: (''|""|``) diff --git a/rules/python/security/python-elasticsearch-hardcoded-bearer-auth-python.yml b/rules/python/security/python-elasticsearch-hardcoded-bearer-auth-python.yml new file mode 100644 index 00000000..9c5bc077 --- /dev/null +++ b/rules/python/security/python-elasticsearch-hardcoded-bearer-auth-python.yml @@ -0,0 +1,29 @@ +id: python-elasticsearch-hardcoded-bearer-auth-python +severity: warning +language: python +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 +rule: + any: + - pattern: Elasticsearch($$$, bearer_auth="$$$",$$$) + - pattern: Elasticsearch($$$,bearer_auth=$$$) + - pattern: $ES.options(bearer_auth="$$$").$$$ + not: + follows: + pattern: elasticsearch.Elasticsearch($$$) + - pattern: $ES.options($$$,bearer_auth="$$$").$$$ + not: + follows: + pattern: elasticsearch.Elasticsearch($$$) + - pattern: $ES.options($$$,bearer_auth="$$$",$$$) + not: + follows: + pattern: elasticsearch.Elasticsearch($$$) diff --git a/rules/typescript/.gitkeep b/rules/typescript/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/rules/typescript/jwt/jwt-none-alg-typescript.yml b/rules/typescript/jwt/jwt-none-alg-typescript.yml new file mode 100644 index 00000000..1badeba2 --- /dev/null +++ b/rules/typescript/jwt/jwt-none-alg-typescript.yml @@ -0,0 +1,46 @@ +id: jwt-none-alg-typescript +language: typescript +severity: warning +message: >- + Detected use of the 'none' algorithm in a JWT token. The 'none' + algorithm assumes the integrity of the token has already been verified. + This would allow a malicious actor to forge a JWT token that will + automatically be verified. Do not explicitly use the 'none' algorithm. + Instead, use an algorithm such as 'HS256'. +note: >- + [CWE-327] Use of a Broken or Risky Cryptographic Algorithm. + [REFERENCES] + - https://owasp.org/Top10/A02_2021-Cryptographic_Failures +rule: + any: + - pattern: const $T = JWT.verify($P, JWK.None); + follows: + pattern: const { JWK, JWT } = $JOSE; + follows: + pattern: const $JOSE = require("jose"); + - pattern: $T = JWT.verify($P, JWK.None); + follows: + pattern: const { JWK, JWT } = $JOSE; + follows: + pattern: const $JOSE = require("jose"); + - pattern: JWT.verify($P, JWK.None); + follows: + pattern: const { JWK, JWT } = $JOSE; + follows: + pattern: const $JOSE = require("jose"); + + - pattern: var $T = JWT.verify($P, JWK.None); + follows: + pattern: var { JWK, JWT } = $JOSE; + follows: + pattern: var $JOSE = require("jose"); + - pattern: $T = JWT.verify($P, JWK.None); + follows: + pattern: var { JWK, JWT } = $JOSE; + follows: + pattern: var $JOSE = require("jose"); + - pattern: JWT.verify($P, JWK.None); + follows: + pattern: var { JWK, JWT } = $JOSE; + follows: + pattern: var $JOSE = require("jose"); diff --git a/rules/typescript/jwt/jwt-simple-noverify-ts.yml b/rules/typescript/jwt/jwt-simple-noverify-ts.yml new file mode 100644 index 00000000..2f58eb0f --- /dev/null +++ b/rules/typescript/jwt/jwt-simple-noverify-ts.yml @@ -0,0 +1,45 @@ +id: jwt-simple-noverify-ts +language: TypeScript +severity: warning +message: >- + "Detected the decoding of a JWT token without a verify step. JWT tokens + must be verified before use, otherwise the token's integrity is unknown. + This means a malicious actor could forge a JWT token with any claims. Set + 'verify' to `true` before using the token." +note: >- + [CWE-287] Improper Authentication + [CWE-345] Insufficient Verification of Data Authenticity + [CWE-347] Improper Verification of Cryptographic Signature + [REFERENCES] + - https://www.npmjs.com/package/jwt-simple + - https://cwe.mitre.org/data/definitions/287 + - https://cwe.mitre.org/data/definitions/345 + - https://cwe.mitre.org/data/definitions/347 +rule: + kind: call_expression + any: + - pattern: $JWT.decode($TOKEN, $SECRET, true $$$) + - pattern: $JWT.decode($TOKEN, $SECRET, "$$$" $$$) + - pattern: $JWT.decode($TOKEN, $SECRET, '$$$' $$$) + - pattern: $JWT.decode($TOKEN, $SECRET, `$$$` $$$) + inside: + kind: expression_statement + stopBy: end + follows: + stopBy: end + any: + - kind: lexical_declaration + all: + - has: + stopBy: end + kind: identifier + pattern: $JWT + - has: + stopBy: end + kind: call_expression + pattern: require('jwt-simple') + - kind: expression_statement + has: + stopBy: end + kind: assignment_expression + pattern: $JWT = require('jwt-simple') diff --git a/rules/typescript/security/detect-angular-sce-disabled-typescript.yml b/rules/typescript/security/detect-angular-sce-disabled-typescript.yml new file mode 100644 index 00000000..68c6f54c --- /dev/null +++ b/rules/typescript/security/detect-angular-sce-disabled-typescript.yml @@ -0,0 +1,15 @@ +id: detect-angular-sce-disabled-typescript +language: typescript +severity: warning +message: >- + $sceProvider is set to false. Disabling Strict Contextual escaping + (SCE) in an AngularJS application could provide additional attack surface + for XSS vulnerabilities. +note: >- + [CWE-79] Improper Neutralization of Input During Web Page Generation. + [REFERENCES] + - https://docs.angularjs.org/api/ng/service/$sce + - https://owasp.org/www-chapter-london/assets/slides/OWASPLondon20170727_AngularJS.pdf +rule: + pattern: | + $sceProvider.enabled(false); diff --git a/rules/typescript/security/node-sequelize-empty-password-argument-typescript.yml b/rules/typescript/security/node-sequelize-empty-password-argument-typescript.yml new file mode 100644 index 00000000..a5eab9dd --- /dev/null +++ b/rules/typescript/security/node-sequelize-empty-password-argument-typescript.yml @@ -0,0 +1,78 @@ +id: node-sequelize-empty-password-argument-typescript +language: typescript +severity: warning +message: >- + The application creates a database connection with an empty password. + This can lead to unauthorized access by either an internal or external + malicious actor. To prevent this vulnerability, enforce authentication + when connecting to a database by using environment variables to securely + provide credentials or retrieving them from a secure vault or HSM + (Hardware Security Module). +note: >- + [CWE-287] Improper Authentication. + [REFERENCES] + - https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html +utils: + MATCH_BLANK_PASSWORD: + kind: string + pattern: $Q + inside: + stopBy: end + kind: lexical_declaration + all: + - has: + stopBy: end + kind: new_expression + all: + - has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: end + kind: arguments + nthChild: 2 + has: + stopBy: end + kind: string + nthChild: 3 + pattern: $Q + not: + has: + stopBy: end + kind: string_fragment + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + has: + stopBy: end + kind: identifier + pattern: $E + - follows: + stopBy: end + kind: import_statement + has: + stopBy: end + kind: import_clause + has: + stopBy: end + kind: identifier + pattern: $E + - follows: + stopBy: end + kind: import_statement + has: + stopBy: end + kind: import_clause + has: + stopBy: end + kind: identifier + pattern: $E + +rule: + kind: string + matches: MATCH_BLANK_PASSWORD diff --git a/rules/typescript/security/node-sequelize-hardcoded-secret-argument-typescript.yml b/rules/typescript/security/node-sequelize-hardcoded-secret-argument-typescript.yml new file mode 100644 index 00000000..e4ea19f9 --- /dev/null +++ b/rules/typescript/security/node-sequelize-hardcoded-secret-argument-typescript.yml @@ -0,0 +1,77 @@ +id: node-sequelize-hardcoded-secret-argument-typescript +language: typescript +severity: warning +message: >- + The application creates a database connection with an empty password. + This can lead to unauthorized access by either an internal or external + malicious actor. To prevent this vulnerability, enforce authentication + when connecting to a database by using environment variables to securely + provide credentials or retrieving them from a secure vault or HSM + (Hardware Security Module). +note: >- + [CWE-287] Improper Authentication. + [REFERENCES] + - https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html +utils: + MATCH_BLANK_PASSWORD: + kind: string + pattern: $Q + inside: + stopBy: end + kind: lexical_declaration + all: + - has: + stopBy: end + kind: new_expression + all: + - has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: end + kind: arguments + nthChild: 2 + has: + stopBy: end + kind: string + nthChild: 3 + pattern: $Q + has: + stopBy: end + kind: string_fragment + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + has: + stopBy: end + kind: identifier + pattern: $E + - follows: + stopBy: end + kind: import_statement + has: + stopBy: end + kind: import_clause + has: + stopBy: end + kind: identifier + pattern: $E + - follows: + stopBy: end + kind: import_statement + has: + stopBy: end + kind: import_clause + has: + stopBy: end + kind: identifier + pattern: $E + +rule: + kind: string + matches: MATCH_BLANK_PASSWORD diff --git a/tests/__snapshots__/avoid-bind-to-all-interfaces-go-snapshot.yml b/tests/__snapshots__/avoid-bind-to-all-interfaces-go-snapshot.yml new file mode 100644 index 00000000..7c22130f --- /dev/null +++ b/tests/__snapshots__/avoid-bind-to-all-interfaces-go-snapshot.yml @@ -0,0 +1,16 @@ +id: avoid-bind-to-all-interfaces-go +snapshots: + ? | + l, err := net.Listen("tcp", "0.0.0.0:2000") + : labels: + - source: net.Listen("tcp", "0.0.0.0:2000") + style: primary + start: 10 + end: 43 + ? | + l, err := net.Listen("tcp", ":2000") + : labels: + - source: net.Listen("tcp", ":2000") + style: primary + start: 10 + end: 36 diff --git a/tests/__snapshots__/detect-angular-sce-disabled-javascript-snapshot.yml b/tests/__snapshots__/detect-angular-sce-disabled-javascript-snapshot.yml new file mode 100644 index 00000000..809d3ff2 --- /dev/null +++ b/tests/__snapshots__/detect-angular-sce-disabled-javascript-snapshot.yml @@ -0,0 +1,9 @@ +id: detect-angular-sce-disabled-javascript +snapshots: + ? | + $sceProvider.enabled(false); + : labels: + - source: $sceProvider.enabled(false); + style: primary + start: 0 + end: 28 diff --git a/tests/__snapshots__/detect-angular-sce-disabled-typescript-snapshot.yml b/tests/__snapshots__/detect-angular-sce-disabled-typescript-snapshot.yml new file mode 100644 index 00000000..8142ea9d --- /dev/null +++ b/tests/__snapshots__/detect-angular-sce-disabled-typescript-snapshot.yml @@ -0,0 +1,9 @@ +id: detect-angular-sce-disabled-typescript +snapshots: + ? | + $sceProvider.enabled(false); + : labels: + - source: $sceProvider.enabled(false); + style: primary + start: 0 + end: 28 diff --git a/tests/__snapshots__/documentbuilderfactory-disallow-doctype-decl-false-java-snapshot.yml b/tests/__snapshots__/documentbuilderfactory-disallow-doctype-decl-false-java-snapshot.yml new file mode 100644 index 00000000..ae72bb04 --- /dev/null +++ b/tests/__snapshots__/documentbuilderfactory-disallow-doctype-decl-false-java-snapshot.yml @@ -0,0 +1,36 @@ +id: documentbuilderfactory-disallow-doctype-decl-false-java +snapshots: + ? | + ParserConfigurationException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + //ruleid:documentbuilderfactory-disallow-doctype-decl-false + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false); + //fix:documentbuilderfactory-disallow-doctype-decl-false + //dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + } + : labels: + - source: dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false); + style: primary + start: 170 + end: 248 + - source: DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + style: secondary + start: 35 + end: 101 + ? | + ParserConfigurationException { + SAXParserFactory spf = SAXParserFactory.newInstance(); + //ruleid:documentbuilderfactory-disallow-doctype-decl-false + spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false); + //fix:documentbuilderfactory-disallow-doctype-decl-false + //spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + } + : labels: + - source: spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false); + style: primary + start: 158 + end: 236 + - source: SAXParserFactory spf = SAXParserFactory.newInstance(); + style: secondary + start: 35 + end: 89 diff --git a/tests/__snapshots__/documentbuilderfactory-external-parameter-entities-true-java-snapshot.yml b/tests/__snapshots__/documentbuilderfactory-external-parameter-entities-true-java-snapshot.yml new file mode 100644 index 00000000..c10c8249 --- /dev/null +++ b/tests/__snapshots__/documentbuilderfactory-external-parameter-entities-true-java-snapshot.yml @@ -0,0 +1,10 @@ +id: documentbuilderfactory-external-parameter-entities-true-java +snapshots: + ? | + dbf.setFeature("http://xml.org/sax/features/external-parameter-entities" , true); + spf.setFeature("http://xml.org/sax/features/external-parameter-entities" , true); + : labels: + - source: dbf.setFeature("http://xml.org/sax/features/external-parameter-entities" , true); + style: primary + start: 0 + end: 81 diff --git a/tests/__snapshots__/gcm-nonce-reuse-java-snapshot.yml b/tests/__snapshots__/gcm-nonce-reuse-java-snapshot.yml new file mode 100644 index 00000000..91128348 --- /dev/null +++ b/tests/__snapshots__/gcm-nonce-reuse-java-snapshot.yml @@ -0,0 +1,14 @@ +id: gcm-nonce-reuse-java +snapshots: + ? | + byte[] theBadIV = BAD_IV.getBytes(); + GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, theBadIV); + : labels: + - source: GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, theBadIV); + style: primary + start: 37 + end: 124 + - source: byte[] theBadIV = BAD_IV.getBytes(); + style: secondary + start: 0 + end: 36 diff --git a/tests/__snapshots__/grpc-client-insecure-connection-go-snapshot.yml b/tests/__snapshots__/grpc-client-insecure-connection-go-snapshot.yml new file mode 100644 index 00000000..18911bf9 --- /dev/null +++ b/tests/__snapshots__/grpc-client-insecure-connection-go-snapshot.yml @@ -0,0 +1,9 @@ +id: grpc-client-insecure-connection-go +snapshots: + ? | + conn, err := grpc.Dial(address, grpc.WithInsecure()) + : labels: + - source: grpc.Dial(address, grpc.WithInsecure()) + style: primary + start: 13 + end: 52 diff --git a/tests/__snapshots__/grpc-client-insecure-connection-snapshot.yml b/tests/__snapshots__/grpc-client-insecure-connection-snapshot.yml deleted file mode 100644 index 4047934f..00000000 --- a/tests/__snapshots__/grpc-client-insecure-connection-snapshot.yml +++ /dev/null @@ -1,43 +0,0 @@ -id: grpc-client-insecure-connection -snapshots: - ? | - grpc.Dial("example.com", grpc.WithInsecure()) - : labels: - - source: grpc.Dial("example.com", grpc.WithInsecure()) - style: primary - start: 0 - end: 45 - ? | - grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock()) - : labels: - - source: grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock()) - style: primary - start: 0 - end: 63 - ? | - grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(5*time.Second)) - : labels: - - source: grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(5*time.Second)) - style: primary - start: 0 - end: 96 - ? | - grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(5*time.Second), grpc.WithUserAgent("example")) - : labels: - - source: grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(5*time.Second), grpc.WithUserAgent("example")) - style: primary - start: 0 - end: 127 - ? | - grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(5*time.Second), grpc.WithUserAgent("example"), grpc.WithAuthority("example.com")) - : labels: - - source: grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(5*time.Second), grpc.WithUserAgent("example"), grpc.WithAuthority("example.com")) - style: primary - start: 0 - end: 162 - ? grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(5*time.Second), grpc.WithUserAgent("example"), grpc.WithAuthority("example.com"), grpc.WithDial) - : labels: - - source: grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(5*time.Second), grpc.WithUserAgent("example"), grpc.WithAuthority("example.com"), grpc.WithDial) - style: primary - start: 0 - end: 177 diff --git a/tests/__snapshots__/hashids-with-django-secret-python-snapshot.yml b/tests/__snapshots__/hashids-with-django-secret-python-snapshot.yml new file mode 100644 index 00000000..da2eddb5 --- /dev/null +++ b/tests/__snapshots__/hashids-with-django-secret-python-snapshot.yml @@ -0,0 +1,11 @@ +id: hashids-with-django-secret-python +snapshots: + ? | + Hashids(salt=settings.SECRET_KEY, min_length=settings.ID_HASH_MIN_LENGTH) + Hashids(salt=settings.SECRET_KEY, min_length=4, alphabet="abcdefghijklmnopqrstuvwxyz") + Hashids(settings.SECRET_KEY, min_length=length, alphabet=alphabet) + : labels: + - source: Hashids(salt=settings.SECRET_KEY, min_length=settings.ID_HASH_MIN_LENGTH) + style: primary + start: 0 + end: 73 diff --git a/tests/__snapshots__/jwt-go-none-algorithm-go-snapshot.yml b/tests/__snapshots__/jwt-go-none-algorithm-go-snapshot.yml new file mode 100644 index 00000000..17c8ceef --- /dev/null +++ b/tests/__snapshots__/jwt-go-none-algorithm-go-snapshot.yml @@ -0,0 +1,90 @@ +id: jwt-go-none-algorithm-go +snapshots: + ? | + import ( + "fmt" + "github.com/dgrijalva/jwt-go" + ) + func bad1(key []byte) { + claims := jwt.StandardClaims{ + ExpiresAt:15000, + Issuer:"test",} + token := jwt.NewWithClaims(jwt.SigningMethodNone, claims) + ss, err := token.SignedString(jwt.UnsafeAllowNoneSignatureType) + fmt.Printf("%v %v\n", ss, err)} + : labels: + - source: jwt.SigningMethodNone + style: primary + start: 172 + end: 193 + - source: |- + ( + "fmt" + "github.com/dgrijalva/jwt-go" + ) + style: secondary + start: 7 + end: 51 + - source: |- + import ( + "fmt" + "github.com/dgrijalva/jwt-go" + ) + style: secondary + start: 0 + end: 51 + - source: |- + func bad1(key []byte) { + claims := jwt.StandardClaims{ + ExpiresAt:15000, + Issuer:"test",} + token := jwt.NewWithClaims(jwt.SigningMethodNone, claims) + ss, err := token.SignedString(jwt.UnsafeAllowNoneSignatureType) + fmt.Printf("%v %v\n", ss, err)} + style: secondary + start: 52 + end: 298 + ? | + import ( + "fmt" + "github.com/dgrijalva/jwt-go" + ) + func bad1(key []byte) { + claims = jwt.StandardClaims{ + ExpiresAt:15000, + Issuer:"test",} + token = jwt.NewWithClaims(jwt.SigningMethodNone, claims) + ss, err = token.SignedString(jwt.UnsafeAllowNoneSignatureType) + fmt.Printf("%v %v\n", ss, err)} + : labels: + - source: jwt.SigningMethodNone + style: primary + start: 170 + end: 191 + - source: |- + ( + "fmt" + "github.com/dgrijalva/jwt-go" + ) + style: secondary + start: 7 + end: 51 + - source: |- + import ( + "fmt" + "github.com/dgrijalva/jwt-go" + ) + style: secondary + start: 0 + end: 51 + - source: |- + func bad1(key []byte) { + claims = jwt.StandardClaims{ + ExpiresAt:15000, + Issuer:"test",} + token = jwt.NewWithClaims(jwt.SigningMethodNone, claims) + ss, err = token.SignedString(jwt.UnsafeAllowNoneSignatureType) + fmt.Printf("%v %v\n", ss, err)} + style: secondary + start: 52 + end: 295 diff --git a/tests/__snapshots__/jwt-none-alg-javascript-snapshot.yml b/tests/__snapshots__/jwt-none-alg-javascript-snapshot.yml new file mode 100644 index 00000000..d1fe39db --- /dev/null +++ b/tests/__snapshots__/jwt-none-alg-javascript-snapshot.yml @@ -0,0 +1,19 @@ +id: jwt-none-alg-javascript +snapshots: + ? | + const jose = require("jose"); + const { JWK, JWT } = jose; + const token = JWT.verify('token-here', JWK.None); + : labels: + - source: const token = JWT.verify('token-here', JWK.None); + style: primary + start: 57 + end: 106 + - source: const jose = require("jose"); + style: secondary + start: 0 + end: 29 + - source: const { JWK, JWT } = jose; + style: secondary + start: 30 + end: 56 diff --git a/tests/__snapshots__/jwt-none-alg-typescript-snapshot.yml b/tests/__snapshots__/jwt-none-alg-typescript-snapshot.yml new file mode 100644 index 00000000..1cb4f8a7 --- /dev/null +++ b/tests/__snapshots__/jwt-none-alg-typescript-snapshot.yml @@ -0,0 +1,19 @@ +id: jwt-none-alg-typescript +snapshots: + ? | + const jose = require("jose"); + const { JWK, JWT } = jose; + const token = JWT.verify('token-here', JWK.None); + : labels: + - source: const token = JWT.verify('token-here', JWK.None); + style: primary + start: 57 + end: 106 + - source: const jose = require("jose"); + style: secondary + start: 0 + end: 29 + - source: const { JWK, JWT } = jose; + style: secondary + start: 30 + end: 56 diff --git a/tests/__snapshots__/jwt-python-hardcoded-secret-python-snapshot.yml b/tests/__snapshots__/jwt-python-hardcoded-secret-python-snapshot.yml new file mode 100644 index 00000000..e8384206 --- /dev/null +++ b/tests/__snapshots__/jwt-python-hardcoded-secret-python-snapshot.yml @@ -0,0 +1,40 @@ +id: jwt-python-hardcoded-secret-python +snapshots: + ? | + encoded = jwt.encode({"some": "payload"}, "secret", algorithm="HS256") + encoded = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256') + secret = "secret" + encoded = jwt.encode({"some": "payload"}, secret, algorithm="HS256") + : labels: + - source: 'encoded = jwt.encode({"some": "payload"}, "secret", algorithm="HS256")' + style: primary + start: 0 + end: 70 + - source: '"secret"' + style: secondary + start: 42 + end: 50 + - source: '({"some": "payload"}, "secret", algorithm="HS256")' + style: secondary + start: 20 + end: 70 + - source: 'jwt.encode({"some": "payload"}, "secret", algorithm="HS256")' + style: secondary + start: 10 + end: 70 + - source: 'encoded = jwt.encode({"some": "payload"}, "secret", algorithm="HS256")' + style: secondary + start: 0 + end: 70 + - source: jwt.encode + style: secondary + start: 10 + end: 20 + - source: 'jwt.encode({"some": "payload"}, "secret", algorithm="HS256")' + style: secondary + start: 10 + end: 70 + - source: 'encoded = jwt.encode({"some": "payload"}, "secret", algorithm="HS256")' + style: secondary + start: 0 + end: 70 diff --git a/tests/__snapshots__/jwt-simple-noverify-js-snapshot.yml b/tests/__snapshots__/jwt-simple-noverify-js-snapshot.yml new file mode 100644 index 00000000..3394c951 --- /dev/null +++ b/tests/__snapshots__/jwt-simple-noverify-js-snapshot.yml @@ -0,0 +1,68 @@ +id: jwt-simple-noverify-js +snapshots: + ? "const jwt = require('jwt-simple'); \n\napp.get('/protectedRoute1', (req, res) => {\n const token = req.headers.authorization;\n\n if (!token) {\n return res.status(401).json({ error: 'Unauthorized. Token missing.' });\n }\n\n try {\n // ruleid: jwt-simple-noverify \n const decoded = jwt.decode(token, secretKey, 'HS256', 12);\n res.json({ message: `Hello ${decoded.username}` });\n } catch (error) {\n res.status(401).json({ error: 'Unauthorized. Invalid token.' });\n }\n});\n" + : labels: + - source: jwt.decode(token, secretKey, 'HS256', 12) + style: primary + start: 287 + end: 328 + - source: jwt + style: secondary + start: 6 + end: 9 + - source: require('jwt-simple') + style: secondary + start: 12 + end: 33 + - source: const jwt = require('jwt-simple'); + style: secondary + start: 0 + end: 34 + - source: "app.get('/protectedRoute1', (req, res) => {\n const token = req.headers.authorization;\n\n if (!token) {\n return res.status(401).json({ error: 'Unauthorized. Token missing.' });\n }\n\n try {\n // ruleid: jwt-simple-noverify \n const decoded = jwt.decode(token, secretKey, 'HS256', 12);\n res.json({ message: `Hello ${decoded.username}` });\n } catch (error) {\n res.status(401).json({ error: 'Unauthorized. Invalid token.' });\n }\n});" + style: secondary + start: 37 + end: 482 + ? "const jwt = require('jwt-simple'); \n\napp.get('/protectedRoute2', (req, res) => {\n const token = req.headers.authorization;\n\n if (!token) {\n return res.status(401).json({ error: 'Unauthorized. Token missing.' });\n }\n\n try {\n // ruleid: jwt-simple-noverify \n const decoded = jwt.decode(token, secretKey, true);\n res.json({ message: `Hello ${decoded.username}` });\n } catch (error) {\n res.status(401).json({ error: 'Unauthorized. Invalid token.' });\n }\n});\n" + : labels: + - source: jwt.decode(token, secretKey, true) + style: primary + start: 289 + end: 323 + - source: jwt + style: secondary + start: 6 + end: 9 + - source: require('jwt-simple') + style: secondary + start: 12 + end: 33 + - source: const jwt = require('jwt-simple'); + style: secondary + start: 0 + end: 34 + - source: "app.get('/protectedRoute2', (req, res) => {\n const token = req.headers.authorization;\n\n if (!token) {\n return res.status(401).json({ error: 'Unauthorized. Token missing.' });\n }\n\n try {\n // ruleid: jwt-simple-noverify \n const decoded = jwt.decode(token, secretKey, true);\n res.json({ message: `Hello ${decoded.username}` });\n } catch (error) {\n res.status(401).json({ error: 'Unauthorized. Invalid token.' });\n }\n});" + style: secondary + start: 38 + end: 477 + ? "const jwt = require('jwt-simple'); \n\napp.get('/protectedRoute3', (req, res) => {\n const token = req.headers.authorization;\n\n if (!token) {\n return res.status(401).json({ error: 'Unauthorized. Token missing.' });\n }\n\n try {\n // ruleid: jwt-simple-noverify \n const decoded = jwt.decode(token, secretKey, 'false');\n res.json({ message: `Hello ${decoded.username}` });\n } catch (error) {\n res.status(401).json({ error: 'Unauthorized. Invalid token.' });\n }\n});\n" + : labels: + - source: jwt.decode(token, secretKey, 'false') + style: primary + start: 290 + end: 327 + - source: jwt + style: secondary + start: 6 + end: 9 + - source: require('jwt-simple') + style: secondary + start: 12 + end: 33 + - source: const jwt = require('jwt-simple'); + style: secondary + start: 0 + end: 34 + - source: "app.get('/protectedRoute3', (req, res) => {\n const token = req.headers.authorization;\n\n if (!token) {\n return res.status(401).json({ error: 'Unauthorized. Token missing.' });\n }\n\n try {\n // ruleid: jwt-simple-noverify \n const decoded = jwt.decode(token, secretKey, 'false');\n res.json({ message: `Hello ${decoded.username}` });\n } catch (error) {\n res.status(401).json({ error: 'Unauthorized. Invalid token.' });\n }\n});" + style: secondary + start: 38 + end: 481 diff --git a/tests/__snapshots__/jwt-simple-noverify-ts-snapshot.yml b/tests/__snapshots__/jwt-simple-noverify-ts-snapshot.yml new file mode 100644 index 00000000..52b0aea6 --- /dev/null +++ b/tests/__snapshots__/jwt-simple-noverify-ts-snapshot.yml @@ -0,0 +1,68 @@ +id: jwt-simple-noverify-ts +snapshots: + ? "const jwt = require('jwt-simple'); \n\napp.get('/protectedRoute1', (req, res) => {\n const token = req.headers.authorization;\n\n if (!token) {\n return res.status(401).json({ error: 'Unauthorized. Token missing.' });\n }\n\n try {\n // ruleid: jwt-simple-noverify \n const decoded = jwt.decode(token, secretKey, 'HS256', 12);\n res.json({ message: `Hello ${decoded.username}` });\n } catch (error) {\n res.status(401).json({ error: 'Unauthorized. Invalid token.' });\n }\n});\n" + : labels: + - source: jwt.decode(token, secretKey, 'HS256', 12) + style: primary + start: 287 + end: 328 + - source: jwt + style: secondary + start: 6 + end: 9 + - source: require('jwt-simple') + style: secondary + start: 12 + end: 33 + - source: const jwt = require('jwt-simple'); + style: secondary + start: 0 + end: 34 + - source: "app.get('/protectedRoute1', (req, res) => {\n const token = req.headers.authorization;\n\n if (!token) {\n return res.status(401).json({ error: 'Unauthorized. Token missing.' });\n }\n\n try {\n // ruleid: jwt-simple-noverify \n const decoded = jwt.decode(token, secretKey, 'HS256', 12);\n res.json({ message: `Hello ${decoded.username}` });\n } catch (error) {\n res.status(401).json({ error: 'Unauthorized. Invalid token.' });\n }\n});" + style: secondary + start: 37 + end: 482 + ? "const jwt = require('jwt-simple'); \n\napp.get('/protectedRoute2', (req, res) => {\n const token = req.headers.authorization;\n\n if (!token) {\n return res.status(401).json({ error: 'Unauthorized. Token missing.' });\n }\n\n try {\n // ruleid: jwt-simple-noverify \n const decoded = jwt.decode(token, secretKey, true);\n res.json({ message: `Hello ${decoded.username}` });\n } catch (error) {\n res.status(401).json({ error: 'Unauthorized. Invalid token.' });\n }\n});\n" + : labels: + - source: jwt.decode(token, secretKey, true) + style: primary + start: 289 + end: 323 + - source: jwt + style: secondary + start: 6 + end: 9 + - source: require('jwt-simple') + style: secondary + start: 12 + end: 33 + - source: const jwt = require('jwt-simple'); + style: secondary + start: 0 + end: 34 + - source: "app.get('/protectedRoute2', (req, res) => {\n const token = req.headers.authorization;\n\n if (!token) {\n return res.status(401).json({ error: 'Unauthorized. Token missing.' });\n }\n\n try {\n // ruleid: jwt-simple-noverify \n const decoded = jwt.decode(token, secretKey, true);\n res.json({ message: `Hello ${decoded.username}` });\n } catch (error) {\n res.status(401).json({ error: 'Unauthorized. Invalid token.' });\n }\n});" + style: secondary + start: 38 + end: 477 + ? "const jwt = require('jwt-simple'); \n\napp.get('/protectedRoute3', (req, res) => {\n const token = req.headers.authorization;\n\n if (!token) {\n return res.status(401).json({ error: 'Unauthorized. Token missing.' });\n }\n\n try {\n // ruleid: jwt-simple-noverify \n const decoded = jwt.decode(token, secretKey, 'false');\n res.json({ message: `Hello ${decoded.username}` });\n } catch (error) {\n res.status(401).json({ error: 'Unauthorized. Invalid token.' });\n }\n});\n" + : labels: + - source: jwt.decode(token, secretKey, 'false') + style: primary + start: 290 + end: 327 + - source: jwt + style: secondary + start: 6 + end: 9 + - source: require('jwt-simple') + style: secondary + start: 12 + end: 33 + - source: const jwt = require('jwt-simple'); + style: secondary + start: 0 + end: 34 + - source: "app.get('/protectedRoute3', (req, res) => {\n const token = req.headers.authorization;\n\n if (!token) {\n return res.status(401).json({ error: 'Unauthorized. Token missing.' });\n }\n\n try {\n // ruleid: jwt-simple-noverify \n const decoded = jwt.decode(token, secretKey, 'false');\n res.json({ message: `Hello ${decoded.username}` });\n } catch (error) {\n res.status(401).json({ error: 'Unauthorized. Invalid token.' });\n }\n});" + style: secondary + start: 38 + end: 481 diff --git a/tests/__snapshots__/node-sequelize-empty-password-argument-javascript-snapshot.yml b/tests/__snapshots__/node-sequelize-empty-password-argument-javascript-snapshot.yml new file mode 100644 index 00000000..6034344a --- /dev/null +++ b/tests/__snapshots__/node-sequelize-empty-password-argument-javascript-snapshot.yml @@ -0,0 +1,61 @@ +id: node-sequelize-empty-password-argument-javascript +snapshots: + ? | + const Sequelize = require('sequelize'); + const sequelize1 = new Sequelize('database', 'username', '', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + : labels: + - source: '''''' + style: primary + start: 97 + end: 99 + - source: Sequelize + style: secondary + start: 63 + end: 72 + - source: '''''' + style: secondary + start: 97 + end: 99 + - source: |- + ('database', 'username', '', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + style: secondary + start: 72 + end: 158 + - source: |- + new Sequelize('database', 'username', '', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + style: secondary + start: 59 + end: 158 + - source: Sequelize + style: secondary + start: 6 + end: 15 + - source: Sequelize = require('sequelize') + style: secondary + start: 6 + end: 38 + - source: const Sequelize = require('sequelize'); + style: secondary + start: 0 + end: 39 + - source: |- + const sequelize1 = new Sequelize('database', 'username', '', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + style: secondary + start: 40 + end: 158 diff --git a/tests/__snapshots__/node-sequelize-empty-password-argument-typescript-snapshot.yml b/tests/__snapshots__/node-sequelize-empty-password-argument-typescript-snapshot.yml new file mode 100644 index 00000000..9efc0238 --- /dev/null +++ b/tests/__snapshots__/node-sequelize-empty-password-argument-typescript-snapshot.yml @@ -0,0 +1,61 @@ +id: node-sequelize-empty-password-argument-typescript +snapshots: + ? | + const Sequelize = require('sequelize'); + const sequelize1 = new Sequelize('database', 'username', '', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + : labels: + - source: '''''' + style: primary + start: 97 + end: 99 + - source: Sequelize + style: secondary + start: 63 + end: 72 + - source: '''''' + style: secondary + start: 97 + end: 99 + - source: |- + ('database', 'username', '', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + style: secondary + start: 72 + end: 158 + - source: |- + new Sequelize('database', 'username', '', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + style: secondary + start: 59 + end: 158 + - source: Sequelize + style: secondary + start: 6 + end: 15 + - source: Sequelize = require('sequelize') + style: secondary + start: 6 + end: 38 + - source: const Sequelize = require('sequelize'); + style: secondary + start: 0 + end: 39 + - source: |- + const sequelize1 = new Sequelize('database', 'username', '', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + style: secondary + start: 40 + end: 158 diff --git a/tests/__snapshots__/node-sequelize-hardcoded-secret-argument-javascript-snapshot.yml b/tests/__snapshots__/node-sequelize-hardcoded-secret-argument-javascript-snapshot.yml new file mode 100644 index 00000000..a9240aff --- /dev/null +++ b/tests/__snapshots__/node-sequelize-hardcoded-secret-argument-javascript-snapshot.yml @@ -0,0 +1,65 @@ +id: node-sequelize-hardcoded-secret-argument-javascript +snapshots: + ? | + const Sequelize = require('sequelize'); + const sequelize = new Sequelize('database', 'username', 'password', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + : labels: + - source: '''password''' + style: primary + start: 96 + end: 106 + - source: Sequelize + style: secondary + start: 62 + end: 71 + - source: password + style: secondary + start: 97 + end: 105 + - source: '''password''' + style: secondary + start: 96 + end: 106 + - source: |- + ('database', 'username', 'password', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + style: secondary + start: 71 + end: 165 + - source: |- + new Sequelize('database', 'username', 'password', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + style: secondary + start: 58 + end: 165 + - source: Sequelize + style: secondary + start: 6 + end: 15 + - source: Sequelize = require('sequelize') + style: secondary + start: 6 + end: 38 + - source: const Sequelize = require('sequelize'); + style: secondary + start: 0 + end: 39 + - source: |- + const sequelize = new Sequelize('database', 'username', 'password', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + style: secondary + start: 40 + end: 165 diff --git a/tests/__snapshots__/node-sequelize-hardcoded-secret-argument-typescript-snapshot.yml b/tests/__snapshots__/node-sequelize-hardcoded-secret-argument-typescript-snapshot.yml new file mode 100644 index 00000000..1ce5b449 --- /dev/null +++ b/tests/__snapshots__/node-sequelize-hardcoded-secret-argument-typescript-snapshot.yml @@ -0,0 +1,65 @@ +id: node-sequelize-hardcoded-secret-argument-typescript +snapshots: + ? | + const Sequelize = require('sequelize'); + const sequelize = new Sequelize('database', 'username', 'password', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + : labels: + - source: '''password''' + style: primary + start: 96 + end: 106 + - source: Sequelize + style: secondary + start: 62 + end: 71 + - source: password + style: secondary + start: 97 + end: 105 + - source: '''password''' + style: secondary + start: 96 + end: 106 + - source: |- + ('database', 'username', 'password', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + style: secondary + start: 71 + end: 165 + - source: |- + new Sequelize('database', 'username', 'password', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + style: secondary + start: 58 + end: 165 + - source: Sequelize + style: secondary + start: 6 + end: 15 + - source: Sequelize = require('sequelize') + style: secondary + start: 6 + end: 38 + - source: const Sequelize = require('sequelize'); + style: secondary + start: 0 + end: 39 + - source: |- + const sequelize = new Sequelize('database', 'username', 'password', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) + style: secondary + start: 40 + end: 165 diff --git a/tests/__snapshots__/openssl-cbc-static-iv-php-snapshot.yml b/tests/__snapshots__/openssl-cbc-static-iv-php-snapshot.yml new file mode 100644 index 00000000..321ed335 --- /dev/null +++ b/tests/__snapshots__/openssl-cbc-static-iv-php-snapshot.yml @@ -0,0 +1,77 @@ +id: openssl-cbc-static-iv-php +snapshots: + ? | + ("foo").c_str(); + } + : labels: + - source: return std::basic_string("foo").c_str(); + style: primary + start: 41 + end: 87 + ? | + char *return_data_directly() { + return std::string("foo").data(); + } + : labels: + - source: return std::string("foo").data(); + style: primary + start: 33 + end: 66 + ? | + char *return_directly() { + return string("foo").c_str(); + } + : labels: + - source: return string("foo").c_str(); + style: primary + start: 28 + end: 57 + ? | + char *return_namespace_directly() { + return std::string("foo").c_str(); + } + : labels: + - source: return std::string("foo").c_str(); + style: primary + start: 38 + end: 72 + ? | + class Foo { + char *f() { + std::string s = std::string("foo"); + return s.c_str(); + } + }; + : labels: + - source: return s.c_str(); + style: primary + start: 70 + end: 87 + - source: std::string s = std::string("foo"); + style: secondary + start: 30 + end: 65 + ? | + class Foo { + char *f() { + std::string s; + return s.c_str(); + } + }; + : labels: + - source: return s.c_str(); + style: primary + start: 49 + end: 66 + - source: std::string s; + style: secondary + start: 30 + end: 44 diff --git a/tests/__snapshots__/simple-command-injection-direct-input-java-snapshot.yml b/tests/__snapshots__/simple-command-injection-direct-input-java-snapshot.yml new file mode 100644 index 00000000..22d0b82e --- /dev/null +++ b/tests/__snapshots__/simple-command-injection-direct-input-java-snapshot.yml @@ -0,0 +1,126 @@ +id: simple-command-injection-direct-input-java +snapshots: + ? | + @GetMapping("/run/{command}") + public ResponseEntity run_direct_from_jumbo( + @PathVariable final String command + ) { + ResponseEntity response = ResponseEntity.noContent().build(); + try { + Runtime.getRuntime().exec(command); + } catch (IOException e) { + response = ResponseEntity.badRequest().build(); + } + + return response; + } + : labels: + - source: Runtime.getRuntime().exec(command) + style: primary + start: 208 + end: 242 + - source: PathVariable + style: secondary + start: 83 + end: 95 + - source: '@PathVariable' + style: secondary + start: 82 + end: 95 + - source: command + style: secondary + start: 109 + end: 116 + - source: String + style: secondary + start: 102 + end: 108 + - source: '@PathVariable final' + style: secondary + start: 82 + end: 101 + - source: '@PathVariable final String command' + style: secondary + start: 82 + end: 116 + - source: |- + @GetMapping("/run/{command}") + public ResponseEntity run_direct_from_jumbo( + @PathVariable final String command + ) { + ResponseEntity response = ResponseEntity.noContent().build(); + try { + Runtime.getRuntime().exec(command); + } catch (IOException e) { + response = ResponseEntity.badRequest().build(); + } + + return response; + } + style: secondary + start: 0 + end: 358 + ? | + @GetMapping("/run/{command}") + public ResponseEntity run_direct_from_jumbo( + @PathVariable() final String command + ) { + ResponseEntity response = ResponseEntity.noContent().build(); + try { + Runtime.getRuntime().exec(command); + } catch (IOException e) { + response = ResponseEntity.badRequest().build(); + } + + return response; + } + : labels: + - source: Runtime.getRuntime().exec(command) + style: primary + start: 210 + end: 244 + - source: PathVariable + style: secondary + start: 83 + end: 95 + - source: () + style: secondary + start: 95 + end: 97 + - source: '@PathVariable()' + style: secondary + start: 82 + end: 97 + - source: command + style: secondary + start: 111 + end: 118 + - source: String + style: secondary + start: 104 + end: 110 + - source: '@PathVariable() final' + style: secondary + start: 82 + end: 103 + - source: '@PathVariable() final String command' + style: secondary + start: 82 + end: 118 + - source: |- + @GetMapping("/run/{command}") + public ResponseEntity run_direct_from_jumbo( + @PathVariable() final String command + ) { + ResponseEntity response = ResponseEntity.noContent().build(); + try { + Runtime.getRuntime().exec(command); + } catch (IOException e) { + response = ResponseEntity.badRequest().build(); + } + + return response; + } + style: secondary + start: 0 + end: 360 diff --git a/tests/__snapshots__/sizeof-this-cpp-snapshot.yml b/tests/__snapshots__/sizeof-this-cpp-snapshot.yml new file mode 100644 index 00000000..4d874f00 --- /dev/null +++ b/tests/__snapshots__/sizeof-this-cpp-snapshot.yml @@ -0,0 +1,9 @@ +id: sizeof-this-cpp +snapshots: + ? | + return sizeof(this); + : labels: + - source: sizeof(this) + style: primary + start: 7 + end: 19 diff --git a/tests/__snapshots__/small-key-size-c-snapshot.yml b/tests/__snapshots__/small-key-size-c-snapshot.yml new file mode 100644 index 00000000..bdfd49e0 --- /dev/null +++ b/tests/__snapshots__/small-key-size-c-snapshot.yml @@ -0,0 +1,50 @@ +id: small-key-size-c +snapshots: + ? | + void foo() { + size_t bad_size = 1024; + size_t good_size = 2048; + DH_generate_parameters_ex(NULL, bad_size); + DSA_generate_parameters_ex(NULL, bad_size); + EVP_PKEY_CTX_set_dh_paramgen_prime_len(NULL, bad_size); + EVP_PKEY_CTX_set_dsa_paramgen_bits(NULL, bad_size); + EVP_PKEY_CTX_set_rsa_keygen_bits(NULL, bad_size); + RSA_generate_key_ex(NULL, bad_size); + RSA_generate_key_fips(NULL, bad_size);} + : labels: + - source: DH_generate_parameters_ex(NULL, bad_size); + style: primary + start: 62 + end: 104 + - source: DH_generate_parameters_ex + style: secondary + start: 62 + end: 87 + - source: bad_size + style: secondary + start: 94 + end: 102 + - source: (NULL, bad_size) + style: secondary + start: 87 + end: 103 + - source: DH_generate_parameters_ex(NULL, bad_size) + style: secondary + start: 62 + end: 103 + - source: bad_size + style: secondary + start: 20 + end: 28 + - source: '1024' + style: secondary + start: 31 + end: 35 + - source: bad_size = 1024 + style: secondary + start: 20 + end: 35 + - source: size_t bad_size = 1024; + style: secondary + start: 13 + end: 36 diff --git a/tests/__snapshots__/small-key-size-cpp-snapshot.yml b/tests/__snapshots__/small-key-size-cpp-snapshot.yml new file mode 100644 index 00000000..caee978d --- /dev/null +++ b/tests/__snapshots__/small-key-size-cpp-snapshot.yml @@ -0,0 +1,50 @@ +id: small-key-size-cpp +snapshots: + ? | + void foo() { + size_t bad_size = 1024; + size_t good_size = 2048; + DH_generate_parameters_ex(NULL, bad_size); + DSA_generate_parameters_ex(NULL, bad_size); + EVP_PKEY_CTX_set_dh_paramgen_prime_len(NULL, bad_size); + EVP_PKEY_CTX_set_dsa_paramgen_bits(NULL, bad_size); + EVP_PKEY_CTX_set_rsa_keygen_bits(NULL, bad_size); + RSA_generate_key_ex(NULL, bad_size); + RSA_generate_key_fips(NULL, bad_size);} + : labels: + - source: DH_generate_parameters_ex(NULL, bad_size); + style: primary + start: 62 + end: 104 + - source: DH_generate_parameters_ex + style: secondary + start: 62 + end: 87 + - source: bad_size + style: secondary + start: 94 + end: 102 + - source: (NULL, bad_size) + style: secondary + start: 87 + end: 103 + - source: DH_generate_parameters_ex(NULL, bad_size) + style: secondary + start: 62 + end: 103 + - source: bad_size + style: secondary + start: 20 + end: 28 + - source: '1024' + style: secondary + start: 31 + end: 35 + - source: bad_size = 1024 + style: secondary + start: 20 + end: 35 + - source: size_t bad_size = 1024; + style: secondary + start: 13 + end: 36 diff --git a/tests/__snapshots__/std-return-data-c-snapshot.yml b/tests/__snapshots__/std-return-data-c-snapshot.yml new file mode 100644 index 00000000..8c6c6885 --- /dev/null +++ b/tests/__snapshots__/std-return-data-c-snapshot.yml @@ -0,0 +1,68 @@ +id: std-return-data-c +snapshots: + ? | + int *return_vector_data() { + std::vector v; + return v.data(); + } + : labels: + - source: return v.data(); + style: primary + start: 48 + end: 64 + - source: v + style: secondary + start: 55 + end: 56 + - source: v.data + style: secondary + start: 55 + end: 61 + - source: v.data() + style: secondary + start: 55 + end: 63 + - source: std + style: secondary + start: 28 + end: 31 + - source: vector + style: secondary + start: 33 + end: 39 + - source: vector + style: secondary + start: 33 + end: 39 + - source: vector v; + return v.data(); + } + style: secondary + start: 0 + end: 66 + - source: v + style: secondary + start: 45 + end: 46 + - source: vector v + style: secondary + start: 33 + end: 46 + - source: vector v; + style: secondary + start: 33 + end: 47 + - source: std::vector v; + style: secondary + start: 28 + end: 47 diff --git a/tests/__snapshots__/std-return-data-cpp-snapshot.yml b/tests/__snapshots__/std-return-data-cpp-snapshot.yml new file mode 100644 index 00000000..ad3d8145 --- /dev/null +++ b/tests/__snapshots__/std-return-data-cpp-snapshot.yml @@ -0,0 +1,76 @@ +id: std-return-data-cpp +snapshots: + ? | + int *return_vector_data() { + std::vector v; + return v.data(); + } + : labels: + - source: return v.data(); + style: primary + start: 48 + end: 64 + - source: v + style: secondary + start: 45 + end: 46 + - source: vector + style: secondary + start: 33 + end: 39 + - source: vector + style: secondary + start: 33 + end: 44 + - source: return_vector_data + style: secondary + start: 5 + end: 23 + - source: return_vector_data() + style: secondary + start: 5 + end: 25 + - source: '*return_vector_data()' + style: secondary + start: 4 + end: 25 + - source: int + style: secondary + start: 0 + end: 3 + - source: |- + { + std::vector v; + return v.data(); + } + style: secondary + start: 26 + end: 66 + - source: std + style: secondary + start: 28 + end: 31 + - source: std::vector + style: secondary + start: 28 + end: 44 + - source: std::vector v; + style: secondary + start: 28 + end: 47 + - source: return v.data(); + style: secondary + start: 48 + end: 64 + - source: v + style: secondary + start: 55 + end: 56 + - source: v.data + style: secondary + start: 55 + end: 61 + - source: v.data() + style: secondary + start: 55 + end: 63 diff --git a/tests/__snapshots__/use-of-weak-rsa-key-go-snapshot.yml b/tests/__snapshots__/use-of-weak-rsa-key-go-snapshot.yml new file mode 100644 index 00000000..91aeb283 --- /dev/null +++ b/tests/__snapshots__/use-of-weak-rsa-key-go-snapshot.yml @@ -0,0 +1,21 @@ +id: use-of-weak-rsa-key-go +snapshots: + ? | + pvk, err := rsa.GenerateKey(rand.Reader, 1025) + : labels: + - source: rsa.GenerateKey(rand.Reader, 1025) + style: primary + start: 12 + end: 46 + - source: rsa.GenerateKey + style: secondary + start: 12 + end: 27 + - source: (rand.Reader, 1025) + style: secondary + start: 27 + end: 46 + - source: '1025' + style: secondary + start: 41 + end: 45 diff --git a/tests/c/small-key-size-c-test.yml b/tests/c/small-key-size-c-test.yml new file mode 100644 index 00000000..e4c3a272 --- /dev/null +++ b/tests/c/small-key-size-c-test.yml @@ -0,0 +1,26 @@ +id: small-key-size-c +valid: + - | + void foo() { + size_t bad_size = 1024; + size_t good_size = 2048; + DH_generate_parameters_ex(NULL, good_size); + DSA_generate_parameters_ex(NULL, good_size); + EVP_PKEY_CTX_set_dh_paramgen_prime_len(NULL, good_size); + EVP_PKEY_CTX_set_dsa_paramgen_bits(NULL, good_size); + EVP_PKEY_CTX_set_rsa_keygen_bits(NULL, good_size); + RSA_generate_key_ex(NULL, good_size); + RSA_generate_key_fips(NULL, good_size);} + +invalid: + - | + void foo() { + size_t bad_size = 1024; + size_t good_size = 2048; + DH_generate_parameters_ex(NULL, bad_size); + DSA_generate_parameters_ex(NULL, bad_size); + EVP_PKEY_CTX_set_dh_paramgen_prime_len(NULL, bad_size); + EVP_PKEY_CTX_set_dsa_paramgen_bits(NULL, bad_size); + EVP_PKEY_CTX_set_rsa_keygen_bits(NULL, bad_size); + RSA_generate_key_ex(NULL, bad_size); + RSA_generate_key_fips(NULL, bad_size);} diff --git a/tests/c/std-return-data-c-test.yml b/tests/c/std-return-data-c-test.yml new file mode 100644 index 00000000..c46c85fa --- /dev/null +++ b/tests/c/std-return-data-c-test.yml @@ -0,0 +1,15 @@ +id: std-return-data-c +valid: + - | + class Wrapper { + std::vector v; + int *return_vector_begin_iterator() { + return v.data(); + } + } +invalid: + - | + int *return_vector_data() { + std::vector v; + return v.data(); + } diff --git a/tests/cpp/return-c-str-cpp-test.yml b/tests/cpp/return-c-str-cpp-test.yml new file mode 100644 index 00000000..b9ac5f52 --- /dev/null +++ b/tests/cpp/return-c-str-cpp-test.yml @@ -0,0 +1,63 @@ +id: return-c-str-cpp +valid: + - | + std::string return_directly() { + // ok: return-c-str + return std::string("foo"); + } + - | + char *f() { + static std::string s; + // ok: return-c-str + return s.c_str(); + } + - | + char *f() { + std::string s1; + return s.c_str(); + } +invalid: + - | + char *f() { + std::string s; + return s.c_str(); + } + - | + char *f() { + std::string s = std::string("foo"); + return s.c_str(); + } + - | + char *f(std::string s) { + return s.c_str(); + } + - | + class Foo { + char *f() { + std::string s = std::string("foo"); + return s.c_str(); + } + }; + - | + class Foo { + char *f() { + std::string s; + return s.c_str(); + } + }; + - | + char *return_namespace_directly() { + return std::string("foo").c_str(); + } + - | + char *return_directly() { + return string("foo").c_str(); + } + - | + char *return_basic_string_directly() { + return std::basic_string("foo").c_str(); + } + - | + char *return_data_directly() { + return std::string("foo").data(); + } diff --git a/tests/cpp/sizeof-this-cpp-test.yml b/tests/cpp/sizeof-this-cpp-test.yml new file mode 100644 index 00000000..343b2a66 --- /dev/null +++ b/tests/cpp/sizeof-this-cpp-test.yml @@ -0,0 +1,7 @@ +id: sizeof-this-cpp +valid: + - | + return sizeof(*this); +invalid: + - | + return sizeof(this); diff --git a/tests/cpp/small-key-size-cpp-test.yml b/tests/cpp/small-key-size-cpp-test.yml new file mode 100644 index 00000000..636b0ce3 --- /dev/null +++ b/tests/cpp/small-key-size-cpp-test.yml @@ -0,0 +1,26 @@ +id: small-key-size-cpp +valid: + - | + void foo() { + size_t bad_size = 1024; + size_t good_size = 2048; + DH_generate_parameters_ex(NULL, good_size); + DSA_generate_parameters_ex(NULL, good_size); + EVP_PKEY_CTX_set_dh_paramgen_prime_len(NULL, good_size); + EVP_PKEY_CTX_set_dsa_paramgen_bits(NULL, good_size); + EVP_PKEY_CTX_set_rsa_keygen_bits(NULL, good_size); + RSA_generate_key_ex(NULL, good_size); + RSA_generate_key_fips(NULL, good_size);} + +invalid: + - | + void foo() { + size_t bad_size = 1024; + size_t good_size = 2048; + DH_generate_parameters_ex(NULL, bad_size); + DSA_generate_parameters_ex(NULL, bad_size); + EVP_PKEY_CTX_set_dh_paramgen_prime_len(NULL, bad_size); + EVP_PKEY_CTX_set_dsa_paramgen_bits(NULL, bad_size); + EVP_PKEY_CTX_set_rsa_keygen_bits(NULL, bad_size); + RSA_generate_key_ex(NULL, bad_size); + RSA_generate_key_fips(NULL, bad_size);} diff --git a/tests/cpp/std-return-data-cpp-test.yml b/tests/cpp/std-return-data-cpp-test.yml new file mode 100644 index 00000000..881e0957 --- /dev/null +++ b/tests/cpp/std-return-data-cpp-test.yml @@ -0,0 +1,15 @@ +id: std-return-data-cpp +valid: + - | + class Wrapper { + std::vector v; + int *return_vector_begin_iterator() { + return v.data(); + } + } +invalid: + - | + int *return_vector_data() { + std::vector v; + return v.data(); + } diff --git a/tests/go/avoid-bind-to-all-interfaces-go-test.yml b/tests/go/avoid-bind-to-all-interfaces-go-test.yml new file mode 100644 index 00000000..4aebe122 --- /dev/null +++ b/tests/go/avoid-bind-to-all-interfaces-go-test.yml @@ -0,0 +1,9 @@ +id: avoid-bind-to-all-interfaces-go +valid: + - | + l, err := net.Listen("tcp", "192.168.1.101:2000") +invalid: + - | + l, err := net.Listen("tcp", "0.0.0.0:2000") + - | + l, err := net.Listen("tcp", ":2000") diff --git a/tests/go/grpc-client-insecure-connection-go-test.yml b/tests/go/grpc-client-insecure-connection-go-test.yml new file mode 100644 index 00000000..dcd502ef --- /dev/null +++ b/tests/go/grpc-client-insecure-connection-go-test.yml @@ -0,0 +1,7 @@ +id: grpc-client-insecure-connection-go +valid: + - | + conn, err := grpc.Dial(address) +invalid: + - | + conn, err := grpc.Dial(address, grpc.WithInsecure()) diff --git a/tests/go/grpc-client-insecure-connection-test.yml b/tests/go/grpc-client-insecure-connection-test.yml deleted file mode 100644 index 4533f57a..00000000 --- a/tests/go/grpc-client-insecure-connection-test.yml +++ /dev/null @@ -1,17 +0,0 @@ -id: grpc-client-insecure-connection -valid: - - | - grpc.Dial("example.com", grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))) -invalid: - - | - grpc.Dial("example.com", grpc.WithInsecure()) - - | - grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock()) - - | - grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(5*time.Second)) - - | - grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(5*time.Second), grpc.WithUserAgent("example")) - - | - grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(5*time.Second), grpc.WithUserAgent("example"), grpc.WithAuthority("example.com")) - - | - grpc.Dial("example.com", grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(5*time.Second), grpc.WithUserAgent("example"), grpc.WithAuthority("example.com"), grpc.WithDial) \ No newline at end of file diff --git a/tests/go/jwt-go-none-algorithm-go-test.yml b/tests/go/jwt-go-none-algorithm-go-test.yml new file mode 100644 index 00000000..d3c1681f --- /dev/null +++ b/tests/go/jwt-go-none-algorithm-go-test.yml @@ -0,0 +1,28 @@ +id: jwt-go-none-algorithm-go +valid: + - | + import ( + "fmt" + "github.com/dgrijalva/jwt-go" + ) + func ok1(key []byte){ + claims = jwt.StandardClaims{ + ExpiresAt:15000, + Issuer:"test",} + token = jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + ss, err = token.SignedString(key) + fmt.Printf("%v %v\n", ss, err)} + +invalid: + - | + import ( + "fmt" + "github.com/dgrijalva/jwt-go" + ) + func bad1(key []byte) { + claims := jwt.StandardClaims{ + ExpiresAt:15000, + Issuer:"test",} + token := jwt.NewWithClaims(jwt.SigningMethodNone, claims) + ss, err := token.SignedString(jwt.UnsafeAllowNoneSignatureType) + fmt.Printf("%v %v\n", ss, err)} diff --git a/tests/go/use-of-weak-rsa-key-go-test.yml b/tests/go/use-of-weak-rsa-key-go-test.yml new file mode 100644 index 00000000..0233aa98 --- /dev/null +++ b/tests/go/use-of-weak-rsa-key-go-test.yml @@ -0,0 +1,7 @@ +id: use-of-weak-rsa-key-go +valid: + - | + rsa.GenerateKey(rand.Reader, 2048) +invalid: + - | + pvk, err := rsa.GenerateKey(rand.Reader, 1025) diff --git a/tests/java/documentbuilderfactory-disallow-doctype-decl-false-java-test.yml b/tests/java/documentbuilderfactory-disallow-doctype-decl-false-java-test.yml new file mode 100644 index 00000000..51cb4f21 --- /dev/null +++ b/tests/java/documentbuilderfactory-disallow-doctype-decl-false-java-test.yml @@ -0,0 +1,63 @@ +id: documentbuilderfactory-disallow-doctype-decl-false-java +valid: + - | + ParserConfigurationException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + //ok:documentbuilderfactory-disallow-doctype-decl-false + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + } + - | + ParserConfigurationException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + //ok:documentbuilderfactory-disallow-doctype-decl-false + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); + dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + } + - | + ParserConfigurationException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + //ok:documentbuilderfactory-disallow-doctype-decl-false + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); + } + - | + ParserConfigurationException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + //ok:documentbuilderfactory-disallow-doctype-decl-false + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + } + - | + ParserConfigurationException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + //ok:documentbuilderfactory-disallow-doctype-decl-false + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); + } + - | + ParserConfigurationException { + SAXParserFactory spf = SAXParserFactory.newInstance(); + //ok:documentbuilderfactory-disallow-doctype-decl-false + spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + } +invalid: + - | + ParserConfigurationException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + //ruleid:documentbuilderfactory-disallow-doctype-decl-false + dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false); + //fix:documentbuilderfactory-disallow-doctype-decl-false + //dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + } + - | + ParserConfigurationException { + SAXParserFactory spf = SAXParserFactory.newInstance(); + //ruleid:documentbuilderfactory-disallow-doctype-decl-false + spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false); + //fix:documentbuilderfactory-disallow-doctype-decl-false + //spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + } diff --git a/tests/java/documentbuilderfactory-external-parameter-entities-true-java-test.yml b/tests/java/documentbuilderfactory-external-parameter-entities-true-java-test.yml new file mode 100644 index 00000000..309b83da --- /dev/null +++ b/tests/java/documentbuilderfactory-external-parameter-entities-true-java-test.yml @@ -0,0 +1,8 @@ +id: documentbuilderfactory-external-parameter-entities-true-java +valid: + - | + dbf.setFeature("http://xml.org/sax/features/external-parameter-entities" , false); +invalid: + - | + dbf.setFeature("http://xml.org/sax/features/external-parameter-entities" , true); + spf.setFeature("http://xml.org/sax/features/external-parameter-entities" , true); diff --git a/tests/java/gcm-nonce-reuse-java-test.yml b/tests/java/gcm-nonce-reuse-java-test.yml new file mode 100644 index 00000000..3f5e052e --- /dev/null +++ b/tests/java/gcm-nonce-reuse-java-test.yml @@ -0,0 +1,9 @@ +id: gcm-nonce-reuse-java +valid: + - | + byte[] theBadIV = BAD_IV.getBytes(); + GCMParameterSpec gcmParameter = new GCMParameter(GCM_TAG_LENGTH * 8, theBadIV); +invalid: + - | + byte[] theBadIV = BAD_IV.getBytes(); + GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, theBadIV); diff --git a/tests/java/simple-command-injection-direct-input-java-test.yml b/tests/java/simple-command-injection-direct-input-java-test.yml new file mode 100644 index 00000000..cba713e4 --- /dev/null +++ b/tests/java/simple-command-injection-direct-input-java-test.yml @@ -0,0 +1,59 @@ +id: simple-command-injection-direct-input-java +valid: + - | + @GetMapping("/run/{command}") + public ResponseEntity run1( + @PathVariable final String command + ) { + ResponseEntity response = ResponseEntity.noContent().build(); + try { + String foo = command + "something something..."; + Runtime.getRuntime().exec(foo); + } catch (IOException e) { + response = ResponseEntity.badRequest().build(); + } + return response; + } + - | + @GetMapping("/run/{command}") + public ResponseEntity ok( + @PathVariable final String command + ) { + ResponseEntity response = ResponseEntity.noContent().build(); + try { + Runtime.getRuntime().exec("/bin/ls"); + } catch (IOException e) { + response = ResponseEntity.badRequest().build(); + } + + return response; + } +invalid: + - | + @GetMapping("/run/{command}") + public ResponseEntity run_direct_from_jumbo( + @PathVariable() final String command + ) { + ResponseEntity response = ResponseEntity.noContent().build(); + try { + Runtime.getRuntime().exec(command); + } catch (IOException e) { + response = ResponseEntity.badRequest().build(); + } + + return response; + } + - | + @GetMapping("/run/{command}") + public ResponseEntity run_direct_from_jumbo( + @PathVariable final String command + ) { + ResponseEntity response = ResponseEntity.noContent().build(); + try { + Runtime.getRuntime().exec(command); + } catch (IOException e) { + response = ResponseEntity.badRequest().build(); + } + + return response; + } diff --git a/tests/javascript/detect-angular-sce-disabled-javascript-test.yml b/tests/javascript/detect-angular-sce-disabled-javascript-test.yml new file mode 100644 index 00000000..965afe1e --- /dev/null +++ b/tests/javascript/detect-angular-sce-disabled-javascript-test.yml @@ -0,0 +1,7 @@ +id: detect-angular-sce-disabled-javascript +valid: + - | + +invalid: + - | + $sceProvider.enabled(false); diff --git a/tests/javascript/jwt-none-alg-javascript-test.yml b/tests/javascript/jwt-none-alg-javascript-test.yml new file mode 100644 index 00000000..11ef4c36 --- /dev/null +++ b/tests/javascript/jwt-none-alg-javascript-test.yml @@ -0,0 +1,9 @@ +id: jwt-none-alg-javascript +valid: + - | + +invalid: + - | + const jose = require("jose"); + const { JWK, JWT } = jose; + const token = JWT.verify('token-here', JWK.None); diff --git a/tests/javascript/jwt-simple-noverify-js-test.yml b/tests/javascript/jwt-simple-noverify-js-test.yml new file mode 100644 index 00000000..1601fa58 --- /dev/null +++ b/tests/javascript/jwt-simple-noverify-js-test.yml @@ -0,0 +1,91 @@ +id: jwt-simple-noverify-js +valid: + - | + const jwt = require('jwt-simple'); + app.get('/protectedRoute4', (req, res) => { + const token = req.headers.authorization; + + if (!token) { + return res.status(401).json({ error: 'Unauthorized. Token missing.' }); + } + + try { + // ok: jwt-simple-noverify + const decoded = jwt.decode(token, secretKey); + res.json({ message: `Hello ${decoded.username}` }); + } catch (error) { + res.status(401).json({ error: 'Unauthorized. Invalid token.' }); + } + }); + - | + const jwt = require('jwt-simple'); + app.get('/protectedRoute5', (req, res) => { + const token = req.headers.authorization; + + if (!token) { + return res.status(401).json({ error: 'Unauthorized. Token missing.' }); + } + + try { + // ok: jwt-simple-noverify + const decoded = jwt.decode(token, secretKey, false); + res.json({ message: `Hello ${decoded.username}` }); + } catch (error) { + res.status(401).json({ error: 'Unauthorized. Invalid token.' }); + } + }); +invalid: + - | + const jwt = require('jwt-simple'); + + app.get('/protectedRoute1', (req, res) => { + const token = req.headers.authorization; + + if (!token) { + return res.status(401).json({ error: 'Unauthorized. Token missing.' }); + } + + try { + // ruleid: jwt-simple-noverify + const decoded = jwt.decode(token, secretKey, 'HS256', 12); + res.json({ message: `Hello ${decoded.username}` }); + } catch (error) { + res.status(401).json({ error: 'Unauthorized. Invalid token.' }); + } + }); + - | + const jwt = require('jwt-simple'); + + app.get('/protectedRoute2', (req, res) => { + const token = req.headers.authorization; + + if (!token) { + return res.status(401).json({ error: 'Unauthorized. Token missing.' }); + } + + try { + // ruleid: jwt-simple-noverify + const decoded = jwt.decode(token, secretKey, true); + res.json({ message: `Hello ${decoded.username}` }); + } catch (error) { + res.status(401).json({ error: 'Unauthorized. Invalid token.' }); + } + }); + - | + const jwt = require('jwt-simple'); + + app.get('/protectedRoute3', (req, res) => { + const token = req.headers.authorization; + + if (!token) { + return res.status(401).json({ error: 'Unauthorized. Token missing.' }); + } + + try { + // ruleid: jwt-simple-noverify + const decoded = jwt.decode(token, secretKey, 'false'); + res.json({ message: `Hello ${decoded.username}` }); + } catch (error) { + res.status(401).json({ error: 'Unauthorized. Invalid token.' }); + } + }); diff --git a/tests/javascript/node-sequelize-empty-password-argument-javascript-test.yml b/tests/javascript/node-sequelize-empty-password-argument-javascript-test.yml new file mode 100644 index 00000000..093cf3a7 --- /dev/null +++ b/tests/javascript/node-sequelize-empty-password-argument-javascript-test.yml @@ -0,0 +1,18 @@ +id: node-sequelize-empty-password-argument-javascript +valid: + - | + const Sequelize = require('sequelize'); + const sequelize = new Sequelize({ + database: 'pinche', + username: 'root', + password: '123456789', + dialect: 'mysql' + }); +invalid: + - | + const Sequelize = require('sequelize'); + const sequelize1 = new Sequelize('database', 'username', '', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) diff --git a/tests/javascript/node-sequelize-hardcoded-secret-argument-javascript-test.yml b/tests/javascript/node-sequelize-hardcoded-secret-argument-javascript-test.yml new file mode 100644 index 00000000..8cc8edeb --- /dev/null +++ b/tests/javascript/node-sequelize-hardcoded-secret-argument-javascript-test.yml @@ -0,0 +1,18 @@ +id: node-sequelize-hardcoded-secret-argument-javascript +valid: + - | + const Sequelize = require('sequelize'); + const sequelize = new Sequelize({ + database: 'pinche', + username: 'root', + password: '123456789', + dialect: 'mysql' + }) +invalid: + - | + const Sequelize = require('sequelize'); + const sequelize = new Sequelize('database', 'username', 'password', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) diff --git a/tests/php/openssl-cbc-static-iv-php-test.yml b/tests/php/openssl-cbc-static-iv-php-test.yml new file mode 100644 index 00000000..e1b06980 --- /dev/null +++ b/tests/php/openssl-cbc-static-iv-php-test.yml @@ -0,0 +1,23 @@ +id: openssl-cbc-static-iv-php +valid: + - | + { + const token = req.headers.authorization; + + if (!token) { + return res.status(401).json({ error: 'Unauthorized. Token missing.' }); + } + + try { + // ok: jwt-simple-noverify + const decoded = jwt.decode(token, secretKey); + res.json({ message: `Hello ${decoded.username}` }); + } catch (error) { + res.status(401).json({ error: 'Unauthorized. Invalid token.' }); + } + }); + - | + const jwt = require('jwt-simple'); + app.get('/protectedRoute5', (req, res) => { + const token = req.headers.authorization; + + if (!token) { + return res.status(401).json({ error: 'Unauthorized. Token missing.' }); + } + + try { + // ok: jwt-simple-noverify + const decoded = jwt.decode(token, secretKey, false); + res.json({ message: `Hello ${decoded.username}` }); + } catch (error) { + res.status(401).json({ error: 'Unauthorized. Invalid token.' }); + } + }); +invalid: + - | + const jwt = require('jwt-simple'); + + app.get('/protectedRoute1', (req, res) => { + const token = req.headers.authorization; + + if (!token) { + return res.status(401).json({ error: 'Unauthorized. Token missing.' }); + } + + try { + // ruleid: jwt-simple-noverify + const decoded = jwt.decode(token, secretKey, 'HS256', 12); + res.json({ message: `Hello ${decoded.username}` }); + } catch (error) { + res.status(401).json({ error: 'Unauthorized. Invalid token.' }); + } + }); + - | + const jwt = require('jwt-simple'); + + app.get('/protectedRoute2', (req, res) => { + const token = req.headers.authorization; + + if (!token) { + return res.status(401).json({ error: 'Unauthorized. Token missing.' }); + } + + try { + // ruleid: jwt-simple-noverify + const decoded = jwt.decode(token, secretKey, true); + res.json({ message: `Hello ${decoded.username}` }); + } catch (error) { + res.status(401).json({ error: 'Unauthorized. Invalid token.' }); + } + }); + - | + const jwt = require('jwt-simple'); + + app.get('/protectedRoute3', (req, res) => { + const token = req.headers.authorization; + + if (!token) { + return res.status(401).json({ error: 'Unauthorized. Token missing.' }); + } + + try { + // ruleid: jwt-simple-noverify + const decoded = jwt.decode(token, secretKey, 'false'); + res.json({ message: `Hello ${decoded.username}` }); + } catch (error) { + res.status(401).json({ error: 'Unauthorized. Invalid token.' }); + } + }); diff --git a/tests/typescript/node-sequelize-empty-password-argument-typescript-test.yml b/tests/typescript/node-sequelize-empty-password-argument-typescript-test.yml new file mode 100644 index 00000000..0c17510d --- /dev/null +++ b/tests/typescript/node-sequelize-empty-password-argument-typescript-test.yml @@ -0,0 +1,18 @@ +id: node-sequelize-empty-password-argument-typescript +valid: + - | + const Sequelize = require('sequelize'); + const sequelize = new Sequelize({ + database: 'pinche', + username: 'root', + password: '123456789', + dialect: 'mysql' + }); +invalid: + - | + const Sequelize = require('sequelize'); + const sequelize1 = new Sequelize('database', 'username', '', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + }) diff --git a/tests/typescript/node-sequelize-hardcoded-secret-argument-typescript-test.yml b/tests/typescript/node-sequelize-hardcoded-secret-argument-typescript-test.yml new file mode 100644 index 00000000..b45d2743 --- /dev/null +++ b/tests/typescript/node-sequelize-hardcoded-secret-argument-typescript-test.yml @@ -0,0 +1,18 @@ +id: node-sequelize-hardcoded-secret-argument-typescript +valid: + - | + const Sequelize = require('sequelize'); + const sequelize = new Sequelize({ + database: 'pinche', + username: 'root', + password: '123456789', + dialect: 'mysql' + }) +invalid: + - | + const Sequelize = require('sequelize'); + const sequelize = new Sequelize('database', 'username', 'password', { + host: 'localhost', + port: '5433', + dialect: 'postgres' + })