javascript.express.security.express-vm-injection.express-vm-injection

Author
442
Download Count*
License
Make sure that unverified user data can not reach $VM
.
Run Locally
Run in CI
Defintion
rules:
- id: express-vm-injection
message: Make sure that unverified user data can not reach `$VM`.
metadata:
owasp:
- A03:2021 - Injection
references:
- https://cheatsheetseries.owasp.org/cheatsheets/Injection_Prevention_Cheat_Sheet.html
cwe:
- "CWE-94: Improper Control of Generation of Code ('Code Injection')"
category: security
technology:
- express
cwe2022-top25: true
subcategory:
- vuln
likelihood: MEDIUM
impact: MEDIUM
confidence: MEDIUM
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
languages:
- javascript
- typescript
severity: ERROR
mode: taint
pattern-sources:
- patterns:
- pattern-either:
- pattern-inside: function ... ($REQ, $RES) {...}
- pattern-inside: function ... ($REQ, $RES, $NEXT) {...}
- patterns:
- pattern-either:
- pattern-inside: $APP.$METHOD(..., function $FUNC($REQ, $RES) {...})
- pattern-inside: $APP.$METHOD(..., function $FUNC($REQ, $RES, $NEXT) {...})
- metavariable-regex:
metavariable: $METHOD
regex: ^(get|post|put|head|delete|options)$
- pattern-either:
- pattern: $REQ.query
- pattern: $REQ.body
- pattern: $REQ.params
- pattern: $REQ.cookies
- pattern: $REQ.headers
- patterns:
- pattern-either:
- pattern-inside: |
({ $REQ }: Request,$RES: Response, $NEXT: NextFunction) =>
{...}
- pattern-inside: |
({ $REQ }: Request,$RES: Response) => {...}
- focus-metavariable: $REQ
- pattern-either:
- pattern: params
- pattern: query
- pattern: cookies
- pattern: headers
- pattern: body
pattern-sinks:
- patterns:
- pattern-inside: |
$VM = require('vm');
...
- pattern-either:
- pattern: |
$VM.runInContext(...)
- pattern: |
$VM.runInNewContext(...)
- pattern: |
$VM.compileFunction(...)
- pattern: |
$VM.runInThisContext(...)
- pattern: new $VM.Script(...)
Examples
express-vm-injection.js
const vm = require('vm')
let ctrl1 = function test1(req,res) {
var input = req.query.something || ''
var sandbox = {
foo: input
}
vm.createContext(sandbox)
// ruleid:express-vm-injection
vm.runInContext('safeEval(orderLinesData)', sandbox, { timeout: 2000 })
res.send('hello world')
}
app.get('/', ctrl1)
app.get('/', (req,res) => {
var sandbox = {
foo: req.query.userInput
}
vm.createContext(sandbox)
// ruleid:express-vm-injection
vm.runInContext('safeEval(orderLinesData)', sandbox, { timeout: 2000 })
res.send('hello world')
})
// ok:express-vm-injection
function testOk1(userInput) {
var sandbox = {
foo: 1
}
vm.createContext(sandbox)
vm.runInContext('safeEval(orderLinesData)', sandbox, { timeout: 2000 })
}
var ctrl2 = null;
ctrl2 = function test2(req,res) {
var input = req.query.something || ''
var sandbox = {
foo: input
}
// ruleid:express-vm-injection
vm.runInNewContext('safeEval(orderLinesData)', sandbox, { timeout: 2000 })
res.send('hello world')
}
app.get('/', ctrl2)
app.get('/', function (req,res) {
var sandbox = {
foo: req.query.userInput
}
// ruleid:express-vm-injection
vm.runInNewContext('safeEval(orderLinesData)', sandbox, { timeout: 2000 })
res.send('hello world')
})
// ok:express-vm-injection
app.get('/', function testOk1(userInput) {
var sandbox = {
foo: 1
}
vm.runInNewContext('safeEval(orderLinesData)', sandbox, { timeout: 2000 })
res.send('hello world')
})
app.get('/', function(req,res) {
const code = `
var x = ${req.query.userInput};
`
// ruleid:express-vm-injection
vm.runInThisContext(code)
res.send('hello world')
})
// ok:express-vm-injection
app.get('/', function okTest3(req,res) {
const code = `
var x = 1;
`
vm.runInThisContext(code)
res.send('hello world')
})
app.get('/', function test4(req,res) {
const parsingContext = vm.createContext({name: 'world'})
const code = `return 'hello ' + ${req.query.userInput}`
// ruleid:express-vm-injection
let fn = vm.compileFunction(code, [], { parsingContext })
res.send('hello world')
})
// ok:express-vm-injection
app.get('/', function okTest4(req,res) {
const parsingContext = vm.createContext({name: 'world'})
const code = `return 'hello ' + name`
const fn = vm.compileFunction(code, [], { parsingContext })
})
app.get('/', (req,res) => {
const context = vm.createContext({name: req.query.userInput})
let code = `return 'hello ' name`
// ruleid:express-vm-injection
const fn = vm.compileFunction(code, [], { parsingContext: context })
res.send('hello world')
})
// ok:express-vm-injection
app.get('/', function okTest5(req, res) {
const parsingContext = vm.createContext({name: 'world'})
const code = `return 'hello ' + name`
const fn = vm.compileFunction(code, [], { parsingContext })
res.send('hello world')
})
app.get('/', function (req,res) {
// ruleid:express-vm-injection
const script = new vm.Script(`
function add(a, b) {
return a + ${req.query.userInput};
}
const x = add(1, 2);
`);
script.runInThisContext();
res.send('hello world')
})
//ok:express-vm-injection
app.get('/', function okTest6(req, res) {
const script = new vm.Script(`
function add(a, b) {
return a + b;
}
const x = add(1, 2);
`);
script.runInThisContext();
res.send('hello world')
})
Short Link: https://sg.run/jkqJ