@@ -8,15 +8,23 @@ import javascript
88module DomBasedXss {
99 import DomBasedXssCustomizations:: DomBasedXss
1010
11+ /**
12+ * DEPRECATED. Use `HtmlInjectionConfiguration` or `JQuerySelectorInjectionConfiguration`.
13+ */
14+ deprecated class Configuration = HtmlInjectionConfiguration ;
15+
1116 /**
1217 * A taint-tracking configuration for reasoning about XSS.
1318 */
14- class Configuration extends TaintTracking:: Configuration {
15- Configuration ( ) { this = "DomBasedXss " }
19+ class HtmlInjectionConfiguration extends TaintTracking:: Configuration {
20+ HtmlInjectionConfiguration ( ) { this = "HtmlInjection " }
1621
1722 override predicate isSource ( DataFlow:: Node source ) { source instanceof Source }
1823
19- override predicate isSink ( DataFlow:: Node sink ) { sink instanceof Sink }
24+ override predicate isSink ( DataFlow:: Node sink ) {
25+ sink instanceof Sink and
26+ not sink instanceof JQuerySelectorSink // Handled by JQuerySelectorInjectionConfiguration below
27+ }
2028
2129 override predicate isSanitizer ( DataFlow:: Node node ) {
2230 super .isSanitizer ( node )
@@ -28,59 +36,68 @@ module DomBasedXss {
2836 guard instanceof SanitizerGuard
2937 }
3038
31- override predicate isAdditionalStoreStep (
32- DataFlow:: Node pred , DataFlow:: SourceNode succ , string prop
33- ) {
34- exists ( DataFlow:: PropRead read |
35- pred = read .getBase ( ) and
36- succ = read and
37- read .getPropertyName ( ) = "hash" and
38- prop = urlSuffixPseudoProperty ( )
39- )
39+ override predicate isSanitizerEdge ( DataFlow:: Node pred , DataFlow:: Node succ ) {
40+ DomBasedXss:: isOptionallySanitizedEdge ( pred , succ )
41+ }
42+ }
43+
44+ /**
45+ * A taint-tracking configuration for reasoning about injection into the jQuery `$` function
46+ * or similar, where the interpretation of the input string depends on its first character.
47+ *
48+ * Values are only considered tainted if they can start with the `<` character.
49+ */
50+ class JQuerySelectorInjectionConfiguration extends TaintTracking:: Configuration {
51+ JQuerySelectorInjectionConfiguration ( ) { this = "JQuerySelectorInjection" }
52+
53+ override predicate isSource ( DataFlow:: Node source , DataFlow:: FlowLabel label ) {
54+ // Reuse any source not derived from location
55+ source instanceof Source and
56+ not source = DOM:: locationRef ( ) and
57+ label .isTaint ( )
58+ or
59+ source = DOM:: locationSource ( ) and
60+ label .isData ( ) // Require transformation before reaching sink
61+ or
62+ source = DOM:: locationRef ( ) .getAPropertyRead ( [ "hash" , "search" ] ) and
63+ label .isData ( ) // Require transformation before reaching sink
64+ }
65+
66+ override predicate isSink ( DataFlow:: Node sink , DataFlow:: FlowLabel label ) {
67+ sink instanceof JQuerySelectorSink and label .isTaint ( )
4068 }
4169
42- override predicate isAdditionalLoadStoreStep (
43- DataFlow:: Node pred , DataFlow:: Node succ , string predProp , string succProp
70+ override predicate isAdditionalFlowStep (
71+ DataFlow:: Node pred , DataFlow:: Node succ , DataFlow:: FlowLabel predlbl ,
72+ DataFlow:: FlowLabel succlbl
4473 ) {
45- exists ( DataFlow:: PropRead read |
46- pred = read .getBase ( ) and
47- succ = read and
48- read .getPropertyName ( ) = "hash" and
49- predProp = "hash" and
50- succProp = urlSuffixPseudoProperty ( )
74+ exists ( TaintTracking:: AdditionalTaintStep step |
75+ step .step ( pred , succ ) and
76+ predlbl .isData ( ) and
77+ succlbl .isTaint ( )
5178 )
5279 }
5380
54- override predicate isAdditionalLoadStep ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
55- exists ( DataFlow:: MethodCallNode call |
56- call .getMethodName ( ) = [ "substr" , "substring" , "slice" ] and
57- not call .getArgument ( 0 ) .getIntValue ( ) = 0 and
58- pred = call .getReceiver ( ) and
59- succ = call and
60- prop = urlSuffixPseudoProperty ( )
61- )
62- or
63- exists ( DataFlow:: MethodCallNode call |
64- call .getMethodName ( ) = "exec" and pred = call .getArgument ( 0 )
65- or
66- call .getMethodName ( ) = "match" and pred = call .getReceiver ( )
67- |
68- succ = call and
69- prop = urlSuffixPseudoProperty ( )
70- )
81+ override predicate isSanitizer ( DataFlow:: Node node ) {
82+ super .isSanitizer ( node )
7183 or
72- exists ( StringSplitCall split |
73- split .getSeparator ( ) = [ "#" , "?" ] and
74- pred = split .getBaseString ( ) and
75- succ = split .getASubstringRead ( 1 ) and
76- prop = urlSuffixPseudoProperty ( )
77- )
84+ node instanceof Sanitizer
85+ }
86+
87+ override predicate isSanitizerGuard ( TaintTracking:: SanitizerGuardNode guard ) {
88+ guard instanceof SanitizerGuard
7889 }
7990
8091 override predicate isSanitizerEdge ( DataFlow:: Node pred , DataFlow:: Node succ ) {
8192 DomBasedXss:: isOptionallySanitizedEdge ( pred , succ )
93+ or
94+ // Avoid stepping from location -> location.hash, as the .hash is already treated as a source
95+ // (with a different flow label)
96+ exists ( DataFlow:: PropRead read |
97+ read = DOM:: locationRef ( ) .getAPropertyRead ( [ "hash" , "search" ] ) and
98+ pred = read .getBase ( ) and
99+ succ = read
100+ )
82101 }
83102 }
84-
85- private string urlSuffixPseudoProperty ( ) { result = "$UrlSuffix$" }
86103}
0 commit comments