@@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.DataFlow
99private import experimental.semmle.python.Concepts
1010private import semmle.python.ApiGraphs
1111import semmle.python.dataflow.new.RemoteFlowSources
12+ private import semmle.python.Concepts
1213
1314private module PrivateDjango {
1415 private module django {
@@ -32,22 +33,64 @@ private module PrivateDjango {
3233 module response {
3334 module HttpResponse {
3435 API:: Node baseClassRef ( ) {
35- result = response ( ) .getMember ( "HttpResponse" ) . getReturn ( )
36+ result = response ( ) .getMember ( "HttpResponse" )
3637 or
3738 // Handle `django.http.HttpResponse` alias
38- result = http ( ) .getMember ( "HttpResponse" ) . getReturn ( )
39+ result = http ( ) .getMember ( "HttpResponse" )
3940 }
4041
42+ /** Gets a reference to the `django.http.response.HttpResponse` class. */
43+ API:: Node classRef ( ) { result = baseClassRef ( ) .getASubclass * ( ) }
44+
45+ /**
46+ * A source of instances of `django.http.response.HttpResponse`, extend this class to model new instances.
47+ *
48+ * This can include instantiations of the class, return values from function
49+ * calls, or a special parameter that will be set when functions are called by an external
50+ * library.
51+ *
52+ * Use the predicate `HttpResponse::instance()` to get references to instances of `django.http.response.HttpResponse`.
53+ */
54+ abstract class InstanceSource extends HTTP:: Server:: HttpResponse:: Range , DataFlow:: Node {
55+ }
56+
57+ /** A direct instantiation of `django.http.response.HttpResponse`. */
58+ private class ClassInstantiation extends InstanceSource , DataFlow:: CallCfgNode {
59+ ClassInstantiation ( ) { this = classRef ( ) .getACall ( ) }
60+
61+ override DataFlow:: Node getBody ( ) {
62+ result in [ this .getArg ( 0 ) , this .getArgByName ( "content" ) ]
63+ }
64+
65+ // How to support the `headers` argument here?
66+ override DataFlow:: Node getMimetypeOrContentTypeArg ( ) {
67+ result in [ this .getArg ( 1 ) , this .getArgByName ( "content_type" ) ]
68+ }
69+
70+ override string getMimetypeDefault ( ) { result = "text/html" }
71+ }
72+
73+ /** Gets a reference to an instance of `django.http.response.HttpResponse`. */
74+ private DataFlow:: TypeTrackingNode instance ( DataFlow:: TypeTracker t ) {
75+ t .start ( ) and
76+ result instanceof InstanceSource
77+ or
78+ exists ( DataFlow:: TypeTracker t2 | result = instance ( t2 ) .track ( t2 , t ) )
79+ }
80+
81+ /** Gets a reference to an instance of `django.http.response.HttpResponse`. */
82+ DataFlow:: Node instance ( ) { instance ( DataFlow:: TypeTracker:: end ( ) ) .flowsTo ( result ) }
83+
4184 /** Gets a reference to a header instance. */
4285 private DataFlow:: LocalSourceNode headerInstance ( DataFlow:: TypeTracker t ) {
4386 t .start ( ) and
4487 (
4588 exists ( SubscriptNode subscript |
46- subscript .getObject ( ) = baseClassRef ( ) .getAUse ( ) .asCfgNode ( ) and
89+ subscript .getObject ( ) = baseClassRef ( ) .getReturn ( ) . getAUse ( ) .asCfgNode ( ) and
4790 result .asCfgNode ( ) = subscript
4891 )
4992 or
50- result .( DataFlow:: AttrRead ) .getObject ( ) = baseClassRef ( ) .getAUse ( )
93+ result .( DataFlow:: AttrRead ) .getObject ( ) = baseClassRef ( ) .getReturn ( ) . getAUse ( )
5194 )
5295 or
5396 exists ( DataFlow:: TypeTracker t2 | result = headerInstance ( t2 ) .track ( t2 , t ) )
@@ -106,27 +149,35 @@ private module PrivateDjango {
106149 * * `isHttpOnly()` predicate would succeed.
107150 * * `isSameSite()` predicate would succeed.
108151 */
109- class DjangoSetCookieCall extends DataFlow:: CallCfgNode , Cookie:: Range {
110- DjangoSetCookieCall ( ) { this = baseClassRef ( ) .getMember ( "set_cookie" ) .getACall ( ) }
152+ class DjangoResponseSetCookieCall extends DataFlow:: MethodCallNode , Cookie:: Range {
153+ DjangoResponseSetCookieCall ( ) {
154+ this .calls ( django:: http:: response:: HttpResponse:: instance ( ) , "set_cookie" )
155+ }
111156
112- override DataFlow:: Node getNameArg ( ) { result = this .getArg ( 0 ) }
157+ override DataFlow:: Node getNameArg ( ) {
158+ result in [ this .getArg ( 0 ) , this .getArgByName ( "key" ) ]
159+ }
113160
114- override DataFlow:: Node getValueArg ( ) { result = this .getArgByName ( "value" ) }
161+ override DataFlow:: Node getValueArg ( ) {
162+ result in [ this .getArg ( 1 ) , this .getArgByName ( "value" ) ]
163+ }
115164
116165 override predicate isSecure ( ) {
117166 DataFlow:: exprNode ( any ( True t ) )
118167 .( DataFlow:: LocalSourceNode )
119- .flowsTo ( this .getArgByName ( "secure" ) )
168+ .flowsTo ( this .( DataFlow :: CallCfgNode ) . getArgByName ( "secure" ) )
120169 }
121170
122171 override predicate isHttpOnly ( ) {
123172 DataFlow:: exprNode ( any ( True t ) )
124173 .( DataFlow:: LocalSourceNode )
125- .flowsTo ( this .getArgByName ( "httponly" ) )
174+ .flowsTo ( this .( DataFlow :: CallCfgNode ) . getArgByName ( "httponly" ) )
126175 }
127176
128177 override predicate isSameSite ( ) {
129- this .getArgByName ( "samesite" ) .asExpr ( ) .( Str_ ) .getS ( ) in [ "Strict" , "Lax" ]
178+ this .( DataFlow:: CallCfgNode ) .getArgByName ( "samesite" ) .asExpr ( ) .( Str_ ) .getS ( ) in [
179+ "Strict" , "Lax"
180+ ]
130181 }
131182
132183 override DataFlow:: Node getHeaderArg ( ) { none ( ) }
0 commit comments