Skip to main content

Code injection prevention for JavaScript

This is a code injection prevention cheat sheet by Semgrep, Inc. It contains code patterns of potential ways to run arbitrary code in an application. Instead of scrutinizing code for exploitable vulnerabilities, the recommendations in this cheat sheet pave a safe road for developers that mitigate the possibility of code injection in your code. By following these recommendations, you can be reasonably sure your code is free of code injection.

Check your project using Semgrep

The following command runs an optimized set of rules for your project:

semgrep --config p/default

1. Executing or evaluating code

1.A. running code with VM module

The vm module enables compiling and running code within V8 Virtual Machine contexts. The vm module is not secure. Do not use it to run untrusted code. If user input is used as a part of the code passed to vm functions, it can result in code injection. See VM (executing JavaScript) documentation.

The following list documents all potentially vulnerable functions that compile and execute code from the vm module:

  • vm.runInContext
  • vm.runInNewContext
  • vm.runInThisContext
  • vm.compileFunction
  • new vm.Script
  • new vm.SourceTextModule

Example:

const vm = require('vm');
const contextObject = { globalVar: 1 };

// safe
vm.runInContext('globalVar *= 2;', contextObject);

// vulnerable
let userInput = 'this.constructor.constructor("return process.env")()'; // Value supplied by user input
vm.runInContext(`globalVar = ${userInput};`, contextObject);

// safe
const code = `return 'hello ' + name`
vm.compileFunction(code, [], { parsingContext: vm.createContext({ name: 'name' }) })

// vulnerable
let userInput = '1; while (true)

References

Mitigation

  • Don't use the vm module for running untrusted code.
  • If you need to use functions of the vm module with non-literal values, ensure that the executed content cannot be controlled by external sources.
  • If it's not possible, strip everything except alphanumeric characters from the input.

Semgrep rule

javascript.lang.security.audit.vm-injection.vm-runincontext-context-injection

1.B. eval or new Function

The eval() or new Function() function evaluates JavaScript code represented as a string. Executing JavaScript from a string is an enormous security risk. It is far too easy for a bad actor to run arbitrary code when you use eval() or new Function().

Example:

const userInput = "1;require('child_process').exec('cat /etc/passwd')"
eval(`var x = ${userInput}`)

const userInput = "require('child_process').exec('cat /etc/passwd') && console.log"
var x = new Function(`return ${userInput}(a,b)`)

References

Mitigation

  • Don't use eval() or new Function() if possible.
  • If you need to use eval() or new Function() with non-literal values, ensure that the executed content cannot be controlled by external sources.
  • If it's not possible, strip everything except alphanumeric characters from the input.

Semgrep rule

javascript.lang.security.detect-eval-with-expression.detect-eval-with-expression