44 */
55
66private import python
7+ private import semmle.python.dataflow.new.DataFlow
78private import semmle.python.Concepts
89private import semmle.python.ApiGraphs
910private import semmle.python.dataflow.new.RemoteFlowSources
1011private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
12+ private import semmle.python.frameworks.Stdlib
13+ private import semmle.python.dataflow.new.RemoteFlowSources
1114
1215/**
1316 * INTERNAL: Do not use.
@@ -21,11 +24,65 @@ module Bottle {
2124
2225 /** Provides models for the `bottle` module. */
2326 module BottleModule {
27+ module App {
28+ API:: Node cls ( ) { result = API:: moduleImport ( "bottle" ) .getMember ( "Bottle" ) }
29+
30+ /** Gets a reference to a FastAPI application (an instance of `fastapi.FastAPI`). */
31+ API:: Node instance ( ) { result = cls ( ) .getReturn ( ) }
32+
33+ API:: Node app ( ) { result = bottle ( ) .getMember ( "app" ) .getReturn ( ) }
34+ }
35+
36+ /** Provides models for functions that are possible "views" */
37+ module View {
38+ /**
39+ * A Bottle view callable, that handles incoming requests.
40+ */
41+ class ViewCallable extends Function {
42+ ViewCallable ( ) { this = any ( BottleRouteSetup rs ) .getARequestHandler ( ) }
43+ }
44+
45+ private class BottleRouteSetup extends Http:: Server:: RouteSetup:: Range , DataFlow:: CallCfgNode {
46+ BottleRouteSetup ( ) {
47+ this =
48+ [
49+ App:: instance ( )
50+ .getMember ( [ "route" , "get" , "post" , "put" , "delete" , "patch" ] )
51+ .getACall ( ) ,
52+ App:: app ( ) .getMember ( [ "route" , "get" , "post" , "put" , "delete" , "patch" ] ) .getACall ( ) ,
53+ bottle ( ) .getMember ( [ "route" , "get" , "post" , "put" , "delete" , "patch" ] ) .getACall ( )
54+ ]
55+ }
56+
57+ override DataFlow:: Node getUrlPatternArg ( ) {
58+ result in [ this .getArg ( 0 ) , this .getArgByName ( "route" ) ]
59+ }
60+
61+ override string getFramework ( ) { result = "Bottle" }
62+
63+ override Parameter getARoutedParameter ( ) { none ( ) }
64+
65+ override Function getARequestHandler ( ) { result .getADecorator ( ) .getAFlowNode ( ) = node }
66+ }
67+ }
68+
2469 /** Provides models for the `bottle.response` module */
2570 module Response {
2671 /** Gets a reference to the `bottle.response` module. */
2772 API:: Node response ( ) { result = bottle ( ) .getMember ( "response" ) }
2873
74+ class BottleReturnResponse extends Http:: Server:: HttpResponse:: Range {
75+ BottleReturnResponse ( ) {
76+ this .asCfgNode ( ) = any ( View:: ViewCallable vc ) .getAReturnValueFlowNode ( )
77+ }
78+
79+ override DataFlow:: Node getBody ( ) { result = this }
80+
81+ override DataFlow:: Node getMimetypeOrContentTypeArg ( ) { none ( ) }
82+
83+ override string getMimetypeDefault ( ) { result = "text/html" }
84+ }
85+
2986 /**
3087 * A call to the `bottle.BaseResponse.set_header` or `bottle.BaseResponse.add_header` method.
3188 *
@@ -50,66 +107,68 @@ module Bottle {
50107
51108 override predicate valueAllowsNewline ( ) { none ( ) }
52109 }
110+ }
53111
54- /** Provides models for the `bottle.request` module */
55- module Request {
56- /** Gets a reference to the `bottle.request` module. */
57- API:: Node request ( ) { result = bottle ( ) .getMember ( "request" ) }
58-
59- private class Request extends RemoteFlowSource:: Range {
60- Request ( ) { this = request ( ) .asSource ( ) }
61-
62- override string getSourceType ( ) { result = "bottle.request" }
63- }
112+ /** Provides models for the `bottle.request` module */
113+ module Request {
114+ /** Gets a reference to the `bottle.request` module. */
115+ API:: Node request ( ) { result = bottle ( ) .getMember ( "request" ) }
64116
65- /**
66- * Taint propagation for `bottle.request`.
67- *
68- * See https://bottlepy.org/docs/dev/api.html#bottle.request
69- */
70- private class InstanceTaintSteps extends InstanceTaintStepsHelper {
71- InstanceTaintSteps ( ) { this = "bottle.request" }
117+ private class Request extends RemoteFlowSource:: Range {
118+ Request ( ) { this = request ( ) .asSource ( ) }
72119
73- override DataFlow:: Node getInstance ( ) {
74- result = request ( ) .getAValueReachableFromSource ( )
75- }
120+ override string getSourceType ( ) { result = "bottle.request" }
121+ }
76122
77- override string getAttributeName ( ) {
78- result in [ "headers" , "query" , "forms" , "params" , "json" , "url" ]
79- }
123+ /**
124+ * Taint propagation for `bottle.request`.
125+ *
126+ * See https://bottlepy.org/docs/dev/api.html#bottle.request
127+ */
128+ private class InstanceTaintSteps extends InstanceTaintStepsHelper {
129+ InstanceTaintSteps ( ) { this = "bottle.request" }
80130
81- override string getMethodName ( ) { none ( ) }
131+ override DataFlow :: Node getInstance ( ) { result = request ( ) . getAValueReachableFromSource ( ) }
82132
83- override string getAsyncMethodName ( ) { none ( ) }
133+ override string getAttributeName ( ) {
134+ result in [
135+ "headers" , "query" , "forms" , "params" , "json" , "url" , "body" , "fullpath" ,
136+ "query_string"
137+ ]
84138 }
85- }
86139
87- /** Provides models for the `bottle.headers` module */
88- module Headers {
89- /** Gets a reference to the `bottle.headers` module. */
90- API:: Node headers ( ) { result = bottle ( ) .getMember ( "response" ) .getMember ( "headers" ) }
140+ override string getMethodName ( ) { none ( ) }
91141
92- /** A dict-like write to a response header. */
93- class HeaderWriteSubscript extends Http:: Server:: ResponseHeaderWrite:: Range , DataFlow:: Node {
94- API:: Node name ;
95- API:: Node value ;
142+ override string getAsyncMethodName ( ) { none ( ) }
143+ }
144+ }
96145
97- HeaderWriteSubscript ( ) {
98- exists ( API:: Node holder |
99- holder = headers ( ) and
100- this = holder .asSource ( ) and
101- value = holder .getSubscriptAt ( name )
102- )
103- }
146+ /** Provides models for the `bottle.headers` module */
147+ module Headers {
148+ /** Gets a reference to the `bottle.headers` module. */
149+ API:: Node headers ( ) { result = bottle ( ) .getMember ( "response" ) .getMember ( "headers" ) }
150+
151+ /** A dict-like write to a response header. */
152+ class HeaderWriteSubscript extends Http:: Server:: ResponseHeaderWrite:: Range , DataFlow:: Node {
153+ DataFlow:: Node name ;
154+ DataFlow:: Node value ;
155+
156+ HeaderWriteSubscript ( ) {
157+ exists ( SubscriptNode subscript |
158+ this .asCfgNode ( ) = subscript and
159+ value .asCfgNode ( ) = subscript .( DefinitionNode ) .getValue ( ) and
160+ name .asCfgNode ( ) = subscript .getIndex ( ) and
161+ subscript .getObject ( ) = headers ( ) .asSource ( ) .asCfgNode ( )
162+ )
163+ }
104164
105- override DataFlow:: Node getNameArg ( ) { result = name . asSink ( ) }
165+ override DataFlow:: Node getNameArg ( ) { result = name }
106166
107- override DataFlow:: Node getValueArg ( ) { result = value . asSink ( ) }
167+ override DataFlow:: Node getValueArg ( ) { result = value }
108168
109- override predicate nameAllowsNewline ( ) { none ( ) }
169+ override predicate nameAllowsNewline ( ) { none ( ) }
110170
111- override predicate valueAllowsNewline ( ) { none ( ) }
112- }
171+ override predicate valueAllowsNewline ( ) { none ( ) }
113172 }
114173 }
115174 }
0 commit comments