Skip to content

Commit 3b8a6b9

Browse files
authored
Instrument vm for code injection vulnerability (#5080)
* Instrument vm for code injection vulnerability * simplify vm constructor instrumentation * support SourceTextModule class * add code injection integration test * instrument SourceTextModule only if it's enabled * unify channel arguments
1 parent c37f47b commit 3b8a6b9

6 files changed

Lines changed: 505 additions & 50 deletions

File tree

packages/datadog-instrumentations/src/helpers/hooks.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ module.exports = {
9797
'node:https': () => require('../http'),
9898
'node:net': () => require('../net'),
9999
'node:url': () => require('../url'),
100+
'node:vm': () => require('../vm'),
100101
nyc: () => require('../nyc'),
101102
oracledb: () => require('../oracledb'),
102103
openai: () => require('../openai'),
@@ -123,6 +124,7 @@ module.exports = {
123124
undici: () => require('../undici'),
124125
url: () => require('../url'),
125126
vitest: { esmFirst: true, fn: () => require('../vitest') },
127+
vm: () => require('../vm'),
126128
when: () => require('../when'),
127129
winston: () => require('../winston'),
128130
workerpool: () => require('../mocha')
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict'
2+
3+
const { channel, addHook } = require('./helpers/instrument')
4+
const shimmer = require('../../datadog-shimmer')
5+
const names = ['vm', 'node:vm']
6+
7+
const runScriptStartChannel = channel('datadog:vm:run-script:start')
8+
const sourceTextModuleStartChannel = channel('datadog:vm:source-text-module:start')
9+
10+
addHook({ name: names }, function (vm) {
11+
vm.Script = class extends vm.Script {
12+
constructor (code) {
13+
super(...arguments)
14+
15+
if (runScriptStartChannel.hasSubscribers && code) {
16+
runScriptStartChannel.publish({ code })
17+
}
18+
}
19+
}
20+
21+
if (vm.SourceTextModule && typeof vm.SourceTextModule === 'function') {
22+
vm.SourceTextModule = class extends vm.SourceTextModule {
23+
constructor (code) {
24+
super(...arguments)
25+
26+
if (sourceTextModuleStartChannel.hasSubscribers && code) {
27+
sourceTextModuleStartChannel.publish({ code })
28+
}
29+
}
30+
}
31+
}
32+
33+
shimmer.wrap(vm, 'runInContext', wrapVMMethod)
34+
shimmer.wrap(vm, 'runInNewContext', wrapVMMethod)
35+
shimmer.wrap(vm, 'runInThisContext', wrapVMMethod)
36+
shimmer.wrap(vm, 'compileFunction', wrapVMMethod)
37+
38+
return vm
39+
})
40+
41+
function wrapVMMethod (original) {
42+
return function wrappedVMMethod (code) {
43+
if (runScriptStartChannel.hasSubscribers && code) {
44+
runScriptStartChannel.publish({ code })
45+
}
46+
47+
return original.apply(this, arguments)
48+
}
49+
}

packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ class CodeInjectionAnalyzer extends InjectionAnalyzer {
1010

1111
onConfigure () {
1212
this.addSub('datadog:eval:call', ({ script }) => this.analyze(script))
13+
this.addSub('datadog:vm:run-script:start', ({ code }) => this.analyze(code))
14+
this.addSub('datadog:vm:source-text-module:start', ({ code }) => this.analyze(code))
1315
}
1416

1517
_areRangesVulnerable () {

0 commit comments

Comments
 (0)