@@ -20,68 +20,70 @@ module SinkEndpointFilter {
20
20
* effective sink.
21
21
*/
22
22
string getAReasonSinkExcluded ( DataFlow:: Node sinkCandidate ) {
23
- (
24
- result = StandardEndpointFilters:: getAReasonSinkExcluded ( sinkCandidate )
23
+ result = StandardEndpointFilters:: getAReasonSinkExcluded ( sinkCandidate )
24
+ or
25
+ exists ( DataFlow:: CallNode call | sinkCandidate = call .getAnArgument ( ) |
26
+ // additional databases accesses that aren't modeled yet
27
+ call .( DataFlow:: MethodCallNode ) .getMethodName ( ) =
28
+ [ "create" , "createCollection" , "createIndexes" ] and
29
+ result = "matches database access call heuristic"
25
30
or
26
- // Require NoSQL injection sink candidates to be direct arguments to external library calls.
27
- //
28
- // The standard endpoint filters allow sink candidates which are within object literals or
29
- // array literals, for example `req.sendFile(_, { path: ENDPOINT })`.
30
- //
31
- // However, the NoSQL injection query deals differently with these types of sinks compared to
32
- // other security queries. Other security queries such as SQL injection tend to treat
33
- // `ENDPOINT` as the ground truth sink, but the NoSQL injection query instead treats
34
- // `{ path: ENDPOINT }` as the ground truth sink and defines an additional flow step to ensure
35
- // data flows from `ENDPOINT` to the ground truth sink `{ path: ENDPOINT }`.
36
- //
37
- // Therefore for the NoSQL injection boosted query, we must explicitly ignore sink candidates
38
- // within object literals or array literals, to avoid having multiple alerts for the same
39
- // security vulnerability (one FP where the sink is `ENDPOINT` and one TP where the sink is
40
- // `{ path: ENDPOINT }`).
41
- //
42
- // We use the same reason as in the standard endpoint filters to avoid duplicate reasons for
43
- // endpoints that are neither direct nor indirect arguments to a likely external library call.
44
- not sinkCandidate = StandardEndpointFilters:: getALikelyExternalLibraryCall ( ) .getAnArgument ( ) and
45
- result = "not an argument to a likely external library call"
31
+ // Remove modeled sinks
32
+ CoreKnowledge:: isArgumentToKnownLibrarySinkFunction ( sinkCandidate ) and
33
+ result = "modeled sink"
46
34
or
47
- exists ( DataFlow:: CallNode call | sinkCandidate = call .getAnArgument ( ) |
48
- // additional databases accesses that aren't modeled yet
49
- call .( DataFlow:: MethodCallNode ) .getMethodName ( ) =
50
- [ "create" , "createCollection" , "createIndexes" ] and
51
- result = "matches database access call heuristic"
52
- or
53
- // Remove modeled sinks
54
- CoreKnowledge:: isArgumentToKnownLibrarySinkFunction ( sinkCandidate ) and
55
- result = "modeled sink"
56
- or
57
- // Remove common kinds of unlikely sinks
58
- CoreKnowledge:: isKnownStepSrc ( sinkCandidate ) and
59
- result = "predecessor in a modeled flow step"
60
- or
61
- // Remove modeled database calls. Arguments to modeled calls are very likely to be modeled
62
- // as sinks if they are true positives. Therefore arguments that are not modeled as sinks
63
- // are unlikely to be true positives.
64
- call instanceof DatabaseAccess and
65
- result = "modeled database access"
66
- or
67
- // Remove calls to APIs that aren't relevant to NoSQL injection
68
- call .getReceiver ( ) .asExpr ( ) instanceof HTTP:: RequestExpr and
69
- result = "receiver is a HTTP request expression"
70
- or
71
- call .getReceiver ( ) .asExpr ( ) instanceof HTTP:: ResponseExpr and
72
- result = "receiver is a HTTP response expression"
73
- )
74
- ) and
35
+ // Remove common kinds of unlikely sinks
36
+ CoreKnowledge:: isKnownStepSrc ( sinkCandidate ) and
37
+ result = "predecessor in a modeled flow step"
38
+ or
39
+ // Remove modeled database calls. Arguments to modeled calls are very likely to be modeled
40
+ // as sinks if they are true positives. Therefore arguments that are not modeled as sinks
41
+ // are unlikely to be true positives.
42
+ call instanceof DatabaseAccess and
43
+ result = "modeled database access"
44
+ or
45
+ // Remove calls to APIs that aren't relevant to NoSQL injection
46
+ call .getReceiver ( ) .asExpr ( ) instanceof HTTP:: RequestExpr and
47
+ result = "receiver is a HTTP request expression"
48
+ or
49
+ call .getReceiver ( ) .asExpr ( ) instanceof HTTP:: ResponseExpr and
50
+ result = "receiver is a HTTP response expression"
51
+ )
52
+ or
53
+ // Require NoSQL injection sink candidates to be (a) direct arguments to external library calls
54
+ // or (b) heuristic sinks for NoSQL injection.
55
+ //
56
+ // ## Direct arguments to external library calls
57
+ //
58
+ // The `StandardEndpointFilters::flowsToArgumentOfLikelyExternalLibraryCall` endpoint filter
59
+ // allows sink candidates which are within object literals or array literals, for example
60
+ // `req.sendFile(_, { path: ENDPOINT })`.
61
+ //
62
+ // However, the NoSQL injection query deals differently with these types of sinks compared to
63
+ // other security queries. Other security queries such as SQL injection tend to treat
64
+ // `ENDPOINT` as the ground truth sink, but the NoSQL injection query instead treats
65
+ // `{ path: ENDPOINT }` as the ground truth sink and defines an additional flow step to ensure
66
+ // data flows from `ENDPOINT` to the ground truth sink `{ path: ENDPOINT }`.
67
+ //
68
+ // Therefore for the NoSQL injection boosted query, we must ignore sink candidates within object
69
+ // literals or array literals, to avoid having multiple alerts for the same security
70
+ // vulnerability (one FP where the sink is `ENDPOINT` and one TP where the sink is
71
+ // `{ path: ENDPOINT }`). We accomplish this by directly testing that the sink candidate is an
72
+ // argument of a likely external library call.
73
+ //
74
+ // ## Heuristic sinks
75
+ //
76
+ // We also allow heuristic sinks in addition to direct arguments to external library calls.
77
+ // These are copied from the `HeuristicNosqlInjectionSink` class defined within
78
+ // `codeql/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll`.
79
+ // We can't reuse the class because importing that file would cause us to treat these
80
+ // heuristic sinks as known sinks.
81
+ not sinkCandidate = StandardEndpointFilters:: getALikelyExternalLibraryCall ( ) .getAnArgument ( ) and
75
82
not (
76
- // Explicitly allow the following heuristic sinks.
77
- //
78
- // These are copied from the `HeuristicNosqlInjectionSink` class defined within
79
- // `codeql/javascript/ql/src/semmle/javascript/heuristics/AdditionalSinks.qll`.
80
- // We can't reuse the class because importing that file would cause us to treat these
81
- // heuristic sinks as known sinks.
82
83
isAssignedToOrConcatenatedWith ( sinkCandidate , "(?i)(nosql|query)" ) or
83
84
isArgTo ( sinkCandidate , "(?i)(query)" )
84
- )
85
+ ) and
86
+ result = "not a direct argument to a likely external library call or a heuristic sink"
85
87
}
86
88
}
87
89
0 commit comments