@@ -6,7 +6,6 @@ const { getNodeModulesPaths } = require('../path-line')
6
6
const { HEADER_NAME_VALUE_SEPARATOR } = require ( '../vulnerabilities-formatter/constants' )
7
7
const { getRanges } = require ( '../taint-tracking/operations' )
8
8
const {
9
- HTTP_REQUEST_COOKIE_NAME ,
10
9
HTTP_REQUEST_COOKIE_VALUE ,
11
10
HTTP_REQUEST_HEADER_VALUE
12
11
} = require ( '../taint-tracking/source-types' )
@@ -45,13 +44,7 @@ class HeaderInjectionAnalyzer extends InjectionAnalyzer {
45
44
if ( this . isExcludedHeaderName ( lowerCasedHeaderName ) || typeof value !== 'string' ) return
46
45
47
46
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 )
55
48
}
56
49
57
50
_getEvidence ( headerInfo , iastContext ) {
@@ -75,28 +68,52 @@ class HeaderInjectionAnalyzer extends InjectionAnalyzer {
75
68
return EXCLUDED_HEADER_NAMES . includes ( name )
76
69
}
77
70
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
+ }
83
77
84
- return false
78
+ isAllRangesFromSource ( ranges , source ) {
79
+ return ranges
80
+ . every ( range => range . iinfo . type === source )
85
81
}
86
82
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
+ */
87
87
isAccessControlAllowExclusion ( name , ranges ) {
88
88
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 )
91
90
}
92
91
93
92
return false
94
93
}
95
94
95
+ /** Exclude when the header is reflected from the request */
96
96
isSameHeaderExclusion ( name , ranges ) {
97
97
return ranges . length === 1 && name === ranges [ 0 ] . iinfo . parameterName ?. toLowerCase ( )
98
98
}
99
99
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
+
100
117
_getExcludedPaths ( ) {
101
118
return EXCLUDED_PATHS
102
119
}
0 commit comments