|
9 | 9 | * @tags security
|
10 | 10 | */
|
11 | 11 |
|
12 |
| - |
13 | 12 | import javascript
|
14 |
| - import DataFlow::PathGraph |
| 13 | + import ConfigFlow::PathGraph |
15 | 14 | import browserextension.BrowserInjectionObjectCustomizations::BrowserInjection
|
16 | 15 | import DataFlow
|
17 | 16 | private import semmle.javascript.security.dataflow.XssThroughDomCustomizations::XssThroughDom as XssThroughDom
|
18 | 17 |
|
19 | 18 |
|
20 |
| - class ObjectLabel extends DataFlow::FlowLabel { |
21 |
| - ObjectLabel() { |
22 |
| - this = "Object" |
23 |
| - } |
| 19 | + class ObjectState extends string { |
| 20 | + ObjectState() { this = "Object" } |
24 | 21 | }
|
25 | 22 |
|
26 | 23 | /**
|
27 | 24 | * Gets either a standard flow label or the partial-taint label.
|
28 | 25 | */
|
29 |
| - DataFlow::FlowLabel anyLabel() { |
30 |
| - result.isDataOrTaint() |
31 |
| - } |
| 26 | + string anyLabel() { result = ["data", "taint"] } |
32 | 27 |
|
33 | 28 |
|
34 |
| - class Configuration extends TaintTracking::Configuration { |
35 |
| - Configuration() { this = "BrowserInjection" } |
36 |
| - |
37 |
| - override predicate isSource(DataFlow::Node source) { |
38 |
| - source instanceof Source // optional: or source instanceof XssThroughDom::Source |
| 29 | + module Config implements DataFlow::StateConfigSig { |
| 30 | + class FlowState extends string { |
| 31 | + FlowState() { this = anyLabel() or this instanceof ObjectState } |
| 32 | + } |
| 33 | + |
| 34 | + predicate isSource(DataFlow::Node source, FlowState state) { |
| 35 | + source instanceof Source and // optional: or source instanceof XssThroughDom::Source |
| 36 | + ( |
| 37 | + state = anyLabel() |
| 38 | + or |
| 39 | + state instanceof ObjectState |
| 40 | + ) |
39 | 41 | }
|
40 | 42 |
|
41 |
| - override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel lbl) { |
42 |
| - sink instanceof Sink and lbl instanceof ObjectLabel |
| 43 | + predicate isSink(DataFlow::Node sink, FlowState state) { |
| 44 | + sink instanceof Sink and state instanceof ObjectState |
43 | 45 | }
|
44 | 46 |
|
45 |
| - override predicate isAdditionalFlowStep( |
46 |
| - DataFlow::Node src, DataFlow::Node trg, DataFlow::FlowLabel inlbl, DataFlow::FlowLabel outlbl |
| 47 | + predicate isAdditionalFlowStep( |
| 48 | + DataFlow::Node src, FlowState inState, DataFlow::Node trg, FlowState outState |
47 | 49 | ) {
|
48 | 50 | // writing a tainted value to an object property makes the object tainted with ObjectLabel
|
49 | 51 | exists(DataFlow::PropWrite write |
|
50 | 52 | write.getRhs() = src and
|
51 |
| - inlbl = anyLabel() and |
| 53 | + inState = anyLabel() and |
52 | 54 | trg.(DataFlow::SourceNode).flowsTo(write.getBase()) and
|
53 |
| - outlbl instanceof ObjectLabel |
| 55 | + outState instanceof ObjectState |
54 | 56 | )
|
55 | 57 | }
|
56 | 58 | }
|
57 | 59 |
|
| 60 | + module ConfigFlow = TaintTracking::GlobalWithState<Config>; |
58 | 61 |
|
59 |
| - from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink |
60 |
| - where cfg.hasFlowPath(source, sink) |
| 62 | + from ConfigFlow::PathNode source, ConfigFlow::PathNode sink |
| 63 | + where ConfigFlow::flowPath(source, sink) |
61 | 64 | select sink.getNode(), source, sink, sink.getNode() + " depends on a $@.",
|
62 | 65 | source.getNode(), "user-provided value"
|
63 | 66 |
|
|
0 commit comments