Skip to content

Commit f4fed36

Browse files
author
Max Schaefer
committed
JavaScript: Add flow summary extraction queries.
1 parent 6d893d4 commit f4fed36

17 files changed

Lines changed: 605 additions & 1 deletion
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
+ semmlecode-javascript-queries/Security/Summaries/ExtractSourceSummaries.ql
2+
+ semmlecode-javascript-queries/Security/Summaries/ExtractSinkSummaries.ql
3+
+ semmlecode-javascript-queries/Security/Summaries/ExtractFlowStepSummaries.ql
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Imports the standard library and all taint-tracking configuration classes from the security queries.
3+
*/
4+
5+
import javascript
6+
7+
import semmle.javascript.security.dataflow.BrokenCryptoAlgorithm
8+
import semmle.javascript.security.dataflow.CleartextLogging
9+
import semmle.javascript.security.dataflow.CleartextStorage
10+
import semmle.javascript.security.dataflow.ClientSideUrlRedirect
11+
import semmle.javascript.security.dataflow.CodeInjection
12+
import semmle.javascript.security.dataflow.CommandInjection
13+
import semmle.javascript.security.dataflow.ConditionalBypass
14+
import semmle.javascript.security.dataflow.CorsMisconfigurationForCredentials
15+
import semmle.javascript.security.dataflow.DifferentKindsComparisonBypass
16+
import semmle.javascript.security.dataflow.DomBasedXss as DomBasedXss
17+
import semmle.javascript.security.dataflow.FileAccessToHttp
18+
import semmle.javascript.security.dataflow.HardcodedCredentials
19+
import semmle.javascript.security.dataflow.InsecureRandomness
20+
import semmle.javascript.security.dataflow.InsufficientPasswordHash
21+
import semmle.javascript.security.dataflow.NosqlInjection
22+
import semmle.javascript.security.dataflow.ReflectedXss as ReflectedXss
23+
import semmle.javascript.security.dataflow.RegExpInjection
24+
import semmle.javascript.security.dataflow.RemotePropertyInjection
25+
import semmle.javascript.security.dataflow.RequestForgery
26+
import semmle.javascript.security.dataflow.ServerSideUrlRedirect
27+
import semmle.javascript.security.dataflow.SqlInjection
28+
import semmle.javascript.security.dataflow.StackTraceExposure
29+
import semmle.javascript.security.dataflow.StoredXss as StoredXss
30+
import semmle.javascript.security.dataflow.TaintedFormatString
31+
import semmle.javascript.security.dataflow.TaintedPath
32+
import semmle.javascript.security.dataflow.TypeConfusionThroughParameterTampering
33+
import semmle.javascript.security.dataflow.UnsafeDeserialization
34+
import semmle.javascript.security.dataflow.XmlBomb
35+
import semmle.javascript.security.dataflow.XpathInjection
36+
import semmle.javascript.security.dataflow.Xxe
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* @name Extract flow step summaries
3+
* @description Extracts flow step summaries, that is, tuples `(p1, lbl1, p2, lbl2, cfg)`
4+
* representing the fact that data with flow label `lbl1` may flow from a
5+
* user-controlled exit node of portal `p1` to an escaping entry node of portal `p2`,
6+
* and have label `lbl2` at that point. Moreover, the path from `p1` to `p2` contains
7+
* no sanitizers specified by configuration `cfg`.
8+
* @kind flow-step-summary
9+
* @id js/step-summary-extraction
10+
*/
11+
12+
import AllConfigurations
13+
import PortalExitSource
14+
import PortalEntrySink
15+
16+
from TaintTracking::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink,
17+
Portal p1, Portal p2, DataFlow::FlowLabel lbl1, DataFlow::FlowLabel lbl2
18+
where cfg.hasFlowPath(source, sink) and
19+
p1 = source.getNode().(PortalExitSource).getPortal() and
20+
p2 = sink.getNode().(PortalEntrySink).getPortal() and
21+
lbl1 = sink.getPathSummary().getStartLabel() and
22+
lbl2 = sink.getPathSummary().getEndLabel() and
23+
// avoid constructing infeasible paths
24+
sink.getPathSummary().hasCall() = false and
25+
sink.getPathSummary().hasReturn() = false and
26+
// restrict to steps flow function parameters to returns
27+
p1.(ParameterPortal).getBasePortal() = p2.(ReturnPortal).getBasePortal() and
28+
// restrict to data/taint flow
29+
lbl1 instanceof DataFlow::StandardFlowLabel
30+
select p1.toString(), lbl1.toString(),
31+
p2.toString(), lbl2.toString(),
32+
cfg.toString()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* @name Extract sink summaries
3+
* @description Extracts sink summaries, that is, tuples `(p, lbl, cfg)` representing the fact
4+
* that data with flow label `lbl` may flow from a user-controlled exit node of portal
5+
* `p` to a known sink for configuration `cfg`.
6+
* @kind sink-summary
7+
* @id js/sink-summary-extraction
8+
*/
9+
10+
import AllConfigurations
11+
import PortalExitSource
12+
13+
from TaintTracking::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink,
14+
Portal p
15+
where cfg.hasFlowPath(source, sink) and
16+
p = source.getNode().(PortalExitSource).getPortal() and
17+
// avoid constructing infeasible paths
18+
sink.getPathSummary().hasReturn() = false
19+
select p.toString(), source.getPathSummary().getStartLabel().toString(), cfg.toString()
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* @name Extract source summaries
3+
* @description Extracts source summaries, that is, tuples `(p, lbl, cfg)` representing the fact
4+
* that data may flow from a known source for configuration `cfg` to an escaping entry
5+
* node of portal `p`, and have flow label `lbl` at that point.
6+
* @kind source-summary
7+
* @id js/source-summary-extraction
8+
*/
9+
10+
import AllConfigurations
11+
import PortalEntrySink
12+
13+
from TaintTracking::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink,
14+
Portal p
15+
where cfg.hasFlowPath(source, sink) and
16+
p = sink.getNode().(PortalEntrySink).getPortal() and
17+
// avoid constructing infeasible paths
18+
sink.getPathSummary().hasCall() = false
19+
select p.toString(), sink.getPathSummary().getEndLabel().toString(), cfg.toString()
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import javascript
2+
import semmle.javascript.dataflow.Portals
3+
4+
/**
5+
* An escaping entry node of a portal, viewed as an additional sink node for any flow
6+
* configuration currently in scope.
7+
*/
8+
class PortalEntrySink extends DataFlow::AdditionalSink {
9+
Portal p;
10+
11+
PortalEntrySink() {
12+
this = p.getAnEntryNode(true)
13+
}
14+
15+
override predicate isSinkFor(DataFlow::Configuration cfg, DataFlow::FlowLabel lbl) {
16+
cfg instanceof TaintTracking::Configuration and
17+
lbl = any(DataFlow::FlowLabel l)
18+
}
19+
20+
/** Gets the portal of which this is an entry node. */
21+
Portal getPortal() {
22+
result = p
23+
}
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import javascript
2+
import semmle.javascript.dataflow.Portals
3+
4+
/**
5+
* A remote exit node of a portal, viewed as an additional source node for any flow
6+
* configuration currently in scope.
7+
*/
8+
class PortalExitSource extends DataFlow::AdditionalSource {
9+
Portal p;
10+
11+
PortalExitSource() {
12+
this = p.getAnExitNode(true)
13+
}
14+
15+
override predicate isSourceFor(DataFlow::Configuration cfg, DataFlow::FlowLabel lbl) {
16+
cfg instanceof TaintTracking::Configuration and
17+
lbl = any(DataFlow::FlowLabel l)
18+
}
19+
20+
/** Gets the portal of which this is an exit node. */
21+
Portal getPortal() {
22+
result = p
23+
}
24+
}

javascript/ql/src/semmle/javascript/dataflow/Configuration.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ class TaintKind = FlowLabel;
246246
/**
247247
* A standard flow label, that is, either `FlowLabel::data()` or `FlowLabel::taint()`.
248248
*/
249-
private class StandardFlowLabel extends FlowLabel {
249+
class StandardFlowLabel extends FlowLabel {
250250
StandardFlowLabel() { this = "data" or this = "taint" }
251251
}
252252

@@ -790,6 +790,11 @@ class PathNode extends TPathNode {
790790
/** Gets the underlying data flow tracking configuration of this path node. */
791791
DataFlow::Configuration getConfiguration() { result = cfg }
792792

793+
/** Gets the summary of the path underlying this path node. */
794+
PathSummary getPathSummary() {
795+
result = summary
796+
}
797+
793798
/** Gets a successor node of this path node. */
794799
PathNode getASuccessor() {
795800
exists(DataFlow::Node succ, PathSummary newSummary |

javascript/ql/src/semmle/javascript/dataflow/internal/FlowSteps.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,11 @@ class PathSummary extends TPathSummary {
285285
/** Indicates whether the path represented by this summary contains any call steps. */
286286
boolean hasCall() { result = hasCall }
287287

288+
/** Gets the flow label describing the value at the start of this flow path. */
289+
FlowLabel getStartLabel() {
290+
result = start
291+
}
292+
288293
/** Gets the flow label describing the value at the end of this flow path. */
289294
FlowLabel getEndLabel() { result = end }
290295

0 commit comments

Comments
 (0)