@@ -20,68 +20,70 @@ module SinkEndpointFilter {
2020 * effective sink.
2121 */
2222 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"
2530 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"
4634 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
7582 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.
8283 isAssignedToOrConcatenatedWith ( sinkCandidate , "(?i)(nosql|query)" ) or
8384 isArgTo ( sinkCandidate , "(?i)(query)" )
84- )
85+ ) and
86+ result = "not a direct argument to a likely external library call or a heuristic sink"
8587 }
8688}
8789
0 commit comments