Skip to content

Commit b70f70f

Browse files
committed
JS: Add TaintedObject flow label library
1 parent 396ad33 commit b70f70f

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* Provides methods for reasoning about the flow of deeply tainted objects, such as JSON objects
3+
* parsed from user-controlled data.
4+
*
5+
* Deeply tainted objects are arrays or objects with user-controlled property names, containing
6+
* tainted values or deeply tainted objects in their properties.
7+
*
8+
* To track deeply tainted objects, a flow-tracking configuration should generally include the following:
9+
*
10+
* 1. One or more sinks associated with the label `TaintedObject::label()`.
11+
* 2. The sources from `TaintedObject::isSource`.
12+
* 3. The flow steps from `TaintedObject::step`.
13+
*/
14+
import javascript
15+
16+
module TaintedObject {
17+
private import DataFlow
18+
19+
private class TaintedObjectLabel extends FlowLabel {
20+
TaintedObjectLabel() { this = "tainted-object" }
21+
}
22+
23+
/**
24+
* Gets the flow label representing a deeply tainted objects.
25+
*
26+
* A "tainted object" is an array or object whose values are all assumed to be tainted as well.
27+
*
28+
* Note that the presence of the `object-taint` label generally implies the presence of the `taint` label as well.
29+
*/
30+
FlowLabel label() { result instanceof TaintedObjectLabel }
31+
32+
/**
33+
* Holds for the flows steps that are relevant for tracking user-controlled JSON objects.
34+
*/
35+
predicate step(Node src, Node trg, FlowLabel inlbl, FlowLabel outlbl) {
36+
// JSON parsers map tainted inputs to tainted JSON
37+
(inlbl = FlowLabel::data() or inlbl = FlowLabel::taint()) and
38+
outlbl = label() and
39+
exists (JsonParserCall parse |
40+
src = parse.getInput() and
41+
trg = parse.getOutput())
42+
or
43+
// Property reads preserve deep object taint.
44+
inlbl = label() and
45+
outlbl = label() and
46+
trg.(PropRead).getBase() = src
47+
or
48+
// Property projection preserves deep object taint
49+
inlbl = label() and
50+
outlbl = label() and
51+
trg.(PropertyProjection).getObject() = src
52+
or
53+
// Extending objects preserves deep object taint
54+
inlbl = label() and
55+
outlbl = label() and
56+
exists (ExtendCall call |
57+
src = call.getAnOperand() and
58+
trg = call
59+
or
60+
src = call.getASourceOperand() and
61+
trg = call.getDestinationOperand().getALocalSource())
62+
}
63+
64+
/**
65+
* Holds if `node` is a source of JSON taint and label is the JSON taint label.
66+
*/
67+
predicate isSource(Node source, FlowLabel label) {
68+
source instanceof Source and label = label()
69+
}
70+
71+
/**
72+
* A source of a user-controlled deep object object.
73+
*/
74+
abstract class Source extends DataFlow::Node {}
75+
76+
/** Request input accesses as a JSON source. */
77+
private class RequestInputAsSource extends Source {
78+
RequestInputAsSource() {
79+
this.(HTTP::RequestInputAccess).isDeepObject()
80+
}
81+
}
82+
83+
// TODO: string tests should be classified as sanitizer guards; need support for flow labels on guards
84+
}

0 commit comments

Comments
 (0)