javascript.lang.security.audit.unsafe-dynamic-method.unsafe-dynamic-method

profile photo of semgrepsemgrep
Author
328
Download Count*

Using non-static data to retrieve and run functions from the object is dangerous. If the data is user-controlled, it may allow executing arbitrary code.

Run Locally

Run in CI

Defintion

rules:
  - id: unsafe-dynamic-method
    message: Using non-static data to retrieve and run functions from the object is
      dangerous. If the data is user-controlled, it may allow executing
      arbitrary code.
    metadata:
      owasp:
        - A03:2021 - Injection
      cwe:
        - "CWE-94: Improper Control of Generation of Code ('Code Injection')"
      category: security
      technology:
        - javascript
      cwe2022-top25: true
      subcategory:
        - audit
      likelihood: LOW
      impact: LOW
      confidence: LOW
      references:
        - https://owasp.org/Top10/A03_2021-Injection
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Code Injection
    languages:
      - javascript
      - typescript
    severity: WARNING
    patterns:
      - pattern-either:
          - pattern: $OBJ[$X](...)
          - pattern: |
              $Y = $OBJ[$X]
              ...
              $Y(...)
      - metavariable-pattern:
          patterns:
            - pattern-not: |
                "..."
            - pattern-not: |
                ($X: float)
          metavariable: $X
      - pattern-not-inside: |
          for (...) {...}
      - pattern-not-inside: |
          $SMTH.forEach(...)
      - pattern-not-inside: |
          $SMTH.map(...)
      - pattern-not-inside: |
          $SMTH.reduce(...)
      - pattern-not-inside: |
          $SMTH.reduceRight(...)
      - pattern-not-inside: |
          if (<... $OBJ.hasOwnProperty(...) ...>) {
            ...
          }
          ...

Examples

unsafe-dynamic-method.js

function test1(data) {
  const message = JSON.parse(data);
  // ruleid:unsafe-dynamic-method
  window[message.name](message.payload);
}

function test2(data) {
  const message = JSON.parse(data);
  // ruleid:unsafe-dynamic-method
  const action = window[message.name];
  action(message.payload);
}

let api = {
  foo: function () { /* do smth */ },
  bar: function () { /* do smth */ }
}

function okTest1(data) {
  const message = JSON.parse(data);
  if (!api.hasOwnProperty(message.name)) {
    return;
  }
  // ok:unsafe-dynamic-method
  api[message.name](message.payload);
}

function okTest2(data) {
  // ok:unsafe-dynamic-method
  const result = api["foo"](data);
  console.log(result);
}

function okTest3(data) {
  // ok:unsafe-dynamic-method
  const result = actions[1](data);
  console.log(result);
}

function okTest4(data) {
  const actions = api = {
    foo: function () { /* do smth */ },
    bar: function () { /* do smth */ }
  }
  let result = null
  Object.keys(actions).forEach(a => {
    // ok:unsafe-dynamic-method
    result = actions[a](result);
  })
  console.log(result);
}