-
Notifications
You must be signed in to change notification settings - Fork 2k
Python: Model flask_admin
#7033
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
c2632cf
Python: Add RequestHandler meta query
RasmusWL ab88d94
Python: Add `flask_admin` tests
RasmusWL 8cd9fde
Python: Model `flask_admin`
RasmusWL 99081ea
Python: Minor adjustment in QLDoc
RasmusWL 860b1a5
Python: Other minor QLDoc adjustment
RasmusWL File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| lgtm,codescanning | ||
| * Added modeling of HTTP requests and responses when using `flask_admin` (`Flask-Admin` PyPI package), which leads to additional remote flow sources. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| /** | ||
| * Provides classes modeling security-relevant aspects of the `Flask-Admin` PyPI package | ||
| * (imported as `flask_admin`). | ||
| * | ||
| * See | ||
| * - https://flask-admin.readthedocs.io/en/latest/ | ||
| * - https://pypi.org/project/Flask-Admin/ | ||
| */ | ||
|
|
||
| private import python | ||
| private import semmle.python.dataflow.new.DataFlow | ||
| private import semmle.python.dataflow.new.RemoteFlowSources | ||
| private import semmle.python.dataflow.new.TaintTracking | ||
| private import semmle.python.Concepts | ||
| private import semmle.python.frameworks.Flask | ||
| private import semmle.python.ApiGraphs | ||
|
|
||
| /** | ||
| * Provides models for the `Flask-Admin` PyPI package (imported as `flask_admin`). | ||
| * | ||
| * See | ||
| * - https://flask-admin.readthedocs.io/en/latest/ | ||
| * - https://pypi.org/project/Flask-Admin/ | ||
| */ | ||
| private module FlaskAdmin { | ||
| /** | ||
| * A call to `flask_admin.expose`, which is used as a decorator to make the | ||
| * function exposed in the admin interface (and make it a request handler) | ||
| * | ||
| * See https://flask-admin.readthedocs.io/en/latest/api/mod_base/#flask_admin.base.expose | ||
| */ | ||
| private class FlaskAdminExposeCall extends Flask::FlaskRouteSetup, DataFlow::CallCfgNode { | ||
| FlaskAdminExposeCall() { | ||
| this = API::moduleImport("flask_admin").getMember("expose").getACall() | ||
| } | ||
|
|
||
| override DataFlow::Node getUrlPatternArg() { | ||
| result in [this.getArg(0), this.getArgByName("url")] | ||
| } | ||
|
|
||
| override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node } | ||
| } | ||
|
|
||
| /** | ||
| * A call to `flask_admin.expose_plugview`, which is used as a decorator to make the | ||
| * class (which we expect to be a flask View class) exposed in the admin interface. | ||
| * | ||
| * See https://flask-admin.readthedocs.io/en/latest/api/mod_base/#flask_admin.base.expose_plugview | ||
| */ | ||
| private class FlaskAdminExposePlugviewCall extends Flask::FlaskRouteSetup, DataFlow::CallCfgNode { | ||
| FlaskAdminExposePlugviewCall() { | ||
| this = API::moduleImport("flask_admin").getMember("expose_plugview").getACall() | ||
| } | ||
|
|
||
| override DataFlow::Node getUrlPatternArg() { | ||
| result in [this.getArg(0), this.getArgByName("url")] | ||
| } | ||
|
|
||
| override Parameter getARoutedParameter() { | ||
| result = super.getARoutedParameter() and | ||
| ( | ||
| exists(this.getUrlPattern()) | ||
| or | ||
| // the first argument is `self`, and the second argument `cls` will receive the | ||
| // containing flask_admin View class -- this is only relevant if the URL pattern | ||
| // is not known | ||
| not exists(this.getUrlPattern()) and | ||
| not result = this.getARequestHandler().getArg([0, 1]) | ||
| ) | ||
| } | ||
|
|
||
| override Function getARequestHandler() { | ||
| exists(Flask::FlaskViewClass cls | | ||
| cls.getADecorator().getAFlowNode() = node and | ||
| result = cls.getARequestHandler() | ||
| ) | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| /** | ||
| * @name Request Handlers | ||
| * @description HTTP Server Request Handlers | ||
| * @kind problem | ||
| * @problem.severity recommendation | ||
| * @id py/meta/alerts/request-handlers | ||
| * @tags meta | ||
| * @precision very-low | ||
| */ | ||
|
|
||
| private import python | ||
| private import semmle.python.dataflow.new.DataFlow | ||
| private import semmle.python.Concepts | ||
| private import meta.MetaMetrics | ||
|
|
||
| from HTTP::Server::RequestHandler requestHandler, string title | ||
| where | ||
| not requestHandler.getLocation().getFile() instanceof IgnoredFile and | ||
| if requestHandler.isMethod() | ||
| then | ||
| title = "Method " + requestHandler.getScope().(Class).getName() + "." + requestHandler.getName() | ||
| else title = requestHandler.toString() | ||
| select requestHandler, "RequestHandler: " + title | ||
Empty file.
12 changes: 12 additions & 0 deletions
12
python/ql/test/library-tests/frameworks/flask_admin/ConceptsTest.ql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| import python | ||
| import experimental.meta.ConceptsTest | ||
|
|
||
| class DedicatedResponseTest extends HttpServerHttpResponseTest { | ||
| DedicatedResponseTest() { file.getShortName() = "response_test.py" } | ||
| } | ||
|
|
||
| class OtherResponseTest extends HttpServerHttpResponseTest { | ||
| OtherResponseTest() { not this instanceof DedicatedResponseTest } | ||
|
|
||
| override string getARelevantTag() { result = "HttpResponse" } | ||
| } |
3 changes: 3 additions & 0 deletions
3
python/ql/test/library-tests/frameworks/flask_admin/InlineTaintTest.expected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| argumentToEnsureNotTaintedNotMarkedAsSpurious | ||
| untaintedArgumentToEnsureTaintedNotMarkedAsMissing | ||
| failures |
1 change: 1 addition & 0 deletions
1
python/ql/test/library-tests/frameworks/flask_admin/InlineTaintTest.ql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| import experimental.meta.InlineTaintTest |
58 changes: 58 additions & 0 deletions
58
python/ql/test/library-tests/frameworks/flask_admin/test.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| from flask import Flask, redirect | ||
| from flask.views import MethodView | ||
| import flask_admin | ||
|
|
||
| ensure_tainted = ensure_not_tainted = print | ||
|
|
||
|
|
||
| app = Flask(__name__) | ||
|
|
||
| # unknown at least for our current analysis | ||
| foo = "'/foo'" | ||
| UNKNOWN_ROUTE = eval(foo) # $ getCode=foo | ||
|
|
||
|
|
||
| class ExampleClass(flask_admin.BaseView): | ||
| @flask_admin.expose('/') # $ routeSetup="/" | ||
| def foo(self): # $ requestHandler | ||
| return "foo" # $ HttpResponse | ||
|
|
||
| @flask_admin.expose(url='/bar/<arg>') # $ routeSetup="/bar/<arg>" | ||
| def bar(self, arg): # $ requestHandler routedParameter=arg | ||
| ensure_tainted(arg) # $ tainted | ||
| return "bar: " + arg # $ HttpResponse | ||
|
|
||
| @flask_admin.expose_plugview("/flask-class") # $ routeSetup="/flask-class" | ||
| @flask_admin.expose_plugview(url="/flask-class/<arg>") # $ routeSetup="/flask-class/<arg>" | ||
| class Nested(MethodView): | ||
| def get(self, cls, arg="default"): # $ requestHandler routedParameter=arg | ||
| assert isinstance(cls, ExampleClass) | ||
| ensure_tainted(arg) # $ tainted | ||
| ensure_not_tainted(cls) | ||
| return "GET: " + arg # $ HttpResponse | ||
|
|
||
| def post(self, cls, arg): # $ requestHandler routedParameter=arg | ||
| assert isinstance(cls, ExampleClass) | ||
| ensure_tainted(arg) # $ tainted | ||
| ensure_not_tainted(cls) | ||
| return "POST: " + arg # $ HttpResponse | ||
|
|
||
| @flask_admin.expose_plugview(UNKNOWN_ROUTE) # $ routeSetup | ||
| class WithUnknownRoute(MethodView): | ||
| def get(self, cls, maybeRouted): # $ requestHandler routedParameter=maybeRouted | ||
| ensure_tainted(maybeRouted) # $ tainted | ||
| ensure_not_tainted(cls) | ||
| return "ok" # $ HttpResponse | ||
|
|
||
|
|
||
| @app.route('/') # $ routeSetup="/" | ||
| def index(): # $ requestHandler | ||
| return redirect('/admin') # $ HttpRedirectResponse HttpResponse redirectLocation='/admin' | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| admin = flask_admin.Admin(app, name="Some Admin Interface") | ||
| admin.add_view(ExampleClass()) | ||
|
|
||
| print(app.url_map) | ||
| app.run(debug=True) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.