Skip to content

Commit df272aa

Browse files
committed
Taint request URI
1 parent 27e1530 commit df272aa

File tree

5 files changed

+98
-3
lines changed

5 files changed

+98
-3
lines changed

packages/dd-trace/src/appsec/iast/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ function onIncomingHttpRequestStart (data) {
5454
const iastContext = iastContextFunctions.saveIastContext(store, topContext, { rootSpan, req: data.req })
5555
createTransaction(rootSpan.context().toSpanId(), iastContext)
5656
overheadController.initializeRequestContext(iastContext)
57-
taintTrackingPlugin.taintHeaders(data.req.headers, iastContext)
57+
taintTrackingPlugin.taintRequest(data.req, iastContext)
5858
}
5959
if (rootSpan.addTags) {
6060
rootSpan.addTags({

packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ module.exports = {
77
HTTP_REQUEST_HEADER_NAME: 'http.request.header.name',
88
HTTP_REQUEST_HEADER_VALUE: 'http.request.header',
99
HTTP_REQUEST_PARAMETER: 'http.request.parameter',
10+
HTTP_REQUEST_PATH: 'http.request.path',
1011
HTTP_REQUEST_PATH_PARAM: 'http.request.path.parameter'
1112
}

packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
const Plugin = require('../../../plugins/plugin')
44
const { getIastContext } = require('../iast-context')
55
const { storage } = require('../../../../../datadog-core')
6-
const { taintObject } = require('./operations')
6+
const { taintObject, newTaintedString } = require('./operations')
77
const {
88
HTTP_REQUEST_BODY,
99
HTTP_REQUEST_COOKIE_VALUE,
1010
HTTP_REQUEST_COOKIE_NAME,
1111
HTTP_REQUEST_HEADER_VALUE,
1212
HTTP_REQUEST_HEADER_NAME,
1313
HTTP_REQUEST_PARAMETER,
14+
HTTP_REQUEST_PATH,
1415
HTTP_REQUEST_PATH_PARAM
1516

1617
} = require('./origin-types')
@@ -73,6 +74,11 @@ class TaintTrackingPlugin extends Plugin {
7374
taintObject(iastContext, headers, HTTP_REQUEST_HEADER_VALUE, true, HTTP_REQUEST_HEADER_NAME)
7475
}
7576

77+
taintRequest (req, iastContext) {
78+
taintObject(iastContext, req.headers, HTTP_REQUEST_HEADER_VALUE, true, HTTP_REQUEST_HEADER_NAME)
79+
req.url = newTaintedString(iastContext, req.url, 'req.url', HTTP_REQUEST_PATH)
80+
}
81+
7682
enable () {
7783
this.configure(true)
7884
}

packages/dd-trace/test/appsec/iast/taint-tracking/plugin.spec.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ const dc = require('../../../../../diagnostics_channel')
77
const {
88
HTTP_REQUEST_COOKIE_VALUE,
99
HTTP_REQUEST_COOKIE_NAME,
10+
HTTP_REQUEST_HEADER_NAME,
11+
HTTP_REQUEST_HEADER_VALUE,
12+
HTTP_REQUEST_PATH,
1013
HTTP_REQUEST_PATH_PARAM
1114
} = require('../../../../src/appsec/iast/taint-tracking/origin-types')
1215

@@ -227,5 +230,30 @@ describe('IAST Taint tracking plugin', () => {
227230
processParamsStartCh.publish({ req })
228231
expect(taintTrackingOperations.taintObject).to.not.be.called
229232
})
233+
234+
it('Should taint headers and uri from request', () => {
235+
const req = {
236+
headers: {
237+
'x-iast-header': 'header-value'
238+
},
239+
url: 'https://testurl'
240+
}
241+
taintTrackingPlugin.taintRequest(req, iastContext)
242+
243+
expect(taintTrackingOperations.taintObject).to.be.calledOnceWith(
244+
iastContext,
245+
req.headers,
246+
HTTP_REQUEST_HEADER_VALUE,
247+
true,
248+
HTTP_REQUEST_HEADER_NAME
249+
)
250+
251+
expect(taintTrackingOperations.newTaintedString).to.be.calledOnceWith(
252+
iastContext,
253+
req.url,
254+
'req.url',
255+
HTTP_REQUEST_PATH
256+
)
257+
})
230258
})
231259
})

packages/dd-trace/test/appsec/iast/taint-tracking/sources/taint-tracking.express.plugin.spec.js

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,67 @@ const { storage } = require('../../../../../../datadog-core')
99
const iast = require('../../../../../src/appsec/iast')
1010
const iastContextFunctions = require('../../../../../src/appsec/iast/iast-context')
1111
const { isTainted, getRanges } = require('../../../../../src/appsec/iast/taint-tracking/operations')
12-
const { HTTP_REQUEST_PATH_PARAM } = require('../../../../../src/appsec/iast/taint-tracking/origin-types')
12+
const {
13+
HTTP_REQUEST_PATH,
14+
HTTP_REQUEST_PATH_PARAM
15+
} = require('../../../../../src/appsec/iast/taint-tracking/origin-types')
16+
17+
describe('Path sourcing with express', () => {
18+
let express
19+
let appListener
20+
21+
withVersions('express', 'express', version => {
22+
before(() => {
23+
return agent.load(['http', 'express'], { client: false })
24+
})
25+
26+
after(() => {
27+
return agent.close({ ritmReset: false })
28+
})
29+
30+
beforeEach(() => {
31+
iast.enable(new Config({
32+
experimental: {
33+
iast: {
34+
enabled: true,
35+
requestSampling: 100
36+
}
37+
}
38+
}))
39+
40+
express = require(`../../../../../../../versions/express@${version}`).get()
41+
})
42+
43+
afterEach(() => {
44+
appListener && appListener.close()
45+
appListener = null
46+
47+
iast.disable()
48+
})
49+
50+
it('should taint path', done => {
51+
const app = express()
52+
app.get('/path/*', (req, res) => {
53+
const store = storage.getStore()
54+
const iastContext = iastContextFunctions.getIastContext(store)
55+
const isPathTainted = isTainted(iastContext, req.url)
56+
expect(isPathTainted).to.be.true
57+
const taintedPathValueRanges = getRanges(iastContext, req.url)
58+
expect(taintedPathValueRanges[0].iinfo.type).to.be.equal(HTTP_REQUEST_PATH)
59+
res.status(200).send()
60+
})
61+
62+
getPort().then(port => {
63+
appListener = app.listen(port, 'localhost', () => {
64+
axios
65+
.get(`http://localhost:${port}/path/vulnearable`)
66+
.then(() => done())
67+
.catch(done)
68+
})
69+
})
70+
})
71+
})
72+
})
1373

1474
describe('Path params sourcing with express', () => {
1575
let express

0 commit comments

Comments
 (0)