You need to sign in or sign up before continuing.
CWE-94 not dectected in semgrep scanner version higher than 4.0.0
Summary
CWE-94 isn't detected by semgrep analyzer image higher than 4.0.0
. the CWE-94 is missing from cat /rules/eslint.yml
in semgrep job using image tag higher than 4.0.0.
The rule was removed from semgrep in this MR: gitlab-org/security-products/analyzers/semgrep!244 (diffs) to use sast-rule as a SSOT
Steps to reproduce
- Run semgrep job in a project with cwe-94 vulnerability
- Observe the pipeline security report doesn't dectect cwe-94
- Run another job with
SAST_ANALYZER_IMAGE_TAG: "4.0.0"
and see the cwe-94 being detected
Example Project
What is the current bug behavior?
What is the expected correct behavior?
Relevant logs and/or screenshots
eslint.yml 4.0.0
rules:
- id: "eslint.detect-new-buffer"
metadata:
source-rule-url: "https://github.com/eslint-community/eslint-plugin-security/blob/main/rules/detect-new-buffer.js"
primary_identifier: "eslint.detect-new-buffer"
secondary_identifiers:
- name: "ESLint rule ID/detect-new-buffer"
type: "eslint_rule_id"
value: "detect-new-buffer"
patterns:
- patterns:
- pattern-not-inside: |-
require("safe-buffer")
...
- pattern-not-inside: |-
import { Buffer } from "safe-buffer"
...
- pattern-inside: |-
function $FUNC(..., $X, ...) { ... }
- pattern: "new Buffer($X,...)"
- pattern-not: |
new Buffer("...",...)
- pattern-not: |
new Buffer([...] , ...)
message: |
Detects instances of new Buffer(argument) where argument is any non-literal value which could
cause memory leak. Recommended usage is `Buffer.from()` or `Buffer.alloc()`.
languages:
- "javascript"
- "typescript"
severity: "ERROR"
- id: eslint.detect-no-csrf-before-method-override
metadata:
cwe: "CWE-352: Cross-Site Request Forgery (CSRF)"
source-rule-url: "https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-no-csrf-before-method-override.js"
references:
- "https://github.com/nodesecurity/eslint-plugin-security/blob/master/docs/bypass-connect-csrf-protection-by-abusing.md"
primary_identifier: "eslint.detect-no-csrf-before-method-override"
secondary_identifiers:
- name: "ESLint rule ID security/detect-no-csrf-before-method-override"
type: "eslint_rule_id"
value: "security/detect-no-csrf-before-method-override"
message: |
Detected use of express.csrf() middleware before express.methodOverride(). This can
allow GET requests (which are not checked by csrf) to turn into POST requests later.
pattern: |
express.csrf();
...
express.methodOverride();
severity: WARNING
languages:
- javascript
- typescript
- id: eslint.detect-eval-with-expression
metadata:
cwe: "CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code
('Eval Injection')"
owasp: "A1: Injection"
source-rule-url: "https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-eval-with-expression.js"
primary_identifier: "eslint.detect-eval-with-expression"
secondary_identifiers:
- name: "ESLint rule ID security/detect-eval-with-expression"
type: "eslint_rule_id"
value: "security/detect-eval-with-expression"
message: |
Detected eval(variable), which could allow a malicious actor to run arbitrary code.
patterns:
- pattern: eval($OBJ)
- pattern-not: eval("...")
severity: WARNING
languages:
- javascript
- typescript
- id: eslint.detect-child-process
metadata:
cwe: "CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code
('Eval Injection')"
owasp: "A1: Injection"
source-rule-url: "https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-child-process.js"
primary_identifier: "eslint.detect-child-process"
secondary_identifiers:
- name: "ESLint rule ID security/detect-child-process"
type: "eslint_rule_id"
value: "security/detect-child-process"
message: |
Detected non-literal calls to child_process.exec(). This could lead to a command
injection vulnerability.
patterns:
- pattern: child_process.exec(...)
- pattern-not: child_process.exec('...')
severity: WARNING
languages:
- javascript
- typescript
- id: eslint.detect-pseudoRandomBytes
metadata:
cwe: "CWE-338: Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)"
source-rule-url: "https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-pseudoRandomBytes.js"
primary_identifier: "eslint.detect-pseudoRandomBytes"
secondary_identifiers:
- name: "ESLint rule ID security/detect-pseudoRandomBytes"
type: "eslint_rule_id"
value: "security/detect-pseudoRandomBytes"
message: |
Detected usage of crypto.pseudoRandomBytes, which does not produce secure random numbers.
pattern: crypto.pseudoRandomBytes
severity: WARNING
languages:
- javascript
- typescript
- id: eslint.detect-disable-mustache-escape
metadata:
cwe: "CWE-79: Improper Neutralization of Input During Web Page Generation (XSS)"
owasp: "A7: Cross-Site Scripting XSS"
source-rule-url: "https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-disable-mustache-escape.js"
primary_identifier: "eslint.detect-disable-mustache-escape"
secondary_identifiers:
- name: "ESLint rule ID security/detect-disable-mustache-escape"
type: "eslint_rule_id"
value: "security/detect-disable-mustache-escape"
message: |
Markup escaping disabled. This can be used with some template engines to escape
disabling of HTML entities, which can lead to XSS attacks.
pattern: $OBJ.escapeMarkup = false
severity: WARNING
languages:
- javascript
- typescript
- id: eslint.detect-non-literal-require
metadata:
cwe: "CWE-95: Improper Neutralization of Directives in Dynamically Evaluated Code
('Eval Injection')"
owasp: "A1: Injection"
source-rule-url: "https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-non-literal-require.js"
primary_identifier: "eslint.detect-non-literal-require"
secondary_identifiers:
- name: "ESLint rule ID security/detect-non-literal-require"
type: "eslint_rule_id"
value: "security/detect-non-literal-require"
message: |
Detected the use of require(variable). Calling require with a non-literal argument might
allow an attacker to load an run arbitrary code, or access arbitrary files.
patterns:
- pattern: require($OBJ)
- pattern-not: require('...')
severity: WARNING
languages:
- javascript
- typescript
- id: eslint.detect-buffer-noassert
metadata:
cwe: "CWE-119: Improper Restriction of Operations within the Bounds of a Memory
Buffer"
source-rule-url: "https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-buffer-noassert.js"
primary_identifier: "eslint.detect-buffer-noassert"
secondary_identifiers:
- name: "ESLint rule ID security/detect-buffer-noassert"
type: "eslint_rule_id"
value: "security/detect-buffer-noassert"
message: |
Detected usage of noassert in Buffer API, which allows the offset the be beyond the
end of the buffer. This could result in writing or reading beyond the end of the buffer.
pattern-either:
- pattern: $OBJ.readUInt8(..., true)
- pattern: $OBJ.readUInt16LE(..., true)
- pattern: $OBJ.readUInt16BE(..., true)
- pattern: $OBJ.readUInt32LE(..., true)
- pattern: $OBJ.readUInt32BE(..., true)
- pattern: $OBJ.readInt8(..., true)
- pattern: $OBJ.readInt16LE(..., true)
- pattern: $OBJ.readInt16BE(..., true)
- pattern: $OBJ.readInt32LE(..., true)
- pattern: $OBJ.readInt32BE(..., true)
- pattern: $OBJ.readFloatLE(..., true)
- pattern: $OBJ.readFloatBE(..., true)
- pattern: $OBJ.readDoubleLE(..., true)
- pattern: $OBJ.readDoubleBE(..., true)
- pattern: $OBJ.writeUInt8(..., true)
- pattern: $OBJ.writeUInt16LE(..., true)
- pattern: $OBJ.writeUInt16BE(..., true)
- pattern: $OBJ.writeUInt32LE(..., true)
- pattern: $OBJ.writeUInt32BE(..., true)
- pattern: $OBJ.writeInt8(..., true)
- pattern: $OBJ.writeInt16LE(..., true)
- pattern: $OBJ.writeInt16BE(..., true)
- pattern: $OBJ.writeInt32LE(..., true)
- pattern: $OBJ.writeInt32BE(..., true)
- pattern: $OBJ.writeFloatLE(..., true)
- pattern: $OBJ.writeFloatBE(..., true)
- pattern: $OBJ.writeDoubleLE(..., true)
- pattern: $OBJ.writeDoubleBE(..., true)
severity: WARNING
languages:
- javascript
- typescript
- id: eslint.detect-possible-timing-attacks
patterns:
- pattern-not: if ($Z == null) { ... };
- pattern-not: if ($Z === null) { ... };
- pattern-not: if ($Z != null) { ... };
- pattern-not: if ($Z !== null) { ... };
- pattern-not: if ($Q != undefined) { ... };
- pattern-not: if ($Q !== undefined) { ... };
- pattern-not: if ($Q == undefined) { ... };
- pattern-not: if ($Q === undefined) { ... };
- pattern-not: return $Y == null;
- pattern-not: return $Y === null;
- pattern-not: return $Y != null;
- pattern-not: return $Y !== null;
- pattern-not: return $Y == undefined;
- pattern-not: return $Y === undefined;
- pattern-not: return $Y != undefined;
- pattern-not: return $Y !== undefined;
- pattern-either:
- pattern: |
if (password == $X) {
...
}
- pattern: |
if ($X == password) {
...
}
- pattern: |
if (password === $X) {
...
}
- pattern: |
if ($X === password) {
...
}
- pattern: |
if (pass == $X) {
...
}
- pattern: |
if ($X == pass) {
...
}
- pattern: |
if (pass === $X) {
...
}
- pattern: |
if ($X === pass) {
...
}
- pattern: |
if (secret == $X) {
...
}
- pattern: |
if ($X == secret) {
...
}
- pattern: |
if (secret === $X) {
...
}
- pattern: |
if ($X === secret) {
...
}
- pattern: |
if (api == $X) {
...
}
- pattern: |
if ($X == api) {
...
}
- pattern: |
if (api === $X) {
...
}
- pattern: |
if ($X === api) {
...
}
- pattern: |
if (apiKey == $X) {
...
}
- pattern: |
if ($X == apiKey) {
...
}
- pattern: |
if (apiKey === $X) {
...
}
- pattern: |
if ($X === apiKey) {
...
}
- pattern: |
if (apiSecret == $X) {
...
}
- pattern: |
if ($X == apiSecret) {
...
}
- pattern: |
if (apiSecret === $X) {
...
}
- pattern: |
if ($X === apiSecret) {
...
}
- pattern: |
if (token == $X) {
...
}
- pattern: |
if ($X == token) {
...
}
- pattern: |
if (token === $X) {
...
}
- pattern: |
if ($X === token) {
...
}
- pattern: |
if (hash == $X) {
...
}
- pattern: |
if ($X == hash) {
...
}
- pattern: |
if (hash === $X) {
...
}
- pattern: |
if ($X === hash) {
...
}
- pattern: |
if (auth_token == $X) {
...
}
- pattern: |
if ($X == auth_token) {
...
}
- pattern: |
if (auth_token === $X) {
...
}
- pattern: |
if ($X === auth_token) {
...
}
- pattern: |
if (password != $X) {
...
}
- pattern: |
if ($X != password) {
...
}
- pattern: |
if (password !== $X) {
...
}
- pattern: |
if ($X !== password) {
...
}
- pattern: |
if (pass != $X) {
...
}
- pattern: |
if ($X != pass) {
...
}
- pattern: |
if (pass !== $X) {
...
}
- pattern: |
if ($X !== pass) {
...
}
- pattern: |
if (secret != $X) {
...
}
- pattern: |
if ($X != secret) {
...
}
- pattern: |
if (secret !== $X) {
...
}
- pattern: |
if ($X !== secret) {
...
}
- pattern: |
if (api != $X) {
...
}
- pattern: |
if ($X != api) {
...
}
- pattern: |
if (api !== $X) {
...
}
- pattern: |
if ($X !== api) {
...
}
- pattern: |
if (apiKey != $X) {
...
}
- pattern: |
if ($X != apiKey) {
...
}
- pattern: |
if (apiKey !== $X) {
...
}
- pattern: |
if ($X !== apiKey) {
...
}
- pattern: |
if (apiSecret != $X) {
...
}
- pattern: |
if ($X != apiSecret) {
...
}
- pattern: |
if (apiSecret !== $X) {
...
}
- pattern: |
if ($X !== apiSecret) {
...
}
- pattern: |
if (token != $X) {
...
}
- pattern: |
if ($X != token) {
...
}
- pattern: |
if (token !== $X) {
...
}
- pattern: |
if ($X !== token) {
...
}
- pattern: |
if (hash != $X) {
...
}
- pattern: |
if ($X != hash) {
...
}
- pattern: |
if (hash !== $X) {
...
}
- pattern: |
if ($X !== hash) {
...
}
- pattern: |
if (auth_token != $X) {
...
}
- pattern: |
if ($X != auth_token) {
...
}
- pattern: |
if (auth_token !== $X) {
...
}
- pattern: |
if ($X !== auth_token) {
...
}
- pattern: |
return $X === auth_token;
- pattern: |
return auth_token === $X;
- pattern: |
return $X === token;
- pattern: |
return token === $X;
- pattern: |
return $X === hash;
- pattern: |
return hash === $X;
- pattern: |
return $X === password;
- pattern: |
return password === $X;
- pattern: |
return $X === pass;
- pattern: |
return pass === $X;
- pattern: |
return $X === apiKey;
- pattern: |
return apiKey === $X;
- pattern: |
return $X === apiSecret;
- pattern: |
return apiSecret === $X;
- pattern: |
return $X === api_key;
- pattern: |
return api_key === $X;
- pattern: |
return $X === api_secret;
- pattern: |
return api_secret === $X;
- pattern: |
return $X === secret;
- pattern: |
return secret === $X;
- pattern: |
return $X === api;
- pattern: |
return api === $X;
- pattern: |
return $X == auth_token;
- pattern: |
return auth_token == $X;
- pattern: |
return $X == token;
- pattern: |
return token == $X;
- pattern: |
return $X == hash;
- pattern: |
return hash == $X;
- pattern: |
return $X == password;
- pattern: |
return password == $X;
- pattern: |
return $X == pass;
- pattern: |
return pass == $X;
- pattern: |
return $X == apiKey;
- pattern: |
return apiKey == $X;
- pattern: |
return $X == apiSecret;
- pattern: |
return apiSecret == $X;
- pattern: |
return $X == api_key;
- pattern: |
return api_key == $X;
- pattern: |
return $X == api_secret;
- pattern: |
return api_secret == $X;
- pattern: |
return $X == secret;
- pattern: |
return secret == $X;
- pattern: |
return $X == api;
- pattern: |
return api == $X;
- pattern: |
return $X !== auth_token;
- pattern: |
return auth_token !== $X;
- pattern: |
return $X !== token;
- pattern: |
return token !== $X;
- pattern: |
return $X !== hash;
- pattern: |
return hash !== $X;
- pattern: |
return $X !== password;
- pattern: |
return password !== $X;
- pattern: |
return $X !== pass;
- pattern: |
return pass !== $X;
- pattern: |
return $X !== apiKey;
- pattern: |
return apiKey !== $X;
- pattern: |
return $X !== apiSecret;
- pattern: |
return apiSecret !== $X;
- pattern: |
return $X !== api_key;
- pattern: |
return api_key !== $X;
- pattern: |
return $X !== api_secret;
- pattern: |
return api_secret !== $X;
- pattern: |
return $X !== secret;
- pattern: |
return secret !== $X;
- pattern: |
return $X !== api;
- pattern: |
return api !== $X;
- pattern: |
return $X != auth_token;
- pattern: |
return auth_token != $X;
- pattern: |
return $X != token;
- pattern: |
return token != $X;
- pattern: |
return $X != hash;
- pattern: |
return hash != $X;
- pattern: |
return $X != password;
- pattern: |
return password != $X;
- pattern: |
return $X != pass;
- pattern: |
return pass != $X;
- pattern: |
return $X != apiKey;
- pattern: |
return apiKey != $X;
- pattern: |
return $X != apiSecret;
- pattern: |
return apiSecret != $X;
- pattern: |
return $X != api_key;
- pattern: |
return api_key != $X;
- pattern: |
return $X != api_secret;
- pattern: |
return api_secret != $X;
- pattern: |
return $X != secret;
- pattern: |
return secret != $X;
- pattern: |
return $X != api;
- pattern: |
return api != $X;
message: >-
String comparisons using '===', '!==', '!=' and '==' is vulnerable to timing attacks.
More info: https://snyk.io/blog/node-js-timing-attack-ccc-ctf/
languages:
- javascript
severity: WARNING
metadata:
cwe: "CWE-208: Observable Timing Discrepancy"
primary_identifier: "eslint.detect-possible-timing-attacks"
secondary_identifiers:
- name: "ESLint rule ID security/detect-possible-timing-attacks"
type: "eslint_rule_id"
value: "security/detect-possible-timing-attacks"
- id: eslint.detect-non-literal-regexp
patterns:
- pattern: |
new RegExp($ARG, ...)
- pattern-not: |
new RegExp("...", ...)
message: |
RegExp() called with a variable, this might allow an attacker to DOS your application with a long-running regular expression.
languages:
- javascript
- typescript
severity: WARNING
metadata:
cwe: "CWE-185: Incorrect Regular Expression"
primary_identifier: "eslint.detect-non-literal-regexp"
secondary_identifiers:
- name: "ESLint rule ID security/detect-non-literal-regexp"
type: "eslint_rule_id"
value: "security/detect-non-literal-regexp"
- id: eslint.detect-non-literal-fs-filename
patterns:
- pattern-not: $MOD.appendFile("...", ...)
- pattern-not: $MOD.appendFileSync("...", ...)
- pattern-not: $MOD.chmod("...", ...)
- pattern-not: $MOD.chmodSync("...", ...)
- pattern-not: $MOD.chown("...", ...)
- pattern-not: $MOD.chownSync("...", ...)
- pattern-not: $MOD.createReadStream("...", ...)
- pattern-not: $MOD.createWriteStream("...", ...)
- pattern-not: $MOD.exists("...", ...)
- pattern-not: $MOD.existsSync("...", ...)
- pattern-not: $MOD.lchmod("...", ...)
- pattern-not: $MOD.lchmodSync("...", ...)
- pattern-not: $MOD.lchown("...", ...)
- pattern-not: $MOD.lchownSync("...", ...)
- pattern-not: $MOD.link("...", "...", ...)
- pattern-not: $MOD.linkSync("...", "...", ...)
- pattern-not: $MOD.lstat("...", ...)
- pattern-not: $MOD.lstatSync("...", ...)
- pattern-not: $MOD.mkdir("...", ...)
- pattern-not: $MOD.mkdirSync("...", ...)
- pattern-not: $MOD.open("...", ...)
- pattern-not: $MOD.openSync("...", ...)
- pattern-not: $MOD.readdir("...", ...)
- pattern-not: $MOD.readdirSync("...", ...)
- pattern-not: $MOD.readFile("...", ...)
- pattern-not: $MOD.readFileSync("...", ...)
- pattern-not: $MOD.readlink("...", ...)
- pattern-not: $MOD.readlinkSync("...", ...)
- pattern-not: $MOD.realpath("...", ...)
- pattern-not: $MOD.realpathSync("...", ...)
- pattern-not: $MOD.rename("...", "...", ...)
- pattern-not: $MOD.renameSync("...", "...", ...)
- pattern-not: $MOD.rmdir("...", ...)
- pattern-not: $MOD.rmdirSync("...", ...)
- pattern-not: $MOD.stat("...", ...)
- pattern-not: $MOD.statSync("...", ...)
- pattern-not: $MOD.symlink("...", "...", ...)
- pattern-not: $MOD.symlinkSync("...", "...", ...)
- pattern-not: $MOD.truncate("...", ...)
- pattern-not: $MOD.truncateSync("...", ...)
- pattern-not: $MOD.unlink("...", ...)
- pattern-not: $MOD.unlinkSync("...", ...)
- pattern-not: $MOD.unwatchFile("...", ...)
- pattern-not: $MOD.utimes("...", ...)
- pattern-not: $MOD.utimesSync("...", ...)
- pattern-not: $MOD.watch("...", ...)
- pattern-not: $MOD.watchFile("...", ...)
- pattern-not: $MOD.writeFile("...", ...)
- pattern-not: $MOD.writeFileSync("...", ...)
- pattern-either:
- pattern: $MOD.appendFile(...)
- pattern: $MOD.appendFileSync(...)
- pattern: $MOD.chmod(...)
- pattern: $MOD.chmodSync(...)
- pattern: $MOD.chown(...)
- pattern: $MOD.chownSync(...)
- pattern: $MOD.createReadStream(...)
- pattern: $MOD.createWriteStream(...)
- pattern: $MOD.exists(...)
- pattern: $MOD.existsSync(...)
- pattern: $MOD.lchmod(...)
- pattern: $MOD.lchmodSync(...)
- pattern: $MOD.lchown(...)
- pattern: $MOD.lchownSync(...)
- pattern: $MOD.link(...)
- pattern: $MOD.linkSync(...)
- pattern: $MOD.lstat(...)
- pattern: $MOD.lstatSync(...)
- pattern: $MOD.mkdir(...)
- pattern: $MOD.mkdirSync(...)
- pattern: $MOD.open(...)
- pattern: $MOD.openSync(...)
- pattern: $MOD.readdir(...)
- pattern: $MOD.readdirSync(...)
- pattern: $MOD.readFile(...)
- pattern: $MOD.readFileSync(...)
- pattern: $MOD.readlink(...)
- pattern: $MOD.readlinkSync(...)
- pattern: $MOD.realpath(...)
- pattern: $MOD.realpathSync(...)
- pattern: $MOD.rename(...)
- pattern: $MOD.renameSync(...)
- pattern: $MOD.rmdir(...)
- pattern: $MOD.rmdirSync(...)
- pattern: $MOD.stat(...)
- pattern: $MOD.statSync(...)
- pattern: $MOD.symlink(...)
- pattern: $MOD.symlinkSync(...)
- pattern: $MOD.truncate(...)
- pattern: $MOD.truncateSync(...)
- pattern: $MOD.unlink(...)
- pattern: $MOD.unlinkSync(...)
- pattern: $MOD.unwatchFile(...)
- pattern: $MOD.utimes(...)
- pattern: $MOD.utimesSync(...)
- pattern: $MOD.watch(...)
- pattern: $MOD.watchFile(...)
- pattern: $MOD.writeFile(...)
- pattern: $MOD.writeFileSync(...)
message: |
A variable is present in the filename argument of fs calls, this might allow an attacker to access anything on your system.
languages:
- typescript
- javascript
severity: WARNING
metadata:
cwe: "CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path
Traversal')"
primary_identifier: "eslint.detect-non-literal-fs-filename"
secondary_identifiers:
- name: "ESLint rule ID security/detect-non-literal-fs-filename"
type: "eslint_rule_id"
value: "security/detect-non-literal-fs-filename"
- id: eslint.detect-object-injection
patterns:
- pattern: $O[$ARG]
- pattern-not: $O["..."]
- pattern-not: "$O[($ARG : float)]"
- pattern-not-inside: |
$ARG = [$V];
...
<... $O[$ARG] ...>;
- pattern-not-inside: |
$ARG = $V;
...
<... $O[$ARG] ...>;
- metavariable-regex:
metavariable: $ARG
regex: (?![0-9]+)
message: "Bracket object notation with user input is present, this might allow an attacker to access all properties of the object and even it's prototype, leading to possible code execution."
languages:
- javascript
- typescript
severity: WARNING
metadata:
cwe: "CWE-94: Improper Control of Generation of Code ('Code Injection')"
primary_identifier: "eslint.detect-object-injection"
secondary_identifiers:
- name: "ESLint rule ID security/detect-object-injection"
type: "eslint_rule_id"
value: "security/detect-object-injection"
- id: "eslint.react-missing-noopener"
pattern-either:
- patterns:
- pattern: |
<$X target="_blank" />
- pattern-not: |
<$X target="_blank" rel="..." />
- patterns:
- pattern-inside: |
<$X target="_blank" rel=... />
- pattern-regex: "rel=[\"']((?!noopener).)*?[\"']"
- patterns:
- pattern: |
React.createElement($A, {target: '_blank'},...)
- pattern-not: |
React.createElement($A, {rel: '...'},...)
- patterns:
- pattern: |
React.createElement($A, {target: '_blank', rel: $REL},...)
- metavariable-regex:
metavariable: "$REL"
regex: "[\"']((?!noopener).)*?['\"]"
- patterns:
- pattern: |
$P = {target: '_blank'};
...
React.createElement($A, $P,...);
- pattern-not: |
$P = {rel: '...'};
...
React.createElement($A, $P,...);
- patterns:
- pattern: |
$P = {target: '_blank', rel: $REL};
...
React.createElement($A, $P,...);
- metavariable-regex:
metavariable: "$REL"
regex: "[\"']((?!noopener).)*?['\"]"
message: |
Missing 'noopener' on an anchor tag where target='_blank'. This could introduce
a reverse tabnabbing vulnerability. Include 'noopener' when using target='_blank'.
metadata:
cwe: "CWE-200: Exposure of Sensitive Information to an Unauthorized Actor"
owasp: "A3: Sensitive Data Exposure"
references:
- "https://html.spec.whatwg.org/multipage/links.html#link-type-noreferrer"
- "https://web.dev/external-anchors-use-rel-noopener/"
- "https://owasp.org/www-community/attacks/Reverse_Tabnabbing"
primary_identifier: "eslint.react-missing-noopener"
secondary_identifiers:
- name: "ESLint rule ID security/react-missing-noopener"
type: "eslint_rule_id"
value: "security/react-missing-noopener"
languages:
- "typescript"
- "javascript"
severity: "WARNING"
- id: "eslint.react-dangerouslysetinnerhtml"
pattern-either:
- pattern: |
<$X dangerouslySetInnerHTML=... />
- pattern: |
{dangerouslySetInnerHTML: ...}
message: |
Setting HTML from code is risky because it’s easy to inadvertently expose your users to a
cross-site scripting (XSS) attack.
metadata:
cwe: "CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site
Scripting')"
owasp: "A7: Cross-site Scripting (XSS)"
references:
- "https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml"
primary_identifier: "eslint.react-dangerouslysetinnerhtml"
secondary_identifiers:
- name: "ESLint rule ID security/react-dangerouslysetinnerhtml"
type: "eslint_rule_id"
value: "security/react-dangerouslysetinnerhtml"
languages:
- "typescript"
- "javascript"
severity: "WARNING"
eslint.yml lastest analyzer image
# yamllint disable
# rule-set version: v2.0.8
# yamllint enable
---
rules:
- id: "eslint.detect-buffer-noassert"
languages:
- "javascript"
- "typescript"
pattern-either:
- pattern: "$OBJ.readUInt8(..., true)"
- pattern: "$OBJ.readUInt16LE(..., true)"
- pattern: "$OBJ.readUInt16BE(..., true)"
- pattern: "$OBJ.readUInt32LE(..., true)"
- pattern: "$OBJ.readUInt32BE(..., true)"
- pattern: "$OBJ.readInt8(..., true)"
- pattern: "$OBJ.readInt16LE(..., true)"
- pattern: "$OBJ.readInt16BE(..., true)"
- pattern: "$OBJ.readInt32LE(..., true)"
- pattern: "$OBJ.readInt32BE(..., true)"
- pattern: "$OBJ.readFloatLE(..., true)"
- pattern: "$OBJ.readFloatBE(..., true)"
- pattern: "$OBJ.readDoubleLE(..., true)"
- pattern: "$OBJ.readDoubleBE(..., true)"
- pattern: "$OBJ.writeUInt8(..., true)"
- pattern: "$OBJ.writeUInt16LE(..., true)"
- pattern: "$OBJ.writeUInt16BE(..., true)"
- pattern: "$OBJ.writeUInt32LE(..., true)"
- pattern: "$OBJ.writeUInt32BE(..., true)"
- pattern: "$OBJ.writeInt8(..., true)"
- pattern: "$OBJ.writeInt16LE(..., true)"
- pattern: "$OBJ.writeInt16BE(..., true)"
- pattern: "$OBJ.writeInt32LE(..., true)"
- pattern: "$OBJ.writeInt32BE(..., true)"
- pattern: "$OBJ.writeFloatLE(..., true)"
- pattern: "$OBJ.writeFloatBE(..., true)"
- pattern: "$OBJ.writeDoubleLE(..., true)"
- pattern: "$OBJ.writeDoubleBE(..., true)"
severity: "WARNING"
message: |
The application was found using `noAssert` when calling the Buffer API. The `noAssert`
argument has
been deprecated since Node 10. Calling the Buffer API with this argument allows the offset
specified to
be beyond the end of the buffer. This could result in writing or reading beyond the end of the
buffer and
cause a segmentation fault, leading to the application crashing.
To remediate this issue, remove the `true` argument when calling any of the Buffer read or
write methods.
The application should still handle `RangeError` exception cases where the offset is beyond
the end of the
buffer.
Example reading from a Buffer without the `noAssert` argument and gracefully handling errors:
```
// Create a new buffer
const buf = Buffer.from([1, 2, 3, 4]);
try {
// Read a single byte from it, starting at offset 1
const b = buf.readInt8(1);
// Work with b
} catch (e) {
if (e instanceof RangeError) {
console.log('Invalid offset: %s', e.message);
}
// handle other errors
}
```
metadata:
shortDescription: "Improper restriction of operations within the bounds of a memory
buffer"
cwe: "CWE-119"
category: "security"
source-rule-url: "https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-buffer-noassert.js"
primary_identifier: "eslint.detect-buffer-noassert"
secondary_identifiers:
- name: "ESLint rule ID/detect-buffer-noassert"
type: "eslint_rule_id"
value: "detect-buffer-noassert"
- id: "eslint.detect-new-buffer"
languages:
- "javascript"
- "typescript"
patterns:
- patterns:
- pattern-not-inside: |-
require("safe-buffer")
...
- pattern-not-inside: |-
import { Buffer } from "safe-buffer"
...
- pattern-inside: |-
function $FUNC(..., $X, ...) { ... }
- pattern: "new Buffer($X,...)"
- pattern-not: |
new Buffer("...",...)
- pattern-not: |
new Buffer([...] , ...)
message: |
The application was found calling the `new Buffer` constructor which has been deprecated
since Node 8.
By passing in a non-literal value, an adversary could allocate large amounts of memory.
Other issues also exist with the `Buffer` constructor:
- Older versions would return uninitialized memory, which could contain sensitive information
- Unable to easily determine what a Buffer contained if passed a non-literal value
To remediate this issue, use `Buffer.alloc` or `Buffer.from` instead to allocate a new
`Buffer`.
Example using `Buffer.alloc` instead of `new Buffer(...)`:
```
// Create a new buffer using Buffer.from
const buf = Buffer.from([1, 2, 3, 4]);
// Work with buf
```
For more information on migrating to `Buffer.from()`/`Buffer.alloc()` see:
- https://nodejs.org/en/docs/guides/buffer-constructor-deprecation
metadata:
shortDescription: "Allocation of resources without limits or throttling"
cwe: "CWE-770"
category: "security"
source-rule-url: "https://github.com/eslint-community/eslint-plugin-security/blob/main/rules/detect-new-buffer.js"
primary_identifier: "eslint.detect-new-buffer"
secondary_identifiers:
- name: "ESLint rule ID/detect-new-buffer"
type: "eslint_rule_id"
value: "detect-new-buffer"
severity: "WARNING"
- id: "eslint.detect-non-literal-regexp"
languages:
- "javascript"
- "typescript"
message: |
The `RegExp` constructor was called with a non-literal value. If an adversary were able to
supply a malicious regex, they could cause a Regular Expression Denial of Service (ReDoS)
against the application. In Node applications, this could cause the entire application to no
longer
be responsive to other users' requests.
To remediate this issue, never allow user-supplied regular expressions. Instead, the regular
expression should be
hardcoded. If this is not possible, consider using an alternative regular expression engine
such as [node-re2](https://www.npmjs.com/package/re2). RE2 is a safe alternative that does not
support backtracking, which is what leads to ReDoS.
Example using re2 which does not support backtracking (Note: it is still recommended to
never use user-supplied input):
```
// Import the re2 module
const RE2 = require('re2');
function match(userSuppliedRegex, userInput) {
// Create a RE2 object with the user supplied regex, this is relatively safe
// due to RE2 not supporting backtracking which can be abused to cause long running
// queries
var re = new RE2(userSuppliedRegex);
// Execute the regular expression against some userInput
var result = re.exec(userInput);
// Work with the result
}
```
For more information on Regular Expression DoS see:
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
metadata:
cwe: "CWE-185"
shortDescription: "Regular expression with non-literal value"
category: "security"
primary_identifier: "eslint.detect-non-literal-regexp"
secondary_identifiers:
- name: "ESLint rule ID/detect-non-literal-regexp"
type: "eslint_rule_id"
value: "detect-non-literal-regexp"
pattern-either:
- patterns:
- pattern: |
new RegExp(...)
- pattern-not: |
new RegExp("...", ...)
- pattern-not: |
new RegExp(/.../, ...)
- patterns:
- pattern: |
RegExp(...)
- pattern-not: |
RegExp("...", ...)
- pattern-not: |
RegExp(/.../, ...)
severity: "WARNING"
- id: "eslint.detect-eval-with-expression"
languages:
- "javascript"
- "typescript"
patterns:
- pattern: "eval($OBJ)"
- pattern-not: "eval(\"...\")"
severity: "WARNING"
message: |
The application was found calling the `eval` function with a non-literal variable. If the
variable comes from user-supplied input, an adversary could attempt to execute arbitrary
JavaScript
code. This could lead to a full system compromise in Node applications or Cross-site Scripting
(XSS) in web applications.
To remediate this issue, remove all calls to `eval` and consider alternative methods for
executing
the necessary business logic. There is almost no safe method of calling `eval` with
user-supplied input.
Instead, consider alternative methods such as using property accessors to dynamically access
values.
Example using property accessors to dynamically access an object's property:
```
// Define an object
const obj = {key1: 'value1', key2: 'value2'};
// Get key dynamically from user input
const key = getUserInput();
// Check if the key exists in our object and return it, or a default empty string
const value = (obj.hasOwnProperty(key)) ? obj[key] : '';
// Work with the value
```
For more information on why not to use `eval`, and alternatives see:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval#never_use_eval!
metadata:
cwe: "CWE-95"
owasp: "A1:2017-Injection"
shortDescription: "Improper neutralization of directives in dynamically evaluated
code ('Eval Injection')"
category: "security"
source-rule-url: "https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-eval-with-expression.js"
primary_identifier: "eslint.detect-eval-with-expression"
secondary_identifiers:
- name: "ESLint rule ID/detect-eval-with-expression"
type: "eslint_rule_id"
value: "detect-eval-with-expression"
- id: "eslint.detect-child-process"
languages:
- "javascript"
- "typescript"
patterns:
- pattern: "child_process.exec(...)"
- pattern-not: "child_process.exec('...')"
severity: "WARNING"
message: |
OS command injection is a critical vulnerability that can lead to a full system
compromise as it may allow an adversary to pass in arbitrary commands or arguments
to be executed.
User input should never be used in constructing commands or command arguments
to functions which execute OS commands. This includes filenames supplied by
user uploads or downloads.
Ensure your application does not:
- Use user-supplied information in the process name to execute.
- Use user-supplied information in an OS command execution function which does
not escape shell meta-characters.
- Use user-supplied information in arguments to OS commands.
The application should have a hardcoded set of arguments that are to be passed
to OS commands. If filenames are being passed to these functions, it is
recommended that a hash of the filename be used instead, or some other unique
identifier. It is strongly recommended that a native library that implements
the same functionality be used instead of using OS system commands, due to the
risk of unknown attacks against third-party commands.
When specifying the OS command, ensure the application uses the full path
information, otherwise the OS may attempt to look up which process to execute
and could be vulnerable to untrusted search path vulnerabilities (CWE-426).
Example of safely executing an OS command:
```
const child_process = require('child_process');
const fs = require('fs');
const crypto = require('node:crypto');
const { mkdtempSync } = require('node:fs');
function executeCommand(userFileData) {
// Create a temporary directory, preferably in an application directory
// that only the application has access to.
const fileDir = mkdtempSync('/tmp/tmpdir-');
// Generate a random filename, do not use user input
const filePath = fileDir + path.sep + crypto.randomUUID();
// Write the user-supplied data to the temporary file.
fs.writeFileSync(filePath, userFileData);
// Execute a program with a hardcoded path to the binary
child_process.exec(`/bin/cat ${filePath}`, (error, stdout, stderr) => {
// Delete the temporary directory and file if no longer needed
fs.rmSync(fileDir, { recursive: true, force: true });
if (error) {
console.error(`exec error: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
console.error(`stderr: ${stderr}`);
});
}
```
For more information on OS command injection, see OWASP's guide:
https://cheatsheetseries.owasp.org/cheatsheets/OS_Command_Injection_Defense_Cheat_Sheet.html
Detected non-literal calls to child_process.exec(). This could lead to a command
injection vulnerability.
metadata:
cwe: "CWE-95"
owasp: "A1:2017-Injection"
shortDescription: "Improper Neutralization of Directives in Dynamically Evaluated
Code ('Eval Injection')"
category: "security"
source-rule-url: "https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-child-process.js"
primary_identifier: "eslint.detect-child-process"
secondary_identifiers:
- name: "ESLint rule ID/detect-child-process"
type: "eslint_rule_id"
value: "detect-child-process"
- id: "eslint.detect-non-literal-fs-filename"
languages:
- "typescript"
- "javascript"
patterns:
- pattern-either:
- pattern-inside: |
import $MOD from $IMP
...
- pattern-inside: |
$MOD = require($IMP)
...
- metavariable-comparison:
metavariable: "$IMP"
comparison: "$IMP in ['fs', 'node:fs', 'fs/promises', 'node:fs/promises', 'fs-extra']"
- pattern-not: "$MOD.appendFile(\"...\", ...)"
- pattern-not: "$MOD.appendFileSync(\"...\", ...)"
- pattern-not: "$MOD.chmod(\"...\", ...)"
- pattern-not: "$MOD.chmodSync(\"...\", ...)"
- pattern-not: "$MOD.chown(\"...\", ...)"
- pattern-not: "$MOD.chownSync(\"...\", ...)"
- pattern-not: "$MOD.createReadStream(\"...\", ...)"
- pattern-not: "$MOD.createWriteStream(\"...\", ...)"
- pattern-not: "$MOD.exists(\"...\", ...)"
- pattern-not: "$MOD.existsSync(\"...\", ...)"
- pattern-not: "$MOD.lchmod(\"...\", ...)"
- pattern-not: "$MOD.lchmodSync(\"...\", ...)"
- pattern-not: "$MOD.lchown(\"...\", ...)"
- pattern-not: "$MOD.lchownSync(\"...\", ...)"
- pattern-not: "$MOD.link(\"...\", \"...\", ...)"
- pattern-not: "$MOD.linkSync(\"...\", \"...\", ...)"
- pattern-not: "$MOD.lstat(\"...\", ...)"
- pattern-not: "$MOD.lstatSync(\"...\", ...)"
- pattern-not: "$MOD.mkdir(\"...\", ...)"
- pattern-not: "$MOD.mkdirSync(\"...\", ...)"
- pattern-not: "$MOD.open(\"...\", ...)"
- pattern-not: "$MOD.openSync(\"...\", ...)"
- pattern-not: "$MOD.readdir(\"...\", ...)"
- pattern-not: "$MOD.readdirSync(\"...\", ...)"
- pattern-not: "$MOD.readFile(\"...\", ...)"
- pattern-not: "$MOD.readFileSync(\"...\", ...)"
- pattern-not: "$MOD.readlink(\"...\", ...)"
- pattern-not: "$MOD.readlinkSync(\"...\", ...)"
- pattern-not: "$MOD.realpath(\"...\", ...)"
- pattern-not: "$MOD.realpathSync(\"...\", ...)"
- pattern-not: "$MOD.rename(\"...\", \"...\", ...)"
- pattern-not: "$MOD.renameSync(\"...\", \"...\", ...)"
- pattern-not: "$MOD.rmdir(\"...\", ...)"
- pattern-not: "$MOD.rmdirSync(\"...\", ...)"
- pattern-not: "$MOD.stat(\"...\", ...)"
- pattern-not: "$MOD.statSync(\"...\", ...)"
- pattern-not: "$MOD.symlink(\"...\", \"...\", ...)"
- pattern-not: "$MOD.symlinkSync(\"...\", \"...\", ...)"
- pattern-not: "$MOD.truncate(\"...\", ...)"
- pattern-not: "$MOD.truncateSync(\"...\", ...)"
- pattern-not: "$MOD.unlink(\"...\", ...)"
- pattern-not: "$MOD.unlinkSync(\"...\", ...)"
- pattern-not: "$MOD.unwatchFile(\"...\", ...)"
- pattern-not: "$MOD.utimes(\"...\", ...)"
- pattern-not: "$MOD.utimesSync(\"...\", ...)"
- pattern-not: "$MOD.watch(\"...\", ...)"
- pattern-not: "$MOD.watchFile(\"...\", ...)"
- pattern-not: "$MOD.writeFile(\"...\", ...)"
- pattern-not: "$MOD.writeFileSync(\"...\", ...)"
- pattern-either:
- pattern: "$MOD.appendFile(...)"
- pattern: "$MOD.appendFileSync(...)"
- pattern: "$MOD.chmod(...)"
- pattern: "$MOD.chmodSync(...)"
- pattern: "$MOD.chown(...)"
- pattern: "$MOD.chownSync(...)"
- pattern: "$MOD.createReadStream(...)"
- pattern: "$MOD.createWriteStream(...)"
- pattern: "$MOD.exists(...)"
- pattern: "$MOD.existsSync(...)"
- pattern: "$MOD.lchmod(...)"
- pattern: "$MOD.lchmodSync(...)"
- pattern: "$MOD.lchown(...)"
- pattern: "$MOD.lchownSync(...)"
- pattern: "$MOD.link(...)"
- pattern: "$MOD.linkSync(...)"
- pattern: "$MOD.lstat(...)"
- pattern: "$MOD.lstatSync(...)"
- pattern: "$MOD.mkdir(...)"
- pattern: "$MOD.mkdirSync(...)"
- pattern: "$MOD.open(...)"
- pattern: "$MOD.openSync(...)"
- pattern: "$MOD.readdir(...)"
- pattern: "$MOD.readdirSync(...)"
- pattern: "$MOD.readFile(...)"
- pattern: "$MOD.readFileSync(...)"
- pattern: "$MOD.readlink(...)"
- pattern: "$MOD.readlinkSync(...)"
- pattern: "$MOD.realpath(...)"
- pattern: "$MOD.realpathSync(...)"
- pattern: "$MOD.rename(...)"
- pattern: "$MOD.renameSync(...)"
- pattern: "$MOD.rmdir(...)"
- pattern: "$MOD.rmdirSync(...)"
- pattern: "$MOD.stat(...)"
- pattern: "$MOD.statSync(...)"
- pattern: "$MOD.symlink(...)"
- pattern: "$MOD.symlinkSync(...)"
- pattern: "$MOD.truncate(...)"
- pattern: "$MOD.truncateSync(...)"
- pattern: "$MOD.unlink(...)"
- pattern: "$MOD.unlinkSync(...)"
- pattern: "$MOD.unwatchFile(...)"
- pattern: "$MOD.utimes(...)"
- pattern: "$MOD.utimesSync(...)"
- pattern: "$MOD.watch(...)"
- pattern: "$MOD.watchFile(...)"
- pattern: "$MOD.writeFile(...)"
- pattern: "$MOD.writeFileSync(...)"
severity: "WARNING"
message: |
The application dynamically constructs file or path information. If the path
information comes from user-supplied input, it could be abused to read sensitive files,
access other users' data, or aid in exploitation to gain further system access.
User input should never be used in constructing paths or files for interacting
with the filesystem. This includes filenames supplied by user uploads or downloads.
If possible, consider hashing user input or using unique values and
use `path.normalize` to resolve and validate the path information
prior to processing any file functionality.
Example using `path.normalize` and not allowing direct user input:
```
// User input, saved only as a reference
// id is a randomly generated UUID to be used as the filename
const userData = {userFilename: userSuppliedFilename, id: crypto.randomUUID()};
// Restrict all file processing to this directory only
const basePath = '/app/restricted/';
// Create the full path, but only use our random generated id as the filename
const joinedPath = path.join(basePath, userData.id);
// Normalize path, removing any '..'
const fullPath = path.normalize(joinedPath);
// Verify the fullPath is contained within our basePath
if (!fullPath.startsWith(basePath)) {
console.log("Invalid path specified!");
}
// Process / work with file
// ...
```
For more information on path traversal issues see OWASP:
https://owasp.org/www-community/attacks/Path_Traversal
metadata:
cwe: "CWE-22"
shortDescription: "Improper limitation of a pathname to a restricted directory
('Path Traversal')"
category: "security"
primary_identifier: "eslint.detect-non-literal-fs-filename"
secondary_identifiers:
- name: "ESLint rule ID/detect-non-literal-fs-filename"
type: "eslint_rule_id"
value: "detect-non-literal-fs-filename"
- id: "eslint.detect-pseudoRandomBytes"
languages:
- "javascript"
- "typescript"
pattern: "crypto.pseudoRandomBytes"
severity: "WARNING"
message: |
Depending on the context, generating weak random numbers may expose cryptographic functions,
which rely on these numbers, to be exploitable. When generating numbers for sensitive values
such as tokens, nonces, and cryptographic keys, it is recommended that the `randomBytes` method
of the `crypto` module be used instead of `pseudoRandomBytes`.
Example using `randomBytes`:
```
// Generate 256 bytes of random data
const randomBytes = crypto.randomBytes(256);
```
For more information on JavaScript Cryptography see:
https://nodejs.org/api/crypto.html#cryptorandombytessize-callback
metadata:
cwe: "CWE-338"
shortDescription: "Use of cryptographically weak pseudo-random number generator
(PRNG)"
category: "security"
source-rule-url: "https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-pseudoRandomBytes.js"
primary_identifier: "eslint.detect-pseudoRandomBytes"
secondary_identifiers:
- name: "ESLint rule ID/detect-pseudoRandomBytes"
type: "eslint_rule_id"
value: "detect-pseudoRandomBytes"
- id: "eslint.react-dangerouslysetinnerhtml"
languages:
- "typescript"
- "javascript"
pattern-either:
- pattern: |
<$X dangerouslySetInnerHTML=... />
- pattern: |
{dangerouslySetInnerHTML: ...}
severity: "WARNING"
message: |
The application was found calling `dangerouslySetInnerHTML` which may lead to Cross Site
Scripting (XSS). By default, React components will encode the data properly before rendering.
Calling `dangerouslySetInnerHTML` disables this encoding and allows raw markup
and JavaScript to be executed.
XSS is an attack which exploits a web application or system to treat
user input as markup or script code. It is important to encode the data, depending on the
specific context it is used in. There are at least six context types:
- Inside HTML tags `<div>context 1</div>`
- Inside attributes: `<div class="context 2"></div>`
- Inside event attributes `<button onclick="context 3">button</button>`
- Inside script blocks: `<script>var x = "context 4"</script>`
- Unsafe element HTML assignment: `element.innerHTML = "context 5"`
- Inside URLs: `<iframe src="context 6"></iframe><a href="context 6">link</a>`
Script blocks alone have multiple ways they need to be encoded. Extra care must be taken if
user input
is ever output inside of script tags.
User input that is displayed within the application must be encoded, sanitized or validated
to ensure it cannot be treated as HTML or executed as Javascript code. Care must also be
taken
to not mix server-side templating with client-side templating, as the server-side templating
will
not encode things like {{ 7*7 }} which may execute client-side templating features.
It is _NOT_ advised to encode user input prior to inserting into a data store. The data will
need to be
encoded depending on context of where it is output. It is much safer to force the displaying
system to
handle the encoding and not attempt to guess how it should be encoded.
Remove the call to `dangerouslySetInnerHTML` or ensure that the data used in this call does
not come from user-supplied input.
For more information on dangerously setting inner HTML see:
- https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html
metadata:
cwe: "CWE-79"
owasp: "A7:2017-Cross-Site Scripting (XSS)"
shortDescription: "Improper neutralization of input during web page generation
('Cross-site Scripting')"
category: "security"
primary_identifier: "eslint.react-dangerouslysetinnerhtml"
secondary_identifiers:
- name: "ESLint rule ID/react-dangerouslysetinnerhtml"
type: "eslint_rule_id"
value: "react-dangerouslysetinnerhtml"
- id: "eslint.detect-non-literal-require"
languages:
- "javascript"
- "typescript"
patterns:
- pattern: "require($OBJ)"
- pattern-not: "require('...')"
severity: "WARNING"
message: |
The application was found to dynamically import a module by calling `require` using a
non-literal string. An adversary might be able to read the first line of
arbitrary files. If they had write access to the file system, they may also be able to
execute arbitrary code.
To remediate this issue, use a hardcoded string literal when calling `require`. Never call it
it with dynamically created variables or user-supplied data.
metadata:
cwe: "CWE-95"
owasp: "A1:2017-Injection"
shortDescription: "Improper neutralization of directives in dynamically evaluated
code ('Eval Injection')"
category: "security"
source-rule-url: "https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-non-literal-require.js"
primary_identifier: "eslint.detect-non-literal-require"
secondary_identifiers:
- name: "ESLint rule ID/detect-non-literal-require"
type: "eslint_rule_id"
value: "detect-non-literal-require"
- id: "eslint.detect-possible-timing-attacks"
languages:
- "javascript"
patterns:
- pattern-not: "if ($Z == null) { ... };"
- pattern-not: "if ($Z === null) { ... };"
- pattern-not: "if ($Z != null) { ... };"
- pattern-not: "if ($Z !== null) { ... };"
- pattern-not: "if ($Q != undefined) { ... };"
- pattern-not: "if ($Q !== undefined) { ... };"
- pattern-not: "if ($Q == undefined) { ... };"
- pattern-not: "if ($Q === undefined) { ... };"
- pattern-not: "return $Y == null;"
- pattern-not: "return $Y === null;"
- pattern-not: "return $Y != null;"
- pattern-not: "return $Y !== null;"
- pattern-not: "return $Y == undefined;"
- pattern-not: "return $Y === undefined;"
- pattern-not: "return $Y != undefined;"
- pattern-not: "return $Y !== undefined;"
- pattern-either:
- pattern: |
if (password == $X) {
...
}
- pattern: |
if ($X == password) {
...
}
- pattern: |
if (password === $X) {
...
}
- pattern: |
if ($X === password) {
...
}
- pattern: |
if (pass == $X) {
...
}
- pattern: |
if ($X == pass) {
...
}
- pattern: |
if (pass === $X) {
...
}
- pattern: |
if ($X === pass) {
...
}
- pattern: |
if (secret == $X) {
...
}
- pattern: |
if ($X == secret) {
...
}
- pattern: |
if (secret === $X) {
...
}
- pattern: |
if ($X === secret) {
...
}
- pattern: |
if (api == $X) {
...
}
- pattern: |
if ($X == api) {
...
}
- pattern: |
if (api === $X) {
...
}
- pattern: |
if ($X === api) {
...
}
- pattern: |
if (apiKey == $X) {
...
}
- pattern: |
if ($X == apiKey) {
...
}
- pattern: |
if (apiKey === $X) {
...
}
- pattern: |
if ($X === apiKey) {
...
}
- pattern: |
if (apiSecret == $X) {
...
}
- pattern: |
if ($X == apiSecret) {
...
}
- pattern: |
if (apiSecret === $X) {
...
}
- pattern: |
if ($X === apiSecret) {
...
}
- pattern: |
if (token == $X) {
...
}
- pattern: |
if ($X == token) {
...
}
- pattern: |
if (token === $X) {
...
}
- pattern: |
if ($X === token) {
...
}
- pattern: |
if (hash == $X) {
...
}
- pattern: |
if ($X == hash) {
...
}
- pattern: |
if (hash === $X) {
...
}
- pattern: |
if ($X === hash) {
...
}
- pattern: |
if (auth_token == $X) {
...
}
- pattern: |
if ($X == auth_token) {
...
}
- pattern: |
if (auth_token === $X) {
...
}
- pattern: |
if ($X === auth_token) {
...
}
- pattern: |
if (password != $X) {
...
}
- pattern: |
if ($X != password) {
...
}
- pattern: |
if (password !== $X) {
...
}
- pattern: |
if ($X !== password) {
...
}
- pattern: |
if (pass != $X) {
...
}
- pattern: |
if ($X != pass) {
...
}
- pattern: |
if (pass !== $X) {
...
}
- pattern: |
if ($X !== pass) {
...
}
- pattern: |
if (secret != $X) {
...
}
- pattern: |
if ($X != secret) {
...
}
- pattern: |
if (secret !== $X) {
...
}
- pattern: |
if ($X !== secret) {
...
}
- pattern: |
if (api != $X) {
...
}
- pattern: |
if ($X != api) {
...
}
- pattern: |
if (api !== $X) {
...
}
- pattern: |
if ($X !== api) {
...
}
- pattern: |
if (apiKey != $X) {
...
}
- pattern: |
if ($X != apiKey) {
...
}
- pattern: |
if (apiKey !== $X) {
...
}
- pattern: |
if ($X !== apiKey) {
...
}
- pattern: |
if (apiSecret != $X) {
...
}
- pattern: |
if ($X != apiSecret) {
...
}
- pattern: |
if (apiSecret !== $X) {
...
}
- pattern: |
if ($X !== apiSecret) {
...
}
- pattern: |
if (token != $X) {
...
}
- pattern: |
if ($X != token) {
...
}
- pattern: |
if (token !== $X) {
...
}
- pattern: |
if ($X !== token) {
...
}
- pattern: |
if (hash != $X) {
...
}
- pattern: |
if ($X != hash) {
...
}
- pattern: |
if (hash !== $X) {
...
}
- pattern: |
if ($X !== hash) {
...
}
- pattern: |
if (auth_token != $X) {
...
}
- pattern: |
if ($X != auth_token) {
...
}
- pattern: |
if (auth_token !== $X) {
...
}
- pattern: |
if ($X !== auth_token) {
...
}
- pattern: |
return $X === auth_token;
- pattern: |
return auth_token === $X;
- pattern: |
return $X === token;
- pattern: |
return token === $X;
- pattern: |
return $X === hash;
- pattern: |
return hash === $X;
- pattern: |
return $X === password;
- pattern: |
return password === $X;
- pattern: |
return $X === pass;
- pattern: |
return pass === $X;
- pattern: |
return $X === apiKey;
- pattern: |
return apiKey === $X;
- pattern: |
return $X === apiSecret;
- pattern: |
return apiSecret === $X;
- pattern: |
return $X === api_key;
- pattern: |
return api_key === $X;
- pattern: |
return $X === api_secret;
- pattern: |
return api_secret === $X;
- pattern: |
return $X === secret;
- pattern: |
return secret === $X;
- pattern: |
return $X === api;
- pattern: |
return api === $X;
- pattern: |
return $X == auth_token;
- pattern: |
return auth_token == $X;
- pattern: |
return $X == token;
- pattern: |
return token == $X;
- pattern: |
return $X == hash;
- pattern: |
return hash == $X;
- pattern: |
return $X == password;
- pattern: |
return password == $X;
- pattern: |
return $X == pass;
- pattern: |
return pass == $X;
- pattern: |
return $X == apiKey;
- pattern: |
return apiKey == $X;
- pattern: |
return $X == apiSecret;
- pattern: |
return apiSecret == $X;
- pattern: |
return $X == api_key;
- pattern: |
return api_key == $X;
- pattern: |
return $X == api_secret;
- pattern: |
return api_secret == $X;
- pattern: |
return $X == secret;
- pattern: |
return secret == $X;
- pattern: |
return $X == api;
- pattern: |
return api == $X;
- pattern: |
return $X !== auth_token;
- pattern: |
return auth_token !== $X;
- pattern: |
return $X !== token;
- pattern: |
return token !== $X;
- pattern: |
return $X !== hash;
- pattern: |
return hash !== $X;
- pattern: |
return $X !== password;
- pattern: |
return password !== $X;
- pattern: |
return $X !== pass;
- pattern: |
return pass !== $X;
- pattern: |
return $X !== apiKey;
- pattern: |
return apiKey !== $X;
- pattern: |
return $X !== apiSecret;
- pattern: |
return apiSecret !== $X;
- pattern: |
return $X !== api_key;
- pattern: |
return api_key !== $X;
- pattern: |
return $X !== api_secret;
- pattern: |
return api_secret !== $X;
- pattern: |
return $X !== secret;
- pattern: |
return secret !== $X;
- pattern: |
return $X !== api;
- pattern: |
return api !== $X;
- pattern: |
return $X != auth_token;
- pattern: |
return auth_token != $X;
- pattern: |
return $X != token;
- pattern: |
return token != $X;
- pattern: |
return $X != hash;
- pattern: |
return hash != $X;
- pattern: |
return $X != password;
- pattern: |
return password != $X;
- pattern: |
return $X != pass;
- pattern: |
return pass != $X;
- pattern: |
return $X != apiKey;
- pattern: |
return apiKey != $X;
- pattern: |
return $X != apiSecret;
- pattern: |
return apiSecret != $X;
- pattern: |
return $X != api_key;
- pattern: |
return api_key != $X;
- pattern: |
return $X != api_secret;
- pattern: |
return api_secret != $X;
- pattern: |
return $X != secret;
- pattern: |
return secret != $X;
- pattern: |
return $X != api;
- pattern: |
return api != $X;
severity: "WARNING"
message: |
The application was found executing string comparisons using one of `===`, `!==`, `==` or `!=`
against security sensitive values. String comparisons like this are not constant time, meaning
the
first character found not to match in the two strings will immediately exit the conditional
statement.
This allows an adversary to calculate or observe small timing differences depending on the
strings
passed to this comparison. This potentially allows an adversary the ability to brute force a
string
that will match the expected value by monitoring different character values.
To remediate this issue, use the `crypto.timingSafeEqual` method when comparing strings.
Example using `crypto.timingSafeEqual` to safely compare strings:
```
function constantTimeIsPasswordEqual(userInput) {
// Retrieve the password from a secure data store such as a KMS or Hashicorp's vault.
const password = getPasswordFromSecureDataStore();
// Use crypto timingSafeEqual to ensure the comparison is done in constant time.
return crypto.timingSafeEqual(Buffer.from(userInput, 'utf-8'), Buffer.from(password,
'utf-8'));
}
```
For more information on constant time comparison see:
- https://nodejs.org/api/crypto.html#crypto_crypto_timingsafeequal_a_b
metadata:
cwe: "CWE-208"
shortDescription: "Observable timing discrepancy"
category: "security"
primary_identifier: "eslint.detect-possible-timing-attacks"
secondary_identifiers:
- name: "ESLint rule ID/detect-possible-timing-attacks"
type: "eslint_rule_id"
value: "detect-possible-timing-attacks"
- id: "eslint.detect-disable-mustache-escape"
languages:
- "javascript"
- "typescript"
pattern: "$OBJ.escapeMarkup = false"
severity: "WARNING"
message: |
Markup escaping disabled. This can be used with some template engines to escape
disabling of HTML entities, which can lead to XSS attacks.
metadata:
cwe: "CWE-79"
owasp: "A7:2017-Cross-Site Scripting (XSS)"
category: "security"
shortDescription: "Improper neutralization of input during web page generation
(XSS)"
source-rule-url: "https://github.com/nodesecurity/eslint-plugin-security/blob/master/rules/detect-disable-mustache-escape.js"
primary_identifier: "eslint.detect-disable-mustache-escape"
secondary_identifiers:
- name: "ESLint rule ID/detect-disable-mustache-escape"
type: "eslint_rule_id"
value: "detect-disable-mustache-escape"
Output of checks
Results of GitLab environment info
Expand for output related to GitLab environment info
(For installations with omnibus-gitlab package run and paste the output of: `sudo gitlab-rake gitlab:env:info`) (For installations from source run and paste the output of: `sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
Results of GitLab application Check
Expand for output related to the GitLab application check
(For installations with omnibus-gitlab package run and paste the output of:
sudo gitlab-rake gitlab:check SANITIZE=true
)(For installations from source run and paste the output of:
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true
)(we will only investigate if the tests are passing)
Possible fixes
Edited by Tal Kopel