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-injection1.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
- Never use eval() in MDN Web Docs documentation.
Mitigation
- Don't use
eval()
ornew Function()
if possible. - If you need to use
eval()
ornew 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-expressionNot finding what you need in this doc? Ask questions in our Community Slack group, or see Support for other ways to get help.