Skip to content

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

  1. Run semgrep job in a project with cwe-94 vulnerability
  2. Observe the pipeline security report doesn't dectect cwe-94
  3. 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