Skip to content

Commit 70e99bd

Browse files
authored
Add exclusions for header injection vulnerability (#4841)
* Add exclusions for header injection vulnerability * Rewrite fn to get a partial value from accept-encoding header to reflect it in transfer/content-encoding * Fix linting problems
1 parent 367bd2d commit 70e99bd

File tree

3 files changed

+339
-166
lines changed

3 files changed

+339
-166
lines changed

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

+33-16
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ const { getNodeModulesPaths } = require('../path-line')
66
const { HEADER_NAME_VALUE_SEPARATOR } = require('../vulnerabilities-formatter/constants')
77
const { getRanges } = require('../taint-tracking/operations')
88
const {
9-
HTTP_REQUEST_COOKIE_NAME,
109
HTTP_REQUEST_COOKIE_VALUE,
1110
HTTP_REQUEST_HEADER_VALUE
1211
} = require('../taint-tracking/source-types')
@@ -45,13 +44,7 @@ class HeaderInjectionAnalyzer extends InjectionAnalyzer {
4544
if (this.isExcludedHeaderName(lowerCasedHeaderName) || typeof value !== 'string') return
4645

4746
const ranges = getRanges(iastContext, value)
48-
if (ranges?.length > 0) {
49-
return !(this.isCookieExclusion(lowerCasedHeaderName, ranges) ||
50-
this.isSameHeaderExclusion(lowerCasedHeaderName, ranges) ||
51-
this.isAccessControlAllowExclusion(lowerCasedHeaderName, ranges))
52-
}
53-
54-
return false
47+
return ranges?.length > 0 && !this.shouldIgnoreHeader(lowerCasedHeaderName, ranges)
5548
}
5649

5750
_getEvidence (headerInfo, iastContext) {
@@ -75,28 +68,52 @@ class HeaderInjectionAnalyzer extends InjectionAnalyzer {
7568
return EXCLUDED_HEADER_NAMES.includes(name)
7669
}
7770

78-
isCookieExclusion (name, ranges) {
79-
if (name === 'set-cookie') {
80-
return ranges
81-
.every(range => range.iinfo.type === HTTP_REQUEST_COOKIE_VALUE || range.iinfo.type === HTTP_REQUEST_COOKIE_NAME)
82-
}
71+
isAllRangesFromHeader (ranges, headerName) {
72+
return ranges
73+
.every(range =>
74+
range.iinfo.type === HTTP_REQUEST_HEADER_VALUE && range.iinfo.parameterName?.toLowerCase() === headerName
75+
)
76+
}
8377

84-
return false
78+
isAllRangesFromSource (ranges, source) {
79+
return ranges
80+
.every(range => range.iinfo.type === source)
8581
}
8682

83+
/**
84+
* Exclude access-control-allow-*: when the header starts with access-control-allow- and the
85+
* source of the tainted range is a request header
86+
*/
8787
isAccessControlAllowExclusion (name, ranges) {
8888
if (name?.startsWith('access-control-allow-')) {
89-
return ranges
90-
.every(range => range.iinfo.type === HTTP_REQUEST_HEADER_VALUE)
89+
return this.isAllRangesFromSource(ranges, HTTP_REQUEST_HEADER_VALUE)
9190
}
9291

9392
return false
9493
}
9594

95+
/** Exclude when the header is reflected from the request */
9696
isSameHeaderExclusion (name, ranges) {
9797
return ranges.length === 1 && name === ranges[0].iinfo.parameterName?.toLowerCase()
9898
}
9999

100+
shouldIgnoreHeader (headerName, ranges) {
101+
switch (headerName) {
102+
case 'set-cookie':
103+
/** Exclude set-cookie header if the source of all the tainted ranges are cookies */
104+
return this.isAllRangesFromSource(ranges, HTTP_REQUEST_COOKIE_VALUE)
105+
case 'pragma':
106+
/** Ignore pragma headers when the source is the cache control header. */
107+
return this.isAllRangesFromHeader(ranges, 'cache-control')
108+
case 'transfer-encoding':
109+
case 'content-encoding':
110+
/** Ignore transfer and content encoding headers when the source is the accept encoding header. */
111+
return this.isAllRangesFromHeader(ranges, 'accept-encoding')
112+
}
113+
114+
return this.isAccessControlAllowExclusion(headerName, ranges) || this.isSameHeaderExclusion(headerName, ranges)
115+
}
116+
100117
_getExcludedPaths () {
101118
return EXCLUDED_PATHS
102119
}

0 commit comments

Comments
 (0)