@@ -3,53 +3,37 @@ import semmle.python.dataflow.new.DataFlow
33import semmle.python.dataflow.new.DataFlow2
44import semmle.python.dataflow.new.TaintTracking
55import semmle.python.dataflow.new.TaintTracking2
6- import experimental.semmle.python.Concepts
76import semmle.python.dataflow.new.RemoteFlowSources
8- import semmle.python.ApiGraphs
97import semmle.python.security.dataflow.ChainedConfigs12
8+ import experimental.semmle.python.Concepts
9+ import semmle.python.Concepts
1010
11- class JsonLoadsCall extends DataFlow:: CallCfgNode {
12- JsonLoadsCall ( ) { this = API:: moduleImport ( "json" ) .getMember ( "loads" ) .getACall ( ) }
13-
14- DataFlow:: Node getLoadNode ( ) { result = this .getArg ( 0 ) }
15- }
16-
17- class XmlToDictParseCall extends DataFlow:: CallCfgNode {
18- XmlToDictParseCall ( ) { this = API:: moduleImport ( "xmltodict" ) .getMember ( "parse" ) .getACall ( ) }
19-
20- DataFlow:: Node getParseNode ( ) { result = this .getArg ( 0 ) }
21- }
22-
23- class UltraJsonLoadsCall extends DataFlow:: CallCfgNode {
24- UltraJsonLoadsCall ( ) { this = API:: moduleImport ( "ujson" ) .getMember ( "loads" ) .getACall ( ) }
25-
26- DataFlow:: Node getLoadNode ( ) { result = this .getArg ( 0 ) }
27- }
28-
29- class DataToDictSink extends DataFlow:: Node {
30- DataToDictSink ( ) {
31- this = any ( JsonLoadsCall jsonLoads ) .getLoadNode ( ) or
32- this = any ( XmlToDictParseCall jsonLoads ) .getParseNode ( ) or
33- this = any ( UltraJsonLoadsCall jsonLoads ) .getLoadNode ( )
34- }
35- }
36-
11+ /**
12+ * A taint-tracking configuration for detecting string-to-dict conversions.
13+ */
3714class RFSToDictConfig extends TaintTracking:: Configuration {
3815 RFSToDictConfig ( ) { this = "RFSToDictConfig" }
3916
4017 override predicate isSource ( DataFlow:: Node source ) { source instanceof RemoteFlowSource }
4118
42- override predicate isSink ( DataFlow:: Node sink ) { sink instanceof DataToDictSink }
19+ override predicate isSink ( DataFlow:: Node sink ) {
20+ exists ( Decoding decoding | decoding .getFormat ( ) = "JSON" and sink = decoding )
21+ }
4322
4423 override predicate isSanitizer ( DataFlow:: Node sanitizer ) {
4524 sanitizer = any ( NoSQLSanitizer noSQLSanitizer ) .getAnInput ( )
4625 }
4726}
4827
28+ /**
29+ * A taint-tracking configuration for detecting NoSQL injections (previously converted to a dict).
30+ */
4931class FromDataDictToSink extends TaintTracking2:: Configuration {
5032 FromDataDictToSink ( ) { this = "FromDataDictToSink" }
5133
52- override predicate isSource ( DataFlow:: Node source ) { source instanceof DataToDictSink }
34+ override predicate isSource ( DataFlow:: Node source ) {
35+ exists ( Decoding decoding | decoding .getFormat ( ) = "JSON" and source = decoding )
36+ }
5337
5438 override predicate isSink ( DataFlow:: Node sink ) { sink = any ( NoSQLQuery noSQLQuery ) .getQuery ( ) }
5539
@@ -58,6 +42,9 @@ class FromDataDictToSink extends TaintTracking2::Configuration {
5842 }
5943}
6044
45+ /**
46+ * A predicate checking string-to-dict conversion and its arrival to a NoSQL injection sink.
47+ */
6148predicate noSQLInjectionFlow ( CustomPathNode source , CustomPathNode sink ) {
6249 exists (
6350 RFSToDictConfig config , DataFlow:: PathNode mid1 , DataFlow2:: PathNode mid2 ,
0 commit comments