Skip to content

Commit aab0a24

Browse files
committed
Python: Add redirects to bottle framework support.
1 parent d514fc5 commit aab0a24

File tree

8 files changed

+67
-1
lines changed

8 files changed

+67
-1
lines changed

change-notes/1.20/analysis-python.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@ Removes false positives seen when using Python 3.6, but not when using earlier v
3535
## Changes to QL libraries
3636

3737
* Added support for the `dill` pickle library.
38+
* Added support for the bottle web framework.
39+

python/ql/src/semmle/python/web/HttpRedirect.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ import semmle.python.web.django.Redirect
66
import semmle.python.web.flask.Redirect
77
import semmle.python.web.tornado.Redirect
88
import semmle.python.web.pyramid.Redirect
9+
import semmle.python.web.bottle.Redirect
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/** Provides class representing the `bottle.redirect` function.
2+
* This module is intended to be imported into a taint-tracking query
3+
* to extend `TaintSink`.
4+
*/
5+
import python
6+
7+
import semmle.python.security.TaintTracking
8+
import semmle.python.security.strings.Basic
9+
import semmle.python.web.bottle.General
10+
11+
FunctionObject bottle_redirect() {
12+
result = theBottleModule().getAttribute("redirect")
13+
}
14+
15+
/**
16+
* Represents an argument to the `bottle.redirect` function.
17+
*/
18+
class BottleRedirect extends TaintSink {
19+
20+
override string toString() {
21+
result = "bottle.redirect"
22+
}
23+
24+
BottleRedirect() {
25+
exists(CallNode call |
26+
bottle_redirect().getACall() = call and
27+
this = call.getAnArg()
28+
)
29+
}
30+
31+
override predicate sinks(TaintKind kind) {
32+
kind instanceof StringKind
33+
}
34+
35+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
| /args | test.py:31:1:31:14 | Function unsafe2 |
12
| /bye/<name> | test.py:12:1:12:25 | Function bye |
23
| /hello/<name> | test.py:8:1:8:27 | Function hello |
34
| /other | test.py:17:1:17:12 | Function other |
5+
| /wrong/<where> | test.py:27:1:27:31 | Function unsafe |
6+
| /wrong/url | test.py:23:1:23:11 | Function safe |

python/ql/test/library-tests/web/bottle/Sources.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@
55
| test.py:8 | name | externally controlled string |
66
| test.py:12 | name | externally controlled string |
77
| test.py:18 | request | bottle.request |
8+
| test.py:27 | where | externally controlled string |
9+
| test.py:32 | request | bottle.request |

python/ql/test/library-tests/web/bottle/Taint.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
| ../../../query-tests/Security/lib/bottle.py:64 | LocalRequest() | bottle.request |
22
| ../../../query-tests/Security/lib/bottle.py:64 | request | bottle.request |
3+
| ../../../query-tests/Security/lib/bottle.py:68 | url | externally controlled string |
34
| test.py:3 | ImportMember | bottle.request |
45
| test.py:3 | request | bottle.request |
56
| test.py:8 | name | externally controlled string |
@@ -13,3 +14,8 @@
1314
| test.py:18 | request | bottle.request |
1415
| test.py:19 | BinaryExpr | externally controlled string |
1516
| test.py:19 | name | externally controlled string |
17+
| test.py:27 | where | externally controlled string |
18+
| test.py:28 | where | externally controlled string |
19+
| test.py:32 | Attribute | bottle.FormsDict |
20+
| test.py:32 | Attribute | externally controlled string |
21+
| test.py:32 | request | bottle.request |

python/ql/test/library-tests/web/bottle/test.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22

3-
from bottle import Bottle, route, request
3+
from bottle import Bottle, route, request, redirect
44

55
app = Bottle()
66

@@ -17,3 +17,16 @@ def bye(name = "World!"):
1717
def other():
1818
name = request.cookies.username
1919
return "User name is " + name
20+
21+
22+
@route('/wrong/url')
23+
def safe():
24+
redirect("/right/url")
25+
26+
@route('/wrong/<where>')
27+
def unsafe(where="/right/url"):
28+
redirect(where)
29+
30+
@route('/args')
31+
def unsafe2():
32+
redirect(request.query.where, code)

python/ql/test/query-tests/Security/lib/bottle.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,7 @@ class LocalResponse(LocalProxy):
6464
request = LocalRequest()
6565
response = LocalResponse()
6666

67+
68+
def redirect(url, code=None):
69+
pass
70+

0 commit comments

Comments
 (0)