javascript.express.security.express-vm2-injection.express-vm2-context-injection

profile photo of returntocorpreturntocorp
Author
5,905
Download Count*

Make sure that unverified user data can not reach vm2.

Run Locally

Run in CI

Defintion

rules:
  - id: express-vm2-context-injection
    message: |
      Make sure that unverified user data can not reach `vm2`.
    severity: ERROR
    languages:
      - javascript
      - typescript
    metadata:
      owasp: "A1: Injection"
      cwe: "CWE-94: Improper Control of Generation of Code (Code Injection)"
      category: security
      technology:
        - express
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
    patterns:
      - pattern-inside: |
          require('vm2');
          ...
      - pattern-either:
          - pattern-inside: function ... ($REQ, $RES) {...}
          - pattern-inside: function ... ($REQ, $RES, $NEXT) {...}
          - pattern-inside: $APP.get(..., function $FUNC($REQ, $RES) {...})
          - pattern-inside: $APP.post(..., function $FUNC($REQ, $RES) {...})
          - pattern-inside: $APP.put(..., function $FUNC($REQ, $RES) {...})
          - pattern-inside: $APP.head(..., function $FUNC($REQ, $RES) {...})
          - pattern-inside: $APP.delete(..., function $FUNC($REQ, $RES) {...})
          - pattern-inside: $APP.options(..., function $FUNC($REQ, $RES) {...})
      - pattern-either:
          - pattern: |
              new VM({sandbox: <... $REQ.$QUERY.$FOO ...>},...);
          - pattern: |
              $CONTEXT = <... $REQ.$QUERY.$FOO ...>;
              ...
              new VM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $CONTEXT = <... {$NAME:$REQ.$QUERY.$FOO} ...>;
              ...
              new VM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $CONTEXT = {$NAME: <... $REQ.$QUERY.$FOO ...>};
              ...
              new VM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $VAR = <... $REQ.$QUERY.$FOO ...>;
              ...
              $CONTEXT = {$NAME: <... $VAR ...>};
              ...
              new VM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $OPTS = {sandbox: <... $REQ.$QUERY.$FOO ...>};
              ...
              new VM($OPTS,...);
          - pattern: |
              $CONTEXT = <... $REQ.$QUERY.$FOO ...>;
              ...
              $OPTS = {sandbox: <... $CONTEXT ...>};
              ...
              new VM($OPTS,...);
          - pattern: |
              $CONTEXT = {$NAME: <... $REQ.$QUERY.$FOO ...>};
              ...
              $OPTS = {sandbox: <... $CONTEXT ...>};
              ...
              new VM($OPTS,...);
          - pattern: |
              $VAR = <... $REQ.$QUERY.$FOO ...>;
              ...
              $CONTEXT = {$NAME: <... $VAR ...>};
              ...
              $OPTS = {sandbox: <... $CONTEXT ...>};
              ...
              new VM($OPTS,...);
          - pattern: |
              new NodeVM({sandbox: <... $REQ.$QUERY.$FOO ...>},...);
          - pattern: |
              $CONTEXT = <... $REQ.$QUERY.$FOO ...>;
              ...
              new NodeVM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $CONTEXT = <... {$NAME:$REQ.$QUERY.$FOO} ...>;
              ...
              new NodeVM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $CONTEXT = {$NAME: <... $REQ.$QUERY.$FOO ...>};
              ...
              new NodeVM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $VAR = <... $REQ.$QUERY.$FOO ...>;
              ...
              $CONTEXT = {$NAME: <... $VAR ...>};
              ...
              new NodeVM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $OPTS = {sandbox: <... $REQ.$QUERY.$FOO ...>};
              ...
              new NodeVM($OPTS,...);
          - pattern: |
              $CONTEXT = <... $REQ.$QUERY.$FOO ...>;
              ...
              $OPTS = {sandbox: <... $CONTEXT ...>};
              ...
              new NodeVM($OPTS,...);
          - pattern: |
              $CONTEXT = {$NAME: <... $REQ.$QUERY.$FOO ...>};
              ...
              $OPTS = {sandbox: <... $CONTEXT ...>};
              ...
              new NodeVM($OPTS,...);
          - pattern: |
              $VAR = <... $REQ.$QUERY.$FOO ...>;
              ...
              $CONTEXT = {$NAME: <... $VAR ...>};
              ...
              $OPTS = {sandbox: <... $CONTEXT ...>};
              ...
              new NodeVM($OPTS,...);
          - pattern: |
              new VM({sandbox: <... $REQ.$BODY ...>},...);
          - pattern: |
              $CONTEXT = <... $REQ.$BODY ...>;
              ...
              new VM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $CONTEXT = <... {$NAME:$REQ.$BODY} ...>;
              ...
              new VM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $CONTEXT = {$NAME: <... $REQ.$BODY ...>};
              ...
              new VM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $VAR = <... $REQ.$BODY ...>;
              ...
              $CONTEXT = {$NAME: <... $VAR ...>};
              ...
              new VM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $OPTS = {sandbox: <... $REQ.$BODY ...>};
              ...
              new VM($OPTS,...);
          - pattern: |
              $CONTEXT = <... $REQ.$BODY ...>;
              ...
              $OPTS = {sandbox: <... $CONTEXT ...>};
              ...
              new VM($OPTS,...);
          - pattern: |
              $CONTEXT = {$NAME: <... $REQ.$BODY ...>};
              ...
              $OPTS = {sandbox: <... $CONTEXT ...>};
              ...
              new VM($OPTS,...);
          - pattern: |
              $VAR = <... $REQ.$BODY ...>;
              ...
              $CONTEXT = {$NAME: <... $VAR ...>};
              ...
              $OPTS = {sandbox: <... $CONTEXT ...>};
              ...
              new VM($OPTS,...);
          - pattern: |
              new NodeVM({sandbox: <... $REQ.$BODY ...>},...);
          - pattern: |
              $CONTEXT = <... $REQ.$BODY ...>;
              ...
              new NodeVM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $CONTEXT = <... {$NAME:$REQ.$BODY} ...>;
              ...
              new NodeVM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $CONTEXT = {$NAME: <... $REQ.$BODY ...>};
              ...
              new NodeVM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $VAR = <... $REQ.$BODY ...>;
              ...
              $CONTEXT = {$NAME: <... $VAR ...>};
              ...
              new NodeVM({sandbox: <... $CONTEXT ...>},...);
          - pattern: |
              $OPTS = {sandbox: <... $REQ.$BODY ...>};
              ...
              new NodeVM($OPTS,...);
          - pattern: |
              $CONTEXT = <... $REQ.$BODY ...>;
              ...
              $OPTS = {sandbox: <... $CONTEXT ...>};
              ...
              new NodeVM($OPTS,...);
          - pattern: |
              $CONTEXT = {$NAME: <... $REQ.$BODY ...>};
              ...
              $OPTS = {sandbox: <... $CONTEXT ...>};
              ...
              new NodeVM($OPTS,...);
          - pattern: |-
              $VAR = <... $REQ.$BODY ...>;
              ...
              $CONTEXT = {$NAME: <... $VAR ...>};
              ...
              $OPTS = {sandbox: <... $CONTEXT ...>};
              ...
              new NodeVM($OPTS,...);

Examples

express-vm2-injection.js

const fs = require('fs');
const {VM, NodeVM} = require('vm2');
const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => res.send('Hello World!'))

app.get('/test1', (req, res) => {
  // ruleid:express-vm2-code-injection
  code = `
    console.log(${req.query.input})
  `;

  const sandbox = {
    setTimeout,
    fs: {
      watch: fs.watch
    }
  };

  new VM({
    timeout: 40 * 1000,
    sandbox
  }).run(code);

  res.send('hello world');
})

app.get('/test2', function (req, res) {
  const sandbox = {
    setTimeout,
    fs: {
      watch: fs.watch
    }
  };

  // ruleid:express-vm2-code-injection
  const nodeVM = new NodeVM({timeout: 40 * 1000, sandbox});
  nodeVM.run('console.log(' + req.query.input + ')')

  res.send('hello world');
})

app.get('/test3', function (req, res) {
  const sandbox = {
    setTimeout,
    fs: {
      watch: fs.watch
    }
  };

  // ruleid:express-vm2-code-injection
  const nodeVM = new NodeVM({timeout: 40 * 1000, sandbox});
  const script = new VMScript(`console.log(${req.query.input})`)
  nodeVM.run(script)

  res.send('hello world')
})

app.get('/ok-test1', async function (req, res) {
  code = `
    console.log("Hello world")
  `;

  const sandbox = {
    setTimeout,
    fs: {
      watch: fs.watch
    }
  };

  const vmResult = new VM({
    timeout: 40 * 1000,
    sandbox
  }).run(code);

  res.send('hello world');
})

app.get('/ok-test2', function (req, res) {
  const sandbox = {
    setTimeout,
    fs: {
      watch: fs.watch
    }
  };

  const nodeVM = new NodeVM({timeout: 40 * 1000, sandbox});
  nodeVM.run('console.log("Hello world")')

  res.send('hello world');
})

app.get('/ok-test3', function (req, res) {
  const sandbox = {
    setTimeout,
    fs: {
      watch: fs.watch
    }
  };

  const nodeVM = new NodeVM({timeout: 40 * 1000, sandbox});
  const script = new VMScript('console.log("Hello world")')
  nodeVM.run(script)

  res.send('hello world');
})


app.get('/test4', async function test1(req, res) {
  code = `
    console.log("Hello world")
  `;

  // ruleid:express-vm2-context-injection
  const sandbox = {
    setTimeout,
    watch: req.query.input
  };

  return new VM({timeout: 40 * 1000, sandbox}).run(code);
})

app.post('/test5', function test2(req, res) {
  // ruleid:express-vm2-context-injection
  const sandbox = {
    setTimeout,
    input: req.body
  };

  const nodeVM = new NodeVM({timeout: 40 * 1000, sandbox});
  return nodeVM.run('console.log("Hello world")')
})

// ok:express-vm2-context-injection
app.get('/ok-test4', async function okTest1() {
  code = `
    console.log("Hello world")
  `;

  const sandbox = {
    setTimeout,
    fs
  };

  return new VM({timeout: 40 * 1000, sandbox}).run(code);
})

// ok:express-vm2-context-injection
app.get('/ok-test5', function okTest2() {
  const sandbox = {
    setTimeout,
    fs
  };

  const nodeVM = new NodeVM({timeout: 40 * 1000, sandbox});
  return nodeVM.run('console.log("Hello world")')
})

app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))