javascript.lang.security.audit.code-string-concat.code-string-concat

profile photo of semgrepsemgrep
Author
742
Download Count*

Found data from an Express or Next web request flowing to eval. If this data is user-controllable this can lead to execution of arbitrary system commands in the context of your application process. Avoid eval whenever possible.

Run Locally

Run in CI

Defintion

rules:
  - id: code-string-concat
    message: Found data from an Express or Next web request flowing to `eval`. If
      this data is user-controllable this can lead to execution of arbitrary
      system commands in the context of your application process. Avoid `eval`
      whenever possible.
    options:
      interfile: true
    metadata:
      interfile: true
      confidence: HIGH
      owasp:
        - A03:2021 - Injection
      cwe:
        - "CWE-95: Improper Neutralization of Directives in Dynamically
          Evaluated Code ('Eval Injection')"
      references:
        - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
        - https://nodejs.org/api/child_process.html#child_processexeccommand-options-callback
        - https://www.stackhawk.com/blog/nodejs-command-injection-examples-and-prevention/
        - https://ckarande.gitbooks.io/owasp-nodegoat-tutorial/content/tutorial/a1_-_server_side_js_injection.html
      category: security
      technology:
        - node.js
        - Express
        - Next.js
      subcategory:
        - vuln
      likelihood: MEDIUM
      impact: MEDIUM
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Code Injection
    languages:
      - javascript
      - typescript
    severity: ERROR
    mode: taint
    pattern-sources:
      - pattern-either:
          - patterns:
              - pattern-either:
                  - pattern-inside: function ... ($REQ, $RES) {...}
                  - pattern-inside: function ... ($REQ, $RES, $NEXT) {...}
                  - patterns:
                      - pattern-either:
                          - pattern-inside: $APP.$METHOD(..., function $FUNC($REQ, $RES) {...})
                          - pattern-inside: $APP.$METHOD(..., function $FUNC($REQ, $RES, $NEXT) {...})
                      - metavariable-regex:
                          metavariable: $METHOD
                          regex: ^(get|post|put|head|delete|options)$
              - pattern-either:
                  - pattern: $REQ.query
                  - pattern: $REQ.body
                  - pattern: $REQ.params
                  - pattern: $REQ.cookies
                  - pattern: $REQ.headers
          - patterns:
              - pattern-either:
                  - pattern-inside: |
                      import { ...,$IMPORT,... } from 'next/router'
                      ...
                  - pattern-inside: |
                      import $IMPORT from 'next/router';
                      ...
              - pattern-either:
                  - patterns:
                      - pattern-inside: |
                          $ROUTER = $IMPORT()
                          ...
                      - pattern-either:
                          - pattern-inside: |
                              const { ...,$PROPS,... } = $ROUTER.query
                              ...
                          - pattern-inside: |
                              var { ...,$PROPS,... } = $ROUTER.query
                              ...
                          - pattern-inside: |
                              let { ...,$PROPS,... } = $ROUTER.query
                              ...
                      - focus-metavariable: $PROPS
                  - patterns:
                      - pattern-inside: |
                          $ROUTER = $IMPORT()
                          ...
                      - pattern: |
                          $ROUTER.query.$VALUE 
                  - patterns:
                      - pattern: $IMPORT().query.$VALUE
    pattern-sinks:
      - patterns:
          - pattern: |
              eval(...)

Examples

code-string-concat.js

function test1(req,res) {
  const data = JSON.stringify(req.query.key);
  const command = `(secret) => {${data}}`
  // ruleid:code-string-concat
  return eval(command)
}

test2.post(foo, bar, function (req,res) {
  userInput = req.params.input
  var command = "new Function('"+userInput+"')";
  // ruleid:code-string-concat
  return eval(command)
});

function ok1(req,res) {
  var command = "eval('123')";
  // ok:code-string-concat
  return eval(command)
}