@@ -6,7 +6,6 @@ const { getNodeModulesPaths } = require('../path-line')
66const { HEADER_NAME_VALUE_SEPARATOR } = require ( '../vulnerabilities-formatter/constants' )
77const { getRanges } = require ( '../taint-tracking/operations' )
88const {
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