From 9c76ce9289df1564757afa70123cb2e03a393caf Mon Sep 17 00:00:00 2001 From: ESS-ENN Date: Wed, 9 Oct 2024 12:15:17 +0530 Subject: [PATCH 1/4] express-jwt-hardcoded-secret-typescript --- ...xpress-jwt-hardcoded-secret-typescript.yml | 288 ++++++++++++++++++ ...s-jwt-hardcoded-secret-typescript-test.yml | 14 + 2 files changed, 302 insertions(+) create mode 100644 rules/typescript/security/express-jwt-hardcoded-secret-typescript.yml create mode 100644 tests/typescript/express-jwt-hardcoded-secret-typescript-test.yml diff --git a/rules/typescript/security/express-jwt-hardcoded-secret-typescript.yml b/rules/typescript/security/express-jwt-hardcoded-secret-typescript.yml new file mode 100644 index 00000000..dae5ebae --- /dev/null +++ b/rules/typescript/security/express-jwt-hardcoded-secret-typescript.yml @@ -0,0 +1,288 @@ +id: express-jwt-hardcoded-secret-typescript +language: typescript +severity: warning +message: >- + A hard-coded credential was detected. It is not recommended to store + credentials in source-code, as this risks secrets being leaked and used by + either an internal or external malicious adversary. It is recommended to + use environment variables to securely provide credentials or retrieve + credentials from a secure vault or HSM (Hardware Security Module). +note: >- + [CWE-798] Use of Hard-coded Credentials. + [REFERENCES] + - https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html +utils: + MATCH_SECRET_DIRECTLY: + kind: pair + inside: + stopBy: end + kind: expression_statement + all: + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + pattern: $E + - has: + stopBy: end + kind: arguments + has: + stopBy: end + kind: object + has: + stopBy: neighbor + kind: pair + all: + - has: + stopBy: neighbor + kind: property_identifier + regex: "^secret$" + - has: + stopBy: neighbor + kind: string + + - any: + - follows: + stopBy: end + kind: variable_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: "^require$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^express-jwt$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: end + kind: import_clause + has: + stopBy: neighbor + kind: identifier + pattern: $E + - has: + stopBy: neighbor + kind: string + has: + stopBy: end + kind: string_fragment + regex: "^express-jwt$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: end + kind: import_clause + has: + stopBy: end + kind: namespace_import + has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^express-jwt$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + has: + stopBy: neighbor + kind: named_imports + has: + stopBy: neighbor + kind: import_specifier + has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: end + kind: string + has: + stopBy: end + kind: string_fragment + regex: "^express-jwt$" + + MATCH_PATTERN_WITH_INSTANCE: + kind: pair + inside: + stopBy: end + kind: expression_statement + all: + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + pattern: $E + - has: + stopBy: end + kind: arguments + has: + stopBy: end + kind: object + has: + stopBy: neighbor + kind: pair + all: + - has: + stopBy: neighbor + kind: property_identifier + regex: "^secret$" + - has: + stopBy: neighbor + kind: identifier + pattern: $F + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: neighbor + kind: identifier + pattern: $F + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + - any: + - follows: + stopBy: end + kind: variable_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: "^require$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^express-jwt$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: end + kind: import_clause + has: + stopBy: neighbor + kind: identifier + pattern: $E + - has: + stopBy: neighbor + kind: string + has: + stopBy: end + kind: string_fragment + regex: "^express-jwt$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: end + kind: import_clause + has: + stopBy: end + kind: namespace_import + has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^express-jwt$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + has: + stopBy: neighbor + kind: named_imports + has: + stopBy: neighbor + kind: import_specifier + has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: end + kind: string + has: + stopBy: end + kind: string_fragment + regex: "^express-jwt$" + +rule: + kind: pair + any: + - matches: MATCH_SECRET_DIRECTLY + - matches: MATCH_PATTERN_WITH_INSTANCE diff --git a/tests/typescript/express-jwt-hardcoded-secret-typescript-test.yml b/tests/typescript/express-jwt-hardcoded-secret-typescript-test.yml new file mode 100644 index 00000000..356a6e15 --- /dev/null +++ b/tests/typescript/express-jwt-hardcoded-secret-typescript-test.yml @@ -0,0 +1,14 @@ +id: express-jwt-hardcoded-secret-typescript +valid: + - | + app.get('/ok-protected', jwt({ secret: process.env.SECRET }), function(req, res) { + if (!req.user.admin) return res.sendStatus(401); + res.sendStatus(200); + }); +invalid: + - | + var jwt = require('express-jwt'); + app.get('/protected', jwt({ secret: 'shhhhhhared-secret' }), function(req, res) { + if (!req.user.admin) return res.sendStatus(401); + res.sendStatus(200); + }); From 7eddfc8b1b8251b4c19bb4daf8d2e6d830bfedac Mon Sep 17 00:00:00 2001 From: ESS-ENN Date: Wed, 9 Oct 2024 12:18:25 +0530 Subject: [PATCH 2/4] express-jwt-hardcoded-secret-javascript --- ...xpress-jwt-hardcoded-secret-javascript.yml | 288 ++++++++++++++++++ ...t-hardcoded-secret-javascript-snapshot.yml | 81 +++++ ...t-hardcoded-secret-typescript-snapshot.yml | 81 +++++ ...s-jwt-hardcoded-secret-javascript-test.yml | 14 + 4 files changed, 464 insertions(+) create mode 100644 rules/javascript/security/express-jwt-hardcoded-secret-javascript.yml create mode 100644 tests/__snapshots__/express-jwt-hardcoded-secret-javascript-snapshot.yml create mode 100644 tests/__snapshots__/express-jwt-hardcoded-secret-typescript-snapshot.yml create mode 100644 tests/javascript/express-jwt-hardcoded-secret-javascript-test.yml diff --git a/rules/javascript/security/express-jwt-hardcoded-secret-javascript.yml b/rules/javascript/security/express-jwt-hardcoded-secret-javascript.yml new file mode 100644 index 00000000..62e0dcfe --- /dev/null +++ b/rules/javascript/security/express-jwt-hardcoded-secret-javascript.yml @@ -0,0 +1,288 @@ +id: express-jwt-hardcoded-secret-javascript +language: javascript +severity: warning +message: >- + A hard-coded credential was detected. It is not recommended to store + credentials in source-code, as this risks secrets being leaked and used by + either an internal or external malicious adversary. It is recommended to + use environment variables to securely provide credentials or retrieve + credentials from a secure vault or HSM (Hardware Security Module). +note: >- + [CWE-798] Use of Hard-coded Credentials. + [REFERENCES] + - https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html +utils: + MATCH_SECRET_DIRECTLY: + kind: pair + inside: + stopBy: end + kind: expression_statement + all: + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + pattern: $E + - has: + stopBy: end + kind: arguments + has: + stopBy: end + kind: object + has: + stopBy: neighbor + kind: pair + all: + - has: + stopBy: neighbor + kind: property_identifier + regex: "^secret$" + - has: + stopBy: neighbor + kind: string + + - any: + - follows: + stopBy: end + kind: variable_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: "^require$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^express-jwt$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: end + kind: import_clause + has: + stopBy: neighbor + kind: identifier + pattern: $E + - has: + stopBy: neighbor + kind: string + has: + stopBy: end + kind: string_fragment + regex: "^express-jwt$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: end + kind: import_clause + has: + stopBy: end + kind: namespace_import + has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^express-jwt$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + has: + stopBy: neighbor + kind: named_imports + has: + stopBy: neighbor + kind: import_specifier + has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: end + kind: string + has: + stopBy: end + kind: string_fragment + regex: "^express-jwt$" + + MATCH_PATTERN_WITH_INSTANCE: + kind: pair + inside: + stopBy: end + kind: expression_statement + all: + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + pattern: $E + - has: + stopBy: end + kind: arguments + has: + stopBy: end + kind: object + has: + stopBy: neighbor + kind: pair + all: + - has: + stopBy: neighbor + kind: property_identifier + regex: "^secret$" + - has: + stopBy: neighbor + kind: identifier + pattern: $F + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: neighbor + kind: identifier + pattern: $F + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + - any: + - follows: + stopBy: end + kind: variable_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: neighbor + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: "^require$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^express-jwt$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: end + kind: import_clause + has: + stopBy: neighbor + kind: identifier + pattern: $E + - has: + stopBy: neighbor + kind: string + has: + stopBy: end + kind: string_fragment + regex: "^express-jwt$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: end + kind: import_clause + has: + stopBy: end + kind: namespace_import + has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^express-jwt$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + has: + stopBy: neighbor + kind: named_imports + has: + stopBy: neighbor + kind: import_specifier + has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: end + kind: string + has: + stopBy: end + kind: string_fragment + regex: "^express-jwt$" + +rule: + kind: pair + any: + - matches: MATCH_SECRET_DIRECTLY + - matches: MATCH_PATTERN_WITH_INSTANCE diff --git a/tests/__snapshots__/express-jwt-hardcoded-secret-javascript-snapshot.yml b/tests/__snapshots__/express-jwt-hardcoded-secret-javascript-snapshot.yml new file mode 100644 index 00000000..44fd920e --- /dev/null +++ b/tests/__snapshots__/express-jwt-hardcoded-secret-javascript-snapshot.yml @@ -0,0 +1,81 @@ +id: express-jwt-hardcoded-secret-javascript +snapshots: + ? | + var jwt = require('express-jwt'); + app.get('/protected', jwt({ secret: 'shhhhhhared-secret' }), function(req, res) { + if (!req.user.admin) return res.sendStatus(401); + res.sendStatus(200); + }); + : labels: + - source: 'secret: ''shhhhhhared-secret''' + style: primary + start: 62 + end: 90 + - source: jwt + style: secondary + start: 56 + end: 59 + - source: secret + style: secondary + start: 62 + end: 68 + - source: '''shhhhhhared-secret''' + style: secondary + start: 70 + end: 90 + - source: 'secret: ''shhhhhhared-secret''' + style: secondary + start: 62 + end: 90 + - source: '{ secret: ''shhhhhhared-secret'' }' + style: secondary + start: 60 + end: 92 + - source: '({ secret: ''shhhhhhared-secret'' })' + style: secondary + start: 59 + end: 93 + - source: 'jwt({ secret: ''shhhhhhared-secret'' })' + style: secondary + start: 56 + end: 93 + - source: jwt + style: secondary + start: 4 + end: 7 + - source: require + style: secondary + start: 10 + end: 17 + - source: express-jwt + style: secondary + start: 19 + end: 30 + - source: '''express-jwt''' + style: secondary + start: 18 + end: 31 + - source: ('express-jwt') + style: secondary + start: 17 + end: 32 + - source: require('express-jwt') + style: secondary + start: 10 + end: 32 + - source: jwt = require('express-jwt') + style: secondary + start: 4 + end: 32 + - source: var jwt = require('express-jwt'); + style: secondary + start: 0 + end: 33 + - source: |- + app.get('/protected', jwt({ secret: 'shhhhhhared-secret' }), function(req, res) { + if (!req.user.admin) return res.sendStatus(401); + res.sendStatus(200); + }); + style: secondary + start: 34 + end: 189 diff --git a/tests/__snapshots__/express-jwt-hardcoded-secret-typescript-snapshot.yml b/tests/__snapshots__/express-jwt-hardcoded-secret-typescript-snapshot.yml new file mode 100644 index 00000000..72523292 --- /dev/null +++ b/tests/__snapshots__/express-jwt-hardcoded-secret-typescript-snapshot.yml @@ -0,0 +1,81 @@ +id: express-jwt-hardcoded-secret-typescript +snapshots: + ? | + var jwt = require('express-jwt'); + app.get('/protected', jwt({ secret: 'shhhhhhared-secret' }), function(req, res) { + if (!req.user.admin) return res.sendStatus(401); + res.sendStatus(200); + }); + : labels: + - source: 'secret: ''shhhhhhared-secret''' + style: primary + start: 62 + end: 90 + - source: jwt + style: secondary + start: 56 + end: 59 + - source: secret + style: secondary + start: 62 + end: 68 + - source: '''shhhhhhared-secret''' + style: secondary + start: 70 + end: 90 + - source: 'secret: ''shhhhhhared-secret''' + style: secondary + start: 62 + end: 90 + - source: '{ secret: ''shhhhhhared-secret'' }' + style: secondary + start: 60 + end: 92 + - source: '({ secret: ''shhhhhhared-secret'' })' + style: secondary + start: 59 + end: 93 + - source: 'jwt({ secret: ''shhhhhhared-secret'' })' + style: secondary + start: 56 + end: 93 + - source: jwt + style: secondary + start: 4 + end: 7 + - source: require + style: secondary + start: 10 + end: 17 + - source: express-jwt + style: secondary + start: 19 + end: 30 + - source: '''express-jwt''' + style: secondary + start: 18 + end: 31 + - source: ('express-jwt') + style: secondary + start: 17 + end: 32 + - source: require('express-jwt') + style: secondary + start: 10 + end: 32 + - source: jwt = require('express-jwt') + style: secondary + start: 4 + end: 32 + - source: var jwt = require('express-jwt'); + style: secondary + start: 0 + end: 33 + - source: |- + app.get('/protected', jwt({ secret: 'shhhhhhared-secret' }), function(req, res) { + if (!req.user.admin) return res.sendStatus(401); + res.sendStatus(200); + }); + style: secondary + start: 34 + end: 189 diff --git a/tests/javascript/express-jwt-hardcoded-secret-javascript-test.yml b/tests/javascript/express-jwt-hardcoded-secret-javascript-test.yml new file mode 100644 index 00000000..5f2f59bf --- /dev/null +++ b/tests/javascript/express-jwt-hardcoded-secret-javascript-test.yml @@ -0,0 +1,14 @@ +id: express-jwt-hardcoded-secret-javascript +valid: + - | + app.get('/ok-protected', jwt({ secret: process.env.SECRET }), function(req, res) { + if (!req.user.admin) return res.sendStatus(401); + res.sendStatus(200); + }); +invalid: + - | + var jwt = require('express-jwt'); + app.get('/protected', jwt({ secret: 'shhhhhhared-secret' }), function(req, res) { + if (!req.user.admin) return res.sendStatus(401); + res.sendStatus(200); + }); From dfc40dc26ced6a4ff08d143f3bb24d264cc931c3 Mon Sep 17 00:00:00 2001 From: ESS-ENN Date: Wed, 9 Oct 2024 12:21:14 +0530 Subject: [PATCH 3/4] node-rsa-weak-key-typescript --- .../security/node-rsa-weak-key-typescript.yml | 577 ++++++++++++++++++ .../node-rsa-weak-key-typescript-snapshot.yml | 122 ++++ .../node-rsa-weak-key-typescript-test.yml | 18 + 3 files changed, 717 insertions(+) create mode 100644 rules/typescript/security/node-rsa-weak-key-typescript.yml create mode 100644 tests/__snapshots__/node-rsa-weak-key-typescript-snapshot.yml create mode 100644 tests/typescript/node-rsa-weak-key-typescript-test.yml diff --git a/rules/typescript/security/node-rsa-weak-key-typescript.yml b/rules/typescript/security/node-rsa-weak-key-typescript.yml new file mode 100644 index 00000000..e92b05ff --- /dev/null +++ b/rules/typescript/security/node-rsa-weak-key-typescript.yml @@ -0,0 +1,577 @@ +id: node-rsa-weak-key-typescript +language: typescript +severity: warning +message: >- + Use of RSA-$BITS, which is considered weak. Based on NIST standards, + 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: + MATCH_BITS_DIRECTLY_NODE_FORGE: + kind: number + pattern: $R + inside: + stopBy: end + kind: lexical_declaration + all: + - has: + stopBy: end + kind: variable_declarator + has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: end + kind: member_expression + has: + stopBy: end + kind: member_expression + all: + - has: + stopBy: end + kind: identifier + pattern: $A + - has: + stopBy: end + kind: property_identifier + regex: "^rsa$" + - has: + stopBy: end + kind: arguments + has: + stopBy: end + kind: number + pattern: $R + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + pattern: $A + - has: + stopBy: end + kind: member_expression + all: + - has: + stopBy: end + kind: identifier + - has: + stopBy: neighbor + kind: property_identifier + regex: "^pki$" + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: "^require$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-forge$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + has: + stopBy: end + kind: namespace_import + has: + stopBy: neighbor + kind: identifier + - has: + stopBy: end + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-forge$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-forge$" + MATCH_BITS_DIRECTLY_NODE_RSA: + kind: number + pattern: $R + inside: + stopBy: end + kind: lexical_declaration + all: + - has: + stopBy: end + kind: variable_declarator + has: + stopBy: end + kind: new_expression + all: + - has: + stopBy: neighbor + kind: identifier + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: object + has: + stopBy: neighbor + kind: pair + all: + - has: + stopBy: neighbor + kind: property_identifier + - has: + stopBy: neighbor + kind: number + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: "^require$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-rsa$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + has: + stopBy: end + kind: namespace_import + has: + stopBy: neighbor + kind: identifier + - has: + stopBy: end + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-rsa$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-rsa$" + MATCH_BITS_WITHIN_FUNCTION_WITH_NODE_FORGE: + kind: number + pattern: $R + inside: + stopBy: end + kind: variable_declaration + all: + - has: + stopBy: end + kind: variable_declarator + has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: end + kind: member_expression + - has: + stopBy: end + kind: arguments + has: + stopBy: end + kind: object + has: + stopBy: end + kind: pair + all: + - has: + stopBy: end + kind: property_identifier + - has: + stopBy: end + kind: number + pattern: $R + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: "^require$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-forge$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + has: + stopBy: end + kind: namespace_import + has: + stopBy: neighbor + kind: identifier + - has: + stopBy: end + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-forge$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-forge$" + MATCH_BITS_WITHIN_FUNCTION_WITH_CRYPTO_AND_PROMISIFY: + kind: number + pattern: $R + inside: + stopBy: end + kind: lexical_declaration + all: + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: end + kind: member_expression + has: + stopBy: end + kind: property_identifier + regex: "^promisify$" + - has: + stopBy: end + kind: arguments + has: + stopBy: end + kind: member_expression + all: + - has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: end + kind: property_identifier + - has: + stopBy: end + kind: arguments + all: + - has: + stopBy: end + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^rsa$" + - has: + stopBy: end + kind: object + has: + stopBy: neighbor + kind: pair + all: + - has: + stopBy: end + kind: property_identifier + regex: "^modulusLength$" + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: "^require$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^crypto$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + has: + stopBy: end + kind: namespace_import + has: + stopBy: neighbor + kind: identifier + pattern: $E + - has: + stopBy: end + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^crypto$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^crypto$" + MATCH_BITS_WITHIN_FUNCTION_WITH_CRYPTO: + kind: number + pattern: $R + inside: + stopBy: end + kind: lexical_declaration + all: + - has: + stopBy: end + kind: variable_declarator + has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: end + kind: member_expression + all: + - has: + stopBy: end + kind: identifier + pattern: $S + - has: + stopBy: end + kind: property_identifier + - has: + stopBy: end + kind: arguments + all: + - has: + stopBy: end + kind: string + has: + stopBy: end + kind: string_fragment + regex: "^rsa$" + - has: + stopBy: end + kind: object + has: + stopBy: end + kind: pair + all: + - has: + stopBy: end + kind: property_identifier + regex: "^modulusLength$" + - has: + stopBy: neighbor + kind: number + pattern: $R + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + pattern: $S + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: "^require$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^crypto$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + has: + stopBy: end + kind: namespace_import + has: + stopBy: neighbor + kind: identifier + pattern: $S + - has: + stopBy: end + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^crypto$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^crypto$" +rule: + kind: number + any: + - matches: MATCH_BITS_DIRECTLY_NODE_FORGE + - matches: MATCH_BITS_DIRECTLY_NODE_RSA + - matches: MATCH_BITS_WITHIN_FUNCTION_WITH_NODE_FORGE + - matches: MATCH_BITS_WITHIN_FUNCTION_WITH_CRYPTO_AND_PROMISIFY + - matches: MATCH_BITS_WITHIN_FUNCTION_WITH_CRYPTO + +constraints: + R: + regex: '^(-?(0|[1-9][0-9]?|[1-9][0-9]{2}|1[0-9]{3}|20[0-3][0-9]|204[0-7])(\.[0-9]+)?|0|-[1-9][0-9]*|-[1-9][0-9]{2,}|-1[0-9]{3}|-20[0-3][0-9]|-204[0-7])$' diff --git a/tests/__snapshots__/node-rsa-weak-key-typescript-snapshot.yml b/tests/__snapshots__/node-rsa-weak-key-typescript-snapshot.yml new file mode 100644 index 00000000..c03ca54c --- /dev/null +++ b/tests/__snapshots__/node-rsa-weak-key-typescript-snapshot.yml @@ -0,0 +1,122 @@ +id: node-rsa-weak-key-typescript +snapshots: + ? | + const crypto = require("crypto"); + const NodeRSA = require('node-rsa'); + const forge = require('node-forge'); + const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", { + a: 123, + modulusLength: 512, + }); + const key = new NodeRSA({b: 2048}); + const key = new NodeRSA({b: 512}); + const pki = forge.pki; + : labels: + - source: '512' + style: primary + start: 201 + end: 204 + - source: crypto + style: secondary + start: 142 + end: 148 + - source: generateKeyPairSync + style: secondary + start: 149 + end: 168 + - source: crypto.generateKeyPairSync + style: secondary + start: 142 + end: 168 + - source: rsa + style: secondary + start: 170 + end: 173 + - source: '"rsa"' + style: secondary + start: 169 + end: 174 + - source: modulusLength + style: secondary + start: 186 + end: 199 + - source: '512' + style: secondary + start: 201 + end: 204 + - source: 'modulusLength: 512' + style: secondary + start: 186 + end: 204 + - source: |- + { + a: 123, + modulusLength: 512, + } + style: secondary + start: 176 + end: 207 + - source: |- + ("rsa", { + a: 123, + modulusLength: 512, + }) + style: secondary + start: 168 + end: 208 + - source: |- + crypto.generateKeyPairSync("rsa", { + a: 123, + modulusLength: 512, + }) + style: secondary + start: 142 + end: 208 + - source: |- + { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", { + a: 123, + modulusLength: 512, + }) + style: secondary + start: 114 + end: 208 + - source: crypto + style: secondary + start: 6 + end: 12 + - source: require + style: secondary + start: 15 + end: 22 + - source: crypto + style: secondary + start: 24 + end: 30 + - source: '"crypto"' + style: secondary + start: 23 + end: 31 + - source: ("crypto") + style: secondary + start: 22 + end: 32 + - source: require("crypto") + style: secondary + start: 15 + end: 32 + - source: crypto = require("crypto") + style: secondary + start: 6 + end: 32 + - source: const crypto = require("crypto"); + style: secondary + start: 0 + end: 33 + - source: |- + const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", { + a: 123, + modulusLength: 512, + }); + style: secondary + start: 108 + end: 209 diff --git a/tests/typescript/node-rsa-weak-key-typescript-test.yml b/tests/typescript/node-rsa-weak-key-typescript-test.yml new file mode 100644 index 00000000..90230944 --- /dev/null +++ b/tests/typescript/node-rsa-weak-key-typescript-test.yml @@ -0,0 +1,18 @@ +id: node-rsa-weak-key-typescript +valid: + - | + const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", { + modulusLength: 2048, + }); +invalid: + - | + const crypto = require("crypto"); + const NodeRSA = require('node-rsa'); + const forge = require('node-forge'); + const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", { + a: 123, + modulusLength: 512, + }); + const key = new NodeRSA({b: 2048}); + const key = new NodeRSA({b: 512}); + const pki = forge.pki; From 5cc4c1dddc5a7ff9bba7d719e4d760ac3ab6693d Mon Sep 17 00:00:00 2001 From: ESS-ENN Date: Wed, 9 Oct 2024 12:23:03 +0530 Subject: [PATCH 4/4] node-rsa-weak-key-javascript --- .../security/node-rsa-weak-key-javascript.yml | 577 ++++++++++++++++++ .../node-rsa-weak-key-javascript-snapshot.yml | 122 ++++ .../node-rsa-weak-key-javascript-test.yml | 18 + 3 files changed, 717 insertions(+) create mode 100644 rules/javascript/security/node-rsa-weak-key-javascript.yml create mode 100644 tests/__snapshots__/node-rsa-weak-key-javascript-snapshot.yml create mode 100644 tests/javascript/node-rsa-weak-key-javascript-test.yml diff --git a/rules/javascript/security/node-rsa-weak-key-javascript.yml b/rules/javascript/security/node-rsa-weak-key-javascript.yml new file mode 100644 index 00000000..c2faaa01 --- /dev/null +++ b/rules/javascript/security/node-rsa-weak-key-javascript.yml @@ -0,0 +1,577 @@ +id: node-rsa-weak-key-javascript +language: javascript +severity: warning +message: >- + Use of RSA-$BITS, which is considered weak. Based on NIST standards, + 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: + MATCH_BITS_DIRECTLY_NODE_FORGE: + kind: number + pattern: $R + inside: + stopBy: end + kind: lexical_declaration + all: + - has: + stopBy: end + kind: variable_declarator + has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: end + kind: member_expression + has: + stopBy: end + kind: member_expression + all: + - has: + stopBy: end + kind: identifier + pattern: $A + - has: + stopBy: end + kind: property_identifier + regex: "^rsa$" + - has: + stopBy: end + kind: arguments + has: + stopBy: end + kind: number + pattern: $R + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + pattern: $A + - has: + stopBy: end + kind: member_expression + all: + - has: + stopBy: end + kind: identifier + - has: + stopBy: neighbor + kind: property_identifier + regex: "^pki$" + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: "^require$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-forge$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + has: + stopBy: end + kind: namespace_import + has: + stopBy: neighbor + kind: identifier + - has: + stopBy: end + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-forge$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-forge$" + MATCH_BITS_DIRECTLY_NODE_RSA: + kind: number + pattern: $R + inside: + stopBy: end + kind: lexical_declaration + all: + - has: + stopBy: end + kind: variable_declarator + has: + stopBy: end + kind: new_expression + all: + - has: + stopBy: neighbor + kind: identifier + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: object + has: + stopBy: neighbor + kind: pair + all: + - has: + stopBy: neighbor + kind: property_identifier + - has: + stopBy: neighbor + kind: number + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: "^require$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-rsa$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + has: + stopBy: end + kind: namespace_import + has: + stopBy: neighbor + kind: identifier + - has: + stopBy: end + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-rsa$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-rsa$" + MATCH_BITS_WITHIN_FUNCTION_WITH_NODE_FORGE: + kind: number + pattern: $R + inside: + stopBy: end + kind: variable_declaration + all: + - has: + stopBy: end + kind: variable_declarator + has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: end + kind: member_expression + - has: + stopBy: end + kind: arguments + has: + stopBy: end + kind: object + has: + stopBy: end + kind: pair + all: + - has: + stopBy: end + kind: property_identifier + - has: + stopBy: end + kind: number + pattern: $R + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: "^require$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-forge$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + has: + stopBy: end + kind: namespace_import + has: + stopBy: neighbor + kind: identifier + - has: + stopBy: end + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-forge$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^node-forge$" + MATCH_BITS_WITHIN_FUNCTION_WITH_CRYPTO_AND_PROMISIFY: + kind: number + pattern: $R + inside: + stopBy: end + kind: lexical_declaration + all: + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: end + kind: member_expression + has: + stopBy: end + kind: property_identifier + regex: "^promisify$" + - has: + stopBy: end + kind: arguments + has: + stopBy: end + kind: member_expression + all: + - has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: end + kind: property_identifier + - has: + stopBy: end + kind: arguments + all: + - has: + stopBy: end + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^rsa$" + - has: + stopBy: end + kind: object + has: + stopBy: neighbor + kind: pair + all: + - has: + stopBy: end + kind: property_identifier + regex: "^modulusLength$" + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + pattern: $E + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: "^require$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^crypto$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + has: + stopBy: end + kind: namespace_import + has: + stopBy: neighbor + kind: identifier + pattern: $E + - has: + stopBy: end + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^crypto$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^crypto$" + MATCH_BITS_WITHIN_FUNCTION_WITH_CRYPTO: + kind: number + pattern: $R + inside: + stopBy: end + kind: lexical_declaration + all: + - has: + stopBy: end + kind: variable_declarator + has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: end + kind: member_expression + all: + - has: + stopBy: end + kind: identifier + pattern: $S + - has: + stopBy: end + kind: property_identifier + - has: + stopBy: end + kind: arguments + all: + - has: + stopBy: end + kind: string + has: + stopBy: end + kind: string_fragment + regex: "^rsa$" + - has: + stopBy: end + kind: object + has: + stopBy: end + kind: pair + all: + - has: + stopBy: end + kind: property_identifier + regex: "^modulusLength$" + - has: + stopBy: neighbor + kind: number + pattern: $R + - any: + - follows: + stopBy: end + kind: lexical_declaration + has: + stopBy: end + kind: variable_declarator + all: + - has: + stopBy: end + kind: identifier + pattern: $S + - has: + stopBy: end + kind: call_expression + all: + - has: + stopBy: neighbor + kind: identifier + regex: "^require$" + - has: + stopBy: neighbor + kind: arguments + has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^crypto$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + has: + stopBy: end + kind: namespace_import + has: + stopBy: neighbor + kind: identifier + pattern: $S + - has: + stopBy: end + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^crypto$" + - follows: + stopBy: end + kind: import_statement + all: + - has: + stopBy: neighbor + kind: import_clause + - has: + stopBy: neighbor + kind: string + has: + stopBy: neighbor + kind: string_fragment + regex: "^crypto$" +rule: + kind: number + any: + - matches: MATCH_BITS_DIRECTLY_NODE_FORGE + - matches: MATCH_BITS_DIRECTLY_NODE_RSA + - matches: MATCH_BITS_WITHIN_FUNCTION_WITH_NODE_FORGE + - matches: MATCH_BITS_WITHIN_FUNCTION_WITH_CRYPTO_AND_PROMISIFY + - matches: MATCH_BITS_WITHIN_FUNCTION_WITH_CRYPTO + +constraints: + R: + regex: '^(-?(0|[1-9][0-9]?|[1-9][0-9]{2}|1[0-9]{3}|20[0-3][0-9]|204[0-7])(\.[0-9]+)?|0|-[1-9][0-9]*|-[1-9][0-9]{2,}|-1[0-9]{3}|-20[0-3][0-9]|-204[0-7])$' diff --git a/tests/__snapshots__/node-rsa-weak-key-javascript-snapshot.yml b/tests/__snapshots__/node-rsa-weak-key-javascript-snapshot.yml new file mode 100644 index 00000000..51e1d6ca --- /dev/null +++ b/tests/__snapshots__/node-rsa-weak-key-javascript-snapshot.yml @@ -0,0 +1,122 @@ +id: node-rsa-weak-key-javascript +snapshots: + ? | + const crypto = require("crypto"); + const NodeRSA = require('node-rsa'); + const forge = require('node-forge'); + const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", { + a: 123, + modulusLength: 512, + }); + const key = new NodeRSA({b: 2048}); + const key = new NodeRSA({b: 512}); + const pki = forge.pki; + : labels: + - source: '512' + style: primary + start: 201 + end: 204 + - source: crypto + style: secondary + start: 142 + end: 148 + - source: generateKeyPairSync + style: secondary + start: 149 + end: 168 + - source: crypto.generateKeyPairSync + style: secondary + start: 142 + end: 168 + - source: rsa + style: secondary + start: 170 + end: 173 + - source: '"rsa"' + style: secondary + start: 169 + end: 174 + - source: modulusLength + style: secondary + start: 186 + end: 199 + - source: '512' + style: secondary + start: 201 + end: 204 + - source: 'modulusLength: 512' + style: secondary + start: 186 + end: 204 + - source: |- + { + a: 123, + modulusLength: 512, + } + style: secondary + start: 176 + end: 207 + - source: |- + ("rsa", { + a: 123, + modulusLength: 512, + }) + style: secondary + start: 168 + end: 208 + - source: |- + crypto.generateKeyPairSync("rsa", { + a: 123, + modulusLength: 512, + }) + style: secondary + start: 142 + end: 208 + - source: |- + { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", { + a: 123, + modulusLength: 512, + }) + style: secondary + start: 114 + end: 208 + - source: crypto + style: secondary + start: 6 + end: 12 + - source: require + style: secondary + start: 15 + end: 22 + - source: crypto + style: secondary + start: 24 + end: 30 + - source: '"crypto"' + style: secondary + start: 23 + end: 31 + - source: ("crypto") + style: secondary + start: 22 + end: 32 + - source: require("crypto") + style: secondary + start: 15 + end: 32 + - source: crypto = require("crypto") + style: secondary + start: 6 + end: 32 + - source: const crypto = require("crypto"); + style: secondary + start: 0 + end: 33 + - source: |- + const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", { + a: 123, + modulusLength: 512, + }); + style: secondary + start: 108 + end: 209 diff --git a/tests/javascript/node-rsa-weak-key-javascript-test.yml b/tests/javascript/node-rsa-weak-key-javascript-test.yml new file mode 100644 index 00000000..7031b6c0 --- /dev/null +++ b/tests/javascript/node-rsa-weak-key-javascript-test.yml @@ -0,0 +1,18 @@ +id: node-rsa-weak-key-javascript +valid: + - | + const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", { + modulusLength: 2048, + }); +invalid: + - | + const crypto = require("crypto"); + const NodeRSA = require('node-rsa'); + const forge = require('node-forge'); + const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", { + a: 123, + modulusLength: 512, + }); + const key = new NodeRSA({b: 2048}); + const key = new NodeRSA({b: 512}); + const pki = forge.pki;