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

    Not finding what you need in this doc? Ask questions in our Community Slack group, or see Support for other ways to get help.