mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
Python: Port taint tests to use inline expectations
The meat of this PR is described in the new python/ql/test/experimental/meta/InlineTaintTest.qll file: > Defines a InlineExpectationsTest for checking whether any arguments in > `ensure_tainted` and `ensure_not_tainted` calls are tainted. > > Also defines query predicates to ensure that: > - if any arguments to `ensure_not_tainted` are tainted, their annotation is marked with `SPURIOUS`. > - if any arguments to `ensure_tainted` are not tainted, their annotation is marked with `MISSING`. > > The functionality of this module is tested in `ql/test/experimental/meta/inline-taint-test-demo`.
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
@@ -0,0 +1 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
@@ -1,100 +0,0 @@
|
||||
| response_test.py:61 | ok | get_redirect_url | foo |
|
||||
| taint_forms.py:6 | ok | to_python | value |
|
||||
| taint_forms.py:9 | ok | validate | value |
|
||||
| taint_forms.py:12 | ok | run_validators | value |
|
||||
| taint_forms.py:15 | ok | clean | value |
|
||||
| taint_forms.py:33 | ok | clean | cleaned_data |
|
||||
| taint_forms.py:34 | ok | clean | cleaned_data["key"] |
|
||||
| taint_forms.py:35 | ok | clean | cleaned_data.get(..) |
|
||||
| taint_forms.py:39 | ok | clean | self.cleaned_data |
|
||||
| taint_forms.py:40 | ok | clean | self.cleaned_data["key"] |
|
||||
| taint_forms.py:41 | ok | clean | self.cleaned_data.get(..) |
|
||||
| taint_forms.py:46 | ok | clean_foo | self.cleaned_data |
|
||||
| taint_test.py:8 | ok | test_taint | bar |
|
||||
| taint_test.py:8 | ok | test_taint | foo |
|
||||
| taint_test.py:9 | ok | test_taint | baz |
|
||||
| taint_test.py:15 | ok | test_taint | request |
|
||||
| taint_test.py:17 | ok | test_taint | request.body |
|
||||
| taint_test.py:18 | ok | test_taint | request.path |
|
||||
| taint_test.py:19 | ok | test_taint | request.path_info |
|
||||
| taint_test.py:23 | ok | test_taint | request.method |
|
||||
| taint_test.py:25 | ok | test_taint | request.encoding |
|
||||
| taint_test.py:26 | ok | test_taint | request.content_type |
|
||||
| taint_test.py:29 | ok | test_taint | request.content_params |
|
||||
| taint_test.py:30 | ok | test_taint | request.content_params["key"] |
|
||||
| taint_test.py:31 | ok | test_taint | request.content_params.get(..) |
|
||||
| taint_test.py:35 | ok | test_taint | request.GET |
|
||||
| taint_test.py:36 | ok | test_taint | request.GET["key"] |
|
||||
| taint_test.py:37 | ok | test_taint | request.GET.get(..) |
|
||||
| taint_test.py:38 | fail | test_taint | request.GET.getlist(..) |
|
||||
| taint_test.py:39 | fail | test_taint | request.GET.getlist(..)[0] |
|
||||
| taint_test.py:40 | ok | test_taint | request.GET.pop(..) |
|
||||
| taint_test.py:41 | ok | test_taint | request.GET.pop(..)[0] |
|
||||
| taint_test.py:42 | ok | test_taint | request.GET.popitem()[0] |
|
||||
| taint_test.py:43 | ok | test_taint | request.GET.popitem()[1] |
|
||||
| taint_test.py:44 | ok | test_taint | request.GET.popitem()[1][0] |
|
||||
| taint_test.py:45 | fail | test_taint | request.GET.dict() |
|
||||
| taint_test.py:46 | fail | test_taint | request.GET.dict()["key"] |
|
||||
| taint_test.py:47 | fail | test_taint | request.GET.urlencode() |
|
||||
| taint_test.py:50 | ok | test_taint | request.POST |
|
||||
| taint_test.py:53 | ok | test_taint | request.COOKIES |
|
||||
| taint_test.py:54 | ok | test_taint | request.COOKIES["key"] |
|
||||
| taint_test.py:55 | ok | test_taint | request.COOKIES.get(..) |
|
||||
| taint_test.py:58 | ok | test_taint | request.FILES |
|
||||
| taint_test.py:59 | ok | test_taint | request.FILES["key"] |
|
||||
| taint_test.py:60 | fail | test_taint | request.FILES["key"].content_type |
|
||||
| taint_test.py:61 | fail | test_taint | request.FILES["key"].content_type_extra |
|
||||
| taint_test.py:62 | fail | test_taint | request.FILES["key"].content_type_extra["key"] |
|
||||
| taint_test.py:63 | fail | test_taint | request.FILES["key"].charset |
|
||||
| taint_test.py:64 | fail | test_taint | request.FILES["key"].name |
|
||||
| taint_test.py:65 | fail | test_taint | request.FILES["key"].file |
|
||||
| taint_test.py:66 | fail | test_taint | request.FILES["key"].file.read() |
|
||||
| taint_test.py:68 | ok | test_taint | request.FILES.get(..) |
|
||||
| taint_test.py:69 | fail | test_taint | request.FILES.get(..).name |
|
||||
| taint_test.py:70 | fail | test_taint | request.FILES.getlist(..) |
|
||||
| taint_test.py:71 | fail | test_taint | request.FILES.getlist(..)[0] |
|
||||
| taint_test.py:72 | fail | test_taint | request.FILES.getlist(..)[0].name |
|
||||
| taint_test.py:73 | fail | test_taint | request.FILES.dict() |
|
||||
| taint_test.py:74 | fail | test_taint | request.FILES.dict()["key"] |
|
||||
| taint_test.py:75 | fail | test_taint | request.FILES.dict()["key"].name |
|
||||
| taint_test.py:78 | ok | test_taint | request.META |
|
||||
| taint_test.py:79 | ok | test_taint | request.META["HTTP_USER_AGENT"] |
|
||||
| taint_test.py:80 | ok | test_taint | request.META.get(..) |
|
||||
| taint_test.py:83 | ok | test_taint | request.headers |
|
||||
| taint_test.py:84 | ok | test_taint | request.headers["user-agent"] |
|
||||
| taint_test.py:85 | ok | test_taint | request.headers["USER_AGENT"] |
|
||||
| taint_test.py:88 | ok | test_taint | request.resolver_match |
|
||||
| taint_test.py:89 | fail | test_taint | request.resolver_match.args |
|
||||
| taint_test.py:90 | fail | test_taint | request.resolver_match.args[0] |
|
||||
| taint_test.py:91 | fail | test_taint | request.resolver_match.kwargs |
|
||||
| taint_test.py:92 | fail | test_taint | request.resolver_match.kwargs["key"] |
|
||||
| taint_test.py:94 | fail | test_taint | request.get_full_path() |
|
||||
| taint_test.py:95 | fail | test_taint | request.get_full_path_info() |
|
||||
| taint_test.py:99 | fail | test_taint | request.read() |
|
||||
| taint_test.py:100 | fail | test_taint | request.readline() |
|
||||
| taint_test.py:101 | fail | test_taint | request.readlines() |
|
||||
| taint_test.py:102 | fail | test_taint | request.readlines()[0] |
|
||||
| taint_test.py:103 | fail | test_taint | ListComp |
|
||||
| taint_test.py:109 | ok | test_taint | args |
|
||||
| taint_test.py:110 | ok | test_taint | args[0] |
|
||||
| taint_test.py:111 | ok | test_taint | kwargs |
|
||||
| taint_test.py:112 | ok | test_taint | kwargs["key"] |
|
||||
| taint_test.py:116 | ok | test_taint | request.current_app |
|
||||
| taint_test.py:121 | ok | test_taint | request.get_host() |
|
||||
| taint_test.py:122 | ok | test_taint | request.get_port() |
|
||||
| taint_test.py:129 | fail | test_taint | request.build_absolute_uri() |
|
||||
| taint_test.py:130 | fail | test_taint | request.build_absolute_uri(..) |
|
||||
| taint_test.py:131 | fail | test_taint | request.build_absolute_uri(..) |
|
||||
| taint_test.py:134 | ok | test_taint | request.build_absolute_uri(..) |
|
||||
| taint_test.py:135 | ok | test_taint | request.build_absolute_uri(..) |
|
||||
| taint_test.py:143 | ok | test_taint | request.get_signed_cookie(..) |
|
||||
| taint_test.py:144 | ok | test_taint | request.get_signed_cookie(..) |
|
||||
| taint_test.py:145 | ok | test_taint | request.get_signed_cookie(..) |
|
||||
| taint_test.py:149 | fail | test_taint | request.get_signed_cookie(..) |
|
||||
| taint_test.py:150 | fail | test_taint | request.get_signed_cookie(..) |
|
||||
| taint_test.py:157 | ok | some_method | self.request |
|
||||
| taint_test.py:158 | ok | some_method | self.request.GET["key"] |
|
||||
| taint_test.py:160 | ok | some_method | self.args |
|
||||
| taint_test.py:161 | ok | some_method | self.args[0] |
|
||||
| taint_test.py:163 | ok | some_method | self.kwargs |
|
||||
| taint_test.py:164 | ok | some_method | self.kwargs["key"] |
|
||||
@@ -1,6 +0,0 @@
|
||||
import experimental.dataflow.tainttracking.TestTaintLib
|
||||
import semmle.python.dataflow.new.RemoteFlowSources
|
||||
|
||||
class RemoteFlowTestTaintConfiguration extends TestTaintTrackingConfiguration {
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
}
|
||||
@@ -58,7 +58,7 @@ def redirect_shortcut(request):
|
||||
class CustomRedirectView(RedirectView):
|
||||
|
||||
def get_redirect_url(self, foo): # $ requestHandler routedParameter=foo
|
||||
ensure_tainted(foo)
|
||||
ensure_tainted(foo) # $ tainted
|
||||
next = "https://example.com/{}".format(foo)
|
||||
return next # $ HttpResponse HttpRedirectResponse redirectLocation=next
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@ import django.forms
|
||||
|
||||
class MyField(django.forms.Field):
|
||||
def to_python(self, value):
|
||||
ensure_tainted(value)
|
||||
ensure_tainted(value) # $ tainted
|
||||
|
||||
def validate(self, value):
|
||||
ensure_tainted(value)
|
||||
ensure_tainted(value) # $ tainted
|
||||
|
||||
def run_validators(self, value):
|
||||
ensure_tainted(value)
|
||||
ensure_tainted(value) # $ tainted
|
||||
|
||||
def clean(self, value):
|
||||
ensure_tainted(value)
|
||||
ensure_tainted(value) # $ tainted
|
||||
|
||||
# # Base definition of `clean` looks like the following, so there is actually
|
||||
# # _data flow_ from the methods, but we will ignore for simplicity.
|
||||
@@ -30,17 +30,17 @@ class MyForm(django.forms.Form):
|
||||
cleaned_data = super().clean()
|
||||
|
||||
ensure_tainted(
|
||||
cleaned_data,
|
||||
cleaned_data["key"],
|
||||
cleaned_data.get("key"),
|
||||
cleaned_data, # $ tainted
|
||||
cleaned_data["key"], # $ tainted
|
||||
cleaned_data.get("key"), # $ tainted
|
||||
)
|
||||
|
||||
ensure_tainted(
|
||||
self.cleaned_data,
|
||||
self.cleaned_data["key"],
|
||||
self.cleaned_data.get("key"),
|
||||
self.cleaned_data, # $ tainted
|
||||
self.cleaned_data["key"], # $ tainted
|
||||
self.cleaned_data.get("key"), # $ tainted
|
||||
)
|
||||
|
||||
def clean_foo(self):
|
||||
# This method is supposed to clean the `foo` field in context of this form.
|
||||
ensure_tainted(self.cleaned_data)
|
||||
ensure_tainted(self.cleaned_data) # $ tainted
|
||||
|
||||
@@ -5,111 +5,114 @@ from django.views import View
|
||||
|
||||
|
||||
def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler routedParameter=foo routedParameter=bar
|
||||
ensure_tainted(foo, bar)
|
||||
ensure_tainted(foo, bar) # $ tainted
|
||||
ensure_not_tainted(baz)
|
||||
|
||||
# Manually inspected all fields of the HttpRequest object
|
||||
# https://docs.djangoproject.com/en/3.0/ref/request-response/#httprequest-objects
|
||||
|
||||
ensure_tainted(
|
||||
request,
|
||||
request, # $ tainted
|
||||
|
||||
request.body,
|
||||
request.path,
|
||||
request.path_info,
|
||||
request.body, # $ tainted
|
||||
request.path, # $ tainted
|
||||
request.path_info, # $ tainted
|
||||
|
||||
# With CSRF middleware disabled, it's possible to use custom methods,
|
||||
# for example by `curl -X FOO <url>`
|
||||
request.method,
|
||||
request.method, # $ tainted
|
||||
|
||||
request.encoding,
|
||||
request.content_type,
|
||||
request.encoding, # $ tainted
|
||||
request.content_type, # $ tainted
|
||||
|
||||
# Dict[str, str]
|
||||
request.content_params,
|
||||
request.content_params["key"],
|
||||
request.content_params.get("key"),
|
||||
request.content_params, # $ tainted
|
||||
request.content_params["key"], # $ tainted
|
||||
request.content_params.get("key"), # $ tainted
|
||||
|
||||
# django.http.QueryDict
|
||||
# see https://docs.djangoproject.com/en/3.0/ref/request-response/#querydict-objects
|
||||
request.GET,
|
||||
request.GET["key"],
|
||||
request.GET.get("key"),
|
||||
request.GET.getlist("key"),
|
||||
request.GET.getlist("key")[0],
|
||||
request.GET.pop("key"),
|
||||
request.GET.pop("key")[0],
|
||||
request.GET.popitem()[0], # key
|
||||
request.GET.popitem()[1], # values
|
||||
request.GET.popitem()[1][0], # values[0]
|
||||
request.GET.dict(),
|
||||
request.GET.dict()["key"],
|
||||
request.GET.urlencode(),
|
||||
request.GET, # $ tainted
|
||||
request.GET["key"], # $ tainted
|
||||
request.GET.get("key"), # $ tainted
|
||||
request.GET.getlist("key"), # $ MISSING: tainted
|
||||
request.GET.getlist("key")[0], # $ MISSING: tainted
|
||||
request.GET.pop("key"), # $ tainted
|
||||
request.GET.pop("key")[0], # $ tainted
|
||||
# key
|
||||
request.GET.popitem()[0], # $ tainted
|
||||
# values
|
||||
request.GET.popitem()[1], # $ tainted
|
||||
# values[0]
|
||||
request.GET.popitem()[1][0], # $ tainted
|
||||
request.GET.dict(), # $ MISSING: tainted
|
||||
request.GET.dict()["key"], # $ MISSING: tainted
|
||||
request.GET.urlencode(), # $ MISSING: tainted
|
||||
|
||||
# django.http.QueryDict (same as above, did not duplicate tests)
|
||||
request.POST,
|
||||
request.POST, # $ tainted
|
||||
|
||||
# Dict[str, str]
|
||||
request.COOKIES,
|
||||
request.COOKIES["key"],
|
||||
request.COOKIES.get("key"),
|
||||
request.COOKIES, # $ tainted
|
||||
request.COOKIES["key"], # $ tainted
|
||||
request.COOKIES.get("key"), # $ tainted
|
||||
|
||||
# MultiValueDict[str, UploadedFile]
|
||||
request.FILES,
|
||||
request.FILES["key"],
|
||||
request.FILES["key"].content_type,
|
||||
request.FILES["key"].content_type_extra,
|
||||
request.FILES["key"].content_type_extra["key"],
|
||||
request.FILES["key"].charset,
|
||||
request.FILES["key"].name,
|
||||
request.FILES["key"].file,
|
||||
request.FILES["key"].file.read(),
|
||||
request.FILES, # $ tainted
|
||||
request.FILES["key"], # $ tainted
|
||||
request.FILES["key"].content_type, # $ MISSING: tainted
|
||||
request.FILES["key"].content_type_extra, # $ MISSING: tainted
|
||||
request.FILES["key"].content_type_extra["key"], # $ MISSING: tainted
|
||||
request.FILES["key"].charset, # $ MISSING: tainted
|
||||
request.FILES["key"].name, # $ MISSING: tainted
|
||||
request.FILES["key"].file, # $ MISSING: tainted
|
||||
request.FILES["key"].file.read(), # $ MISSING: tainted
|
||||
|
||||
request.FILES.get("key"),
|
||||
request.FILES.get("key").name,
|
||||
request.FILES.getlist("key"),
|
||||
request.FILES.getlist("key")[0],
|
||||
request.FILES.getlist("key")[0].name,
|
||||
request.FILES.dict(),
|
||||
request.FILES.dict()["key"],
|
||||
request.FILES.dict()["key"].name,
|
||||
request.FILES.get("key"), # $ tainted
|
||||
request.FILES.get("key").name, # $ MISSING: tainted
|
||||
request.FILES.getlist("key"), # $ MISSING: tainted
|
||||
request.FILES.getlist("key")[0], # $ MISSING: tainted
|
||||
request.FILES.getlist("key")[0].name, # $ MISSING: tainted
|
||||
request.FILES.dict(), # $ MISSING: tainted
|
||||
request.FILES.dict()["key"], # $ MISSING: tainted
|
||||
request.FILES.dict()["key"].name, # $ MISSING: tainted
|
||||
|
||||
# Dict[str, Any]
|
||||
request.META,
|
||||
request.META["HTTP_USER_AGENT"],
|
||||
request.META.get("HTTP_USER_AGENT"),
|
||||
request.META, # $ tainted
|
||||
request.META["HTTP_USER_AGENT"], # $ tainted
|
||||
request.META.get("HTTP_USER_AGENT"), # $ tainted
|
||||
|
||||
# HttpHeaders (case insensitive dict-like)
|
||||
request.headers,
|
||||
request.headers["user-agent"],
|
||||
request.headers["USER_AGENT"],
|
||||
request.headers, # $ tainted
|
||||
request.headers["user-agent"], # $ tainted
|
||||
request.headers["USER_AGENT"], # $ tainted
|
||||
|
||||
# django.urls.ResolverMatch
|
||||
request.resolver_match,
|
||||
request.resolver_match.args,
|
||||
request.resolver_match.args[0],
|
||||
request.resolver_match.kwargs,
|
||||
request.resolver_match.kwargs["key"],
|
||||
request.resolver_match, # $ tainted
|
||||
request.resolver_match.args, # $ MISSING: tainted
|
||||
request.resolver_match.args[0], # $ MISSING: tainted
|
||||
request.resolver_match.kwargs, # $ MISSING: tainted
|
||||
request.resolver_match.kwargs["key"], # $ MISSING: tainted
|
||||
|
||||
request.get_full_path(),
|
||||
request.get_full_path_info(),
|
||||
request.get_full_path(), # $ MISSING: tainted
|
||||
request.get_full_path_info(), # $ MISSING: tainted
|
||||
# build_absolute_uri handled below
|
||||
# get_signed_cookie handled below
|
||||
|
||||
request.read(),
|
||||
request.readline(),
|
||||
request.readlines(),
|
||||
request.readlines()[0],
|
||||
[line for line in request],
|
||||
request.read(), # $ MISSING: tainted
|
||||
request.readline(), # $ MISSING: tainted
|
||||
request.readlines(), # $ MISSING: tainted
|
||||
request.readlines()[0], # $ MISSING: tainted
|
||||
[line for line in request], # $ MISSING: tainted
|
||||
)
|
||||
|
||||
# django.urls.ResolverMatch also supports iterable unpacking
|
||||
_view, args, kwargs = request.resolver_match
|
||||
ensure_tainted(
|
||||
args,
|
||||
args[0],
|
||||
kwargs,
|
||||
kwargs["key"],
|
||||
args, # $ tainted
|
||||
args[0], # $ tainted
|
||||
kwargs, # $ tainted
|
||||
kwargs["key"], # $ tainted
|
||||
)
|
||||
|
||||
ensure_not_tainted(
|
||||
@@ -126,9 +129,9 @@ def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler rou
|
||||
# build_absolute_uri
|
||||
####################################
|
||||
ensure_tainted(
|
||||
request.build_absolute_uri(),
|
||||
request.build_absolute_uri(request.GET["key"]),
|
||||
request.build_absolute_uri(location=request.GET["key"]),
|
||||
request.build_absolute_uri(), # $ MISSING: tainted
|
||||
request.build_absolute_uri(request.GET["key"]), # $ MISSING: tainted
|
||||
request.build_absolute_uri(location=request.GET["key"]), # $ MISSING: tainted
|
||||
)
|
||||
ensure_not_tainted(
|
||||
request.build_absolute_uri("/hardcoded/"),
|
||||
@@ -146,22 +149,22 @@ def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler rou
|
||||
)
|
||||
# However, providing tainted default value might result in taint
|
||||
ensure_tainted(
|
||||
request.get_signed_cookie("key", request.COOKIES["key"]),
|
||||
request.get_signed_cookie("key", default=request.COOKIES["key"]),
|
||||
request.get_signed_cookie("key", request.COOKIES["key"]), # $ MISSING: tainted
|
||||
request.get_signed_cookie("key", default=request.COOKIES["key"]), # $ MISSING: tainted
|
||||
)
|
||||
|
||||
|
||||
class ClassView(View):
|
||||
def some_method(self):
|
||||
ensure_tainted(
|
||||
self.request,
|
||||
self.request.GET["key"],
|
||||
self.request, # $ tainted
|
||||
self.request.GET["key"], # $ tainted
|
||||
|
||||
self.args,
|
||||
self.args[0],
|
||||
self.args, # $ tainted
|
||||
self.args[0], # $ tainted
|
||||
|
||||
self.kwargs,
|
||||
self.kwargs["key"],
|
||||
self.kwargs, # $ tainted
|
||||
self.kwargs["key"], # $ tainted
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
@@ -0,0 +1 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
@@ -1,10 +0,0 @@
|
||||
| fabric_v1_execute.py:7 | fail | unsafe | cmd |
|
||||
| fabric_v1_execute.py:7 | fail | unsafe | cmd2 |
|
||||
| fabric_v1_execute.py:8 | ok | unsafe | safe_arg |
|
||||
| fabric_v1_execute.py:8 | ok | unsafe | safe_optional |
|
||||
| fabric_v1_execute.py:14 | fail | unsafe | cmd |
|
||||
| fabric_v1_execute.py:14 | fail | unsafe | cmd2 |
|
||||
| fabric_v1_execute.py:15 | ok | unsafe | safe_arg |
|
||||
| fabric_v1_execute.py:15 | ok | unsafe | safe_optional |
|
||||
| fabric_v1_execute.py:21 | ok | some_http_handler | cmd |
|
||||
| fabric_v1_execute.py:21 | ok | some_http_handler | cmd2 |
|
||||
@@ -1 +0,0 @@
|
||||
import experimental.dataflow.tainttracking.TestTaintLib
|
||||
@@ -4,21 +4,21 @@ from fabric.api import run, execute
|
||||
|
||||
|
||||
def unsafe(cmd, safe_arg, cmd2=None, safe_optional=5):
|
||||
ensure_tainted(cmd, cmd2)
|
||||
ensure_tainted(cmd, cmd2) # $ MISSING: tainted
|
||||
ensure_not_tainted(safe_arg, safe_optional)
|
||||
|
||||
|
||||
class Foo(object):
|
||||
|
||||
def unsafe(self, cmd, safe_arg, cmd2=None, safe_optional=5):
|
||||
ensure_tainted(cmd, cmd2)
|
||||
ensure_tainted(cmd, cmd2) # $ MISSING: tainted
|
||||
ensure_not_tainted(safe_arg, safe_optional)
|
||||
|
||||
|
||||
def some_http_handler():
|
||||
cmd = TAINTED_STRING
|
||||
cmd2 = TAINTED_STRING
|
||||
ensure_tainted(cmd, cmd2)
|
||||
ensure_tainted(cmd, cmd2) # $ tainted
|
||||
|
||||
execute(unsafe, cmd=cmd, safe_arg='safe_arg', cmd2=cmd2)
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
@@ -0,0 +1 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
@@ -1,98 +0,0 @@
|
||||
| taint_test.py:6 | ok | test_taint | name |
|
||||
| taint_test.py:6 | ok | test_taint | number |
|
||||
| taint_test.py:7 | ok | test_taint | foo |
|
||||
| taint_test.py:14 | ok | test_taint | request.environ |
|
||||
| taint_test.py:15 | ok | test_taint | request.environ.get(..) |
|
||||
| taint_test.py:17 | ok | test_taint | request.path |
|
||||
| taint_test.py:18 | ok | test_taint | request.full_path |
|
||||
| taint_test.py:19 | ok | test_taint | request.base_url |
|
||||
| taint_test.py:20 | ok | test_taint | request.url |
|
||||
| taint_test.py:23 | fail | test_taint | request.accept_charsets.best |
|
||||
| taint_test.py:24 | fail | test_taint | request.accept_charsets.best_match(..) |
|
||||
| taint_test.py:25 | ok | test_taint | request.accept_charsets[0] |
|
||||
| taint_test.py:26 | ok | test_taint | request.accept_encodings |
|
||||
| taint_test.py:27 | ok | test_taint | request.accept_languages |
|
||||
| taint_test.py:28 | ok | test_taint | request.accept_mimetypes |
|
||||
| taint_test.py:31 | ok | test_taint | request.access_control_request_headers |
|
||||
| taint_test.py:33 | ok | test_taint | request.access_control_request_method |
|
||||
| taint_test.py:35 | ok | test_taint | request.access_route |
|
||||
| taint_test.py:36 | ok | test_taint | request.access_route[0] |
|
||||
| taint_test.py:39 | ok | test_taint | request.args |
|
||||
| taint_test.py:40 | ok | test_taint | request.args['key'] |
|
||||
| taint_test.py:41 | ok | test_taint | request.args.getlist(..) |
|
||||
| taint_test.py:44 | ok | test_taint | request.authorization |
|
||||
| taint_test.py:45 | ok | test_taint | request.authorization['username'] |
|
||||
| taint_test.py:46 | fail | test_taint | request.authorization.username |
|
||||
| taint_test.py:49 | ok | test_taint | request.cache_control |
|
||||
| taint_test.py:51 | fail | test_taint | request.cache_control.max_age |
|
||||
| taint_test.py:52 | fail | test_taint | request.cache_control.max_stale |
|
||||
| taint_test.py:53 | fail | test_taint | request.cache_control.min_fresh |
|
||||
| taint_test.py:55 | ok | test_taint | request.content_encoding |
|
||||
| taint_test.py:57 | ok | test_taint | request.content_md5 |
|
||||
| taint_test.py:59 | ok | test_taint | request.content_type |
|
||||
| taint_test.py:62 | ok | test_taint | request.cookies |
|
||||
| taint_test.py:63 | ok | test_taint | request.cookies['key'] |
|
||||
| taint_test.py:65 | ok | test_taint | request.data |
|
||||
| taint_test.py:68 | ok | test_taint | request.files |
|
||||
| taint_test.py:69 | ok | test_taint | request.files['key'] |
|
||||
| taint_test.py:70 | fail | test_taint | request.files['key'].filename |
|
||||
| taint_test.py:71 | fail | test_taint | request.files['key'].stream |
|
||||
| taint_test.py:72 | ok | test_taint | request.files.getlist(..) |
|
||||
| taint_test.py:73 | fail | test_taint | request.files.getlist(..)[0].filename |
|
||||
| taint_test.py:74 | fail | test_taint | request.files.getlist(..)[0].stream |
|
||||
| taint_test.py:77 | ok | test_taint | request.form |
|
||||
| taint_test.py:78 | ok | test_taint | request.form['key'] |
|
||||
| taint_test.py:79 | ok | test_taint | request.form.getlist(..) |
|
||||
| taint_test.py:81 | ok | test_taint | request.get_data() |
|
||||
| taint_test.py:83 | ok | test_taint | request.get_json() |
|
||||
| taint_test.py:84 | ok | test_taint | request.get_json()['foo'] |
|
||||
| taint_test.py:85 | ok | test_taint | request.get_json()['foo']['bar'] |
|
||||
| taint_test.py:89 | ok | test_taint | request.headers |
|
||||
| taint_test.py:90 | ok | test_taint | request.headers['key'] |
|
||||
| taint_test.py:91 | fail | test_taint | request.headers.get_all(..) |
|
||||
| taint_test.py:92 | fail | test_taint | request.headers.getlist(..) |
|
||||
| taint_test.py:93 | ok | test_taint | list(..) |
|
||||
| taint_test.py:94 | fail | test_taint | request.headers.to_wsgi_list() |
|
||||
| taint_test.py:96 | ok | test_taint | request.json |
|
||||
| taint_test.py:97 | ok | test_taint | request.json['foo'] |
|
||||
| taint_test.py:98 | ok | test_taint | request.json['foo']['bar'] |
|
||||
| taint_test.py:100 | ok | test_taint | request.method |
|
||||
| taint_test.py:102 | ok | test_taint | request.mimetype |
|
||||
| taint_test.py:104 | ok | test_taint | request.mimetype_params |
|
||||
| taint_test.py:106 | ok | test_taint | request.origin |
|
||||
| taint_test.py:109 | ok | test_taint | request.pragma |
|
||||
| taint_test.py:111 | ok | test_taint | request.query_string |
|
||||
| taint_test.py:113 | ok | test_taint | request.referrer |
|
||||
| taint_test.py:115 | ok | test_taint | request.remote_addr |
|
||||
| taint_test.py:117 | ok | test_taint | request.remote_user |
|
||||
| taint_test.py:120 | ok | test_taint | request.stream |
|
||||
| taint_test.py:121 | ok | test_taint | request.input_stream |
|
||||
| taint_test.py:123 | ok | test_taint | request.url |
|
||||
| taint_test.py:125 | ok | test_taint | request.user_agent |
|
||||
| taint_test.py:128 | ok | test_taint | request.values |
|
||||
| taint_test.py:129 | ok | test_taint | request.values['key'] |
|
||||
| taint_test.py:130 | ok | test_taint | request.values.getlist(..) |
|
||||
| taint_test.py:133 | ok | test_taint | request.view_args |
|
||||
| taint_test.py:134 | ok | test_taint | request.view_args['key'] |
|
||||
| taint_test.py:138 | ok | test_taint | request.script_root |
|
||||
| taint_test.py:139 | ok | test_taint | request.url_root |
|
||||
| taint_test.py:143 | ok | test_taint | request.charset |
|
||||
| taint_test.py:144 | ok | test_taint | request.url_charset |
|
||||
| taint_test.py:148 | ok | test_taint | request.date |
|
||||
| taint_test.py:151 | ok | test_taint | request.endpoint |
|
||||
| taint_test.py:156 | ok | test_taint | request.host |
|
||||
| taint_test.py:157 | ok | test_taint | request.host_url |
|
||||
| taint_test.py:159 | ok | test_taint | request.scheme |
|
||||
| taint_test.py:161 | ok | test_taint | request.script_root |
|
||||
| taint_test.py:169 | ok | test_taint | request.args |
|
||||
| taint_test.py:170 | ok | test_taint | a |
|
||||
| taint_test.py:171 | ok | test_taint | b |
|
||||
| taint_test.py:173 | ok | test_taint | request.args['key'] |
|
||||
| taint_test.py:174 | ok | test_taint | a['key'] |
|
||||
| taint_test.py:175 | ok | test_taint | b['key'] |
|
||||
| taint_test.py:177 | ok | test_taint | request.args.getlist(..) |
|
||||
| taint_test.py:178 | ok | test_taint | a.getlist(..) |
|
||||
| taint_test.py:179 | ok | test_taint | b.getlist(..) |
|
||||
| taint_test.py:180 | ok | test_taint | gl(..) |
|
||||
| taint_test.py:187 | ok | test_taint | req.path |
|
||||
| taint_test.py:188 | ok | test_taint | gd() |
|
||||
@@ -1,6 +0,0 @@
|
||||
import experimental.dataflow.tainttracking.TestTaintLib
|
||||
import semmle.python.dataflow.new.RemoteFlowSources
|
||||
|
||||
class RemoteFlowTestTaintConfiguration extends TestTaintTrackingConfiguration {
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
}
|
||||
@@ -3,7 +3,7 @@ app = Flask(__name__)
|
||||
|
||||
@app.route("/test_taint/<name>/<int:number>") # $routeSetup="/test_taint/<name>/<int:number>"
|
||||
def test_taint(name = "World!", number="0", foo="foo"): # $requestHandler routedParameter=name routedParameter=number
|
||||
ensure_tainted(name, number)
|
||||
ensure_tainted(name, number) # $ tainted
|
||||
ensure_not_tainted(foo)
|
||||
|
||||
# Manually inspected all fields of the Request object
|
||||
@@ -11,127 +11,128 @@ def test_taint(name = "World!", number="0", foo="foo"): # $requestHandler route
|
||||
|
||||
ensure_tainted(
|
||||
|
||||
request.environ,
|
||||
request.environ.get('HTTP_AUTHORIZATION'),
|
||||
request.environ, # $ tainted
|
||||
request.environ.get('HTTP_AUTHORIZATION'), # $ tainted
|
||||
|
||||
request.path,
|
||||
request.full_path,
|
||||
request.base_url,
|
||||
request.url,
|
||||
request.path, # $ tainted
|
||||
request.full_path, # $ tainted
|
||||
request.base_url, # $ tainted
|
||||
request.url, # $ tainted
|
||||
|
||||
# These request.accept_* properties are instances of subclasses of werkzeug.datastructures.Accept
|
||||
request.accept_charsets.best,
|
||||
request.accept_charsets.best_match(["utf-8", "utf-16"]),
|
||||
request.accept_charsets[0],
|
||||
request.accept_encodings,
|
||||
request.accept_languages,
|
||||
request.accept_mimetypes,
|
||||
request.accept_charsets.best, # $ MISSING: tainted
|
||||
request.accept_charsets.best_match(["utf-8", "utf-16"]), # $ MISSING: tainted
|
||||
request.accept_charsets[0], # $ tainted
|
||||
request.accept_encodings, # $ tainted
|
||||
request.accept_languages, # $ tainted
|
||||
request.accept_mimetypes, # $ tainted
|
||||
|
||||
# werkzeug.datastructures.HeaderSet (subclass of collections_abc.MutableSet)
|
||||
request.access_control_request_headers,
|
||||
request.access_control_request_headers, # $ tainted
|
||||
|
||||
request.access_control_request_method,
|
||||
request.access_control_request_method, # $ tainted
|
||||
|
||||
request.access_route,
|
||||
request.access_route[0],
|
||||
request.access_route, # $ tainted
|
||||
request.access_route[0], # $ tainted
|
||||
|
||||
# By default werkzeug.datastructures.ImmutableMultiDict -- although can be changed :\
|
||||
request.args,
|
||||
request.args['key'],
|
||||
request.args.getlist('key'),
|
||||
request.args, # $ tainted
|
||||
request.args['key'], # $ tainted
|
||||
request.args.getlist('key'), # $ tainted
|
||||
|
||||
# werkzeug.datastructures.Authorization (a dict, with some properties)
|
||||
request.authorization,
|
||||
request.authorization['username'],
|
||||
request.authorization.username,
|
||||
request.authorization, # $ tainted
|
||||
request.authorization['username'], # $ tainted
|
||||
request.authorization.username, # $ MISSING: tainted
|
||||
|
||||
# werkzeug.datastructures.RequestCacheControl
|
||||
request.cache_control,
|
||||
request.cache_control, # $ tainted
|
||||
# These should be `int`s, but can be strings... see debug method below
|
||||
request.cache_control.max_age,
|
||||
request.cache_control.max_stale,
|
||||
request.cache_control.min_fresh,
|
||||
request.cache_control.max_age, # $ MISSING: tainted
|
||||
request.cache_control.max_stale, # $ MISSING: tainted
|
||||
request.cache_control.min_fresh, # $ MISSING: tainted
|
||||
|
||||
request.content_encoding,
|
||||
request.content_encoding, # $ tainted
|
||||
|
||||
request.content_md5,
|
||||
request.content_md5, # $ tainted
|
||||
|
||||
request.content_type,
|
||||
request.content_type, # $ tainted
|
||||
|
||||
# werkzeug.datastructures.ImmutableTypeConversionDict (which is basically just a dict)
|
||||
request.cookies,
|
||||
request.cookies['key'],
|
||||
request.cookies, # $ tainted
|
||||
request.cookies['key'], # $ tainted
|
||||
|
||||
request.data,
|
||||
request.data, # $ tainted
|
||||
|
||||
# a werkzeug.datastructures.MultiDict, mapping [str, werkzeug.datastructures.FileStorage]
|
||||
request.files,
|
||||
request.files['key'],
|
||||
request.files['key'].filename,
|
||||
request.files['key'].stream,
|
||||
request.files.getlist('key'),
|
||||
request.files.getlist('key')[0].filename,
|
||||
request.files.getlist('key')[0].stream,
|
||||
request.files, # $ tainted
|
||||
request.files['key'], # $ tainted
|
||||
request.files['key'].filename, # $ MISSING: tainted
|
||||
request.files['key'].stream, # $ MISSING: tainted
|
||||
request.files.getlist('key'), # $ tainted
|
||||
request.files.getlist('key')[0].filename, # $ MISSING: tainted
|
||||
request.files.getlist('key')[0].stream, # $ MISSING: tainted
|
||||
|
||||
# By default werkzeug.datastructures.ImmutableMultiDict -- although can be changed :\
|
||||
request.form,
|
||||
request.form['key'],
|
||||
request.form.getlist('key'),
|
||||
request.form, # $ tainted
|
||||
request.form['key'], # $ tainted
|
||||
request.form.getlist('key'), # $ tainted
|
||||
|
||||
request.get_data(),
|
||||
request.get_data(), # $ tainted
|
||||
|
||||
request.get_json(),
|
||||
request.get_json()['foo'],
|
||||
request.get_json()['foo']['bar'],
|
||||
request.get_json(), # $ tainted
|
||||
request.get_json()['foo'], # $ tainted
|
||||
request.get_json()['foo']['bar'], # $ tainted
|
||||
|
||||
# werkzeug.datastructures.EnvironHeaders,
|
||||
# which has same interface as werkzeug.datastructures.Headers
|
||||
request.headers,
|
||||
request.headers['key'],
|
||||
request.headers.get_all('key'),
|
||||
request.headers.getlist('key'),
|
||||
list(request.headers), # (k, v) list
|
||||
request.headers.to_wsgi_list(), # (k, v) list
|
||||
request.headers, # $ tainted
|
||||
request.headers['key'], # $ tainted
|
||||
request.headers.get_all('key'), # $ MISSING: tainted
|
||||
request.headers.getlist('key'), # $ MISSING: tainted
|
||||
# two ways to get (k, v) lists
|
||||
list(request.headers), # $ tainted
|
||||
request.headers.to_wsgi_list(), # $ MISSING: tainted
|
||||
|
||||
request.json,
|
||||
request.json['foo'],
|
||||
request.json['foo']['bar'],
|
||||
request.json, # $ tainted
|
||||
request.json['foo'], # $ tainted
|
||||
request.json['foo']['bar'], # $ tainted
|
||||
|
||||
request.method,
|
||||
request.method, # $ tainted
|
||||
|
||||
request.mimetype,
|
||||
request.mimetype, # $ tainted
|
||||
|
||||
request.mimetype_params,
|
||||
request.mimetype_params, # $ tainted
|
||||
|
||||
request.origin,
|
||||
request.origin, # $ tainted
|
||||
|
||||
# werkzeug.datastructures.HeaderSet (subclass of collections_abc.MutableSet)
|
||||
request.pragma,
|
||||
request.pragma, # $ tainted
|
||||
|
||||
request.query_string,
|
||||
request.query_string, # $ tainted
|
||||
|
||||
request.referrer,
|
||||
request.referrer, # $ tainted
|
||||
|
||||
request.remote_addr,
|
||||
request.remote_addr, # $ tainted
|
||||
|
||||
request.remote_user,
|
||||
request.remote_user, # $ tainted
|
||||
|
||||
# file-like object
|
||||
request.stream,
|
||||
request.input_stream,
|
||||
request.stream, # $ tainted
|
||||
request.input_stream, # $ tainted
|
||||
|
||||
request.url,
|
||||
request.url, # $ tainted
|
||||
|
||||
request.user_agent,
|
||||
request.user_agent, # $ tainted
|
||||
|
||||
# werkzeug.datastructures.CombinedMultiDict, which is basically just a werkzeug.datastructures.MultiDict
|
||||
request.values,
|
||||
request.values['key'],
|
||||
request.values.getlist('key'),
|
||||
request.values, # $ tainted
|
||||
request.values['key'], # $ tainted
|
||||
request.values.getlist('key'), # $ tainted
|
||||
|
||||
# dict
|
||||
request.view_args,
|
||||
request.view_args['key'],
|
||||
request.view_args, # $ tainted
|
||||
request.view_args['key'], # $ tainted
|
||||
)
|
||||
|
||||
ensure_not_tainted(
|
||||
@@ -166,26 +167,26 @@ def test_taint(name = "World!", number="0", foo="foo"): # $requestHandler route
|
||||
b = a
|
||||
gl = b.getlist
|
||||
ensure_tainted(
|
||||
request.args,
|
||||
a,
|
||||
b,
|
||||
request.args, # $ tainted
|
||||
a, # $ tainted
|
||||
b, # $ tainted
|
||||
|
||||
request.args['key'],
|
||||
a['key'],
|
||||
b['key'],
|
||||
request.args['key'], # $ tainted
|
||||
a['key'], # $ tainted
|
||||
b['key'], # $ tainted
|
||||
|
||||
request.args.getlist('key'),
|
||||
a.getlist('key'),
|
||||
b.getlist('key'),
|
||||
gl('key'),
|
||||
request.args.getlist('key'), # $ tainted
|
||||
a.getlist('key'), # $ tainted
|
||||
b.getlist('key'), # $ tainted
|
||||
gl('key'), # $ tainted
|
||||
)
|
||||
|
||||
# aliasing tests
|
||||
req = request
|
||||
gd = request.get_data
|
||||
ensure_tainted(
|
||||
req.path,
|
||||
gd(),
|
||||
req.path, # $ tainted
|
||||
gd(), # $ tainted
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ def test_additional_taint():
|
||||
cmd3 = builtins.compile(src, "<filename>", "exec")
|
||||
|
||||
ensure_tainted(
|
||||
src,
|
||||
cmd1,
|
||||
cmd2,
|
||||
cmd3,
|
||||
src, # $ tainted
|
||||
cmd1, # $ tainted
|
||||
cmd2, # $ tainted
|
||||
cmd3, # $ tainted
|
||||
)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
@@ -0,0 +1 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
@@ -1,37 +0,0 @@
|
||||
| CodeExecution.py:35 | ok | test_additional_taint | src |
|
||||
| CodeExecution.py:36 | ok | test_additional_taint | cmd1 |
|
||||
| CodeExecution.py:37 | ok | test_additional_taint | cmd2 |
|
||||
| CodeExecution.py:38 | ok | test_additional_taint | cmd3 |
|
||||
| http_server.py:22 | ok | test_cgi_FieldStorage_taint | form |
|
||||
| http_server.py:24 | ok | test_cgi_FieldStorage_taint | form['key'] |
|
||||
| http_server.py:25 | ok | test_cgi_FieldStorage_taint | form['key'].value |
|
||||
| http_server.py:26 | ok | test_cgi_FieldStorage_taint | form['key'].file |
|
||||
| http_server.py:27 | ok | test_cgi_FieldStorage_taint | form['key'].filename |
|
||||
| http_server.py:28 | ok | test_cgi_FieldStorage_taint | form['key'][0] |
|
||||
| http_server.py:29 | ok | test_cgi_FieldStorage_taint | form['key'][0].value |
|
||||
| http_server.py:30 | ok | test_cgi_FieldStorage_taint | form['key'][0].file |
|
||||
| http_server.py:31 | ok | test_cgi_FieldStorage_taint | form['key'][0].filename |
|
||||
| http_server.py:32 | fail | test_cgi_FieldStorage_taint | ListComp |
|
||||
| http_server.py:34 | ok | test_cgi_FieldStorage_taint | form.getvalue(..) |
|
||||
| http_server.py:35 | ok | test_cgi_FieldStorage_taint | form.getvalue(..)[0] |
|
||||
| http_server.py:37 | ok | test_cgi_FieldStorage_taint | form.getfirst(..) |
|
||||
| http_server.py:39 | ok | test_cgi_FieldStorage_taint | form.getlist(..) |
|
||||
| http_server.py:40 | ok | test_cgi_FieldStorage_taint | form.getlist(..)[0] |
|
||||
| http_server.py:41 | fail | test_cgi_FieldStorage_taint | ListComp |
|
||||
| http_server.py:50 | ok | taint_sources | self |
|
||||
| http_server.py:52 | ok | taint_sources | self.requestline |
|
||||
| http_server.py:54 | ok | taint_sources | self.path |
|
||||
| http_server.py:56 | ok | taint_sources | self.headers |
|
||||
| http_server.py:57 | ok | taint_sources | self.headers['Foo'] |
|
||||
| http_server.py:58 | ok | taint_sources | self.headers.get(..) |
|
||||
| http_server.py:59 | fail | taint_sources | self.headers.get_all(..) |
|
||||
| http_server.py:60 | fail | taint_sources | self.headers.keys() |
|
||||
| http_server.py:61 | ok | taint_sources | self.headers.values() |
|
||||
| http_server.py:62 | ok | taint_sources | self.headers.items() |
|
||||
| http_server.py:63 | fail | taint_sources | self.headers.as_bytes() |
|
||||
| http_server.py:64 | fail | taint_sources | self.headers.as_string() |
|
||||
| http_server.py:65 | ok | taint_sources | str(..) |
|
||||
| http_server.py:66 | ok | taint_sources | bytes(..) |
|
||||
| http_server.py:68 | ok | taint_sources | self.rfile |
|
||||
| http_server.py:69 | fail | taint_sources | self.rfile.read() |
|
||||
| http_server.py:78 | ok | taint_sources | form |
|
||||
@@ -1,9 +0,0 @@
|
||||
import experimental.dataflow.tainttracking.TestTaintLib
|
||||
import semmle.python.dataflow.new.RemoteFlowSources
|
||||
|
||||
class WithRemoteFlowSources extends TestTaintTrackingConfiguration {
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
super.isSource(source) or
|
||||
source instanceof RemoteFlowSource
|
||||
}
|
||||
}
|
||||
@@ -19,26 +19,28 @@ def test_cgi_FieldStorage_taint():
|
||||
form = cgi.FieldStorage()
|
||||
|
||||
ensure_tainted(
|
||||
form,
|
||||
form, # $ tainted
|
||||
|
||||
form['key'], # will be a list, if multiple fields named "key" are provided
|
||||
form['key'].value,
|
||||
form['key'].file,
|
||||
form['key'].filename,
|
||||
form['key'][0],
|
||||
form['key'][0].value,
|
||||
form['key'][0].file,
|
||||
form['key'][0].filename,
|
||||
[field.value for field in form['key']],
|
||||
# `form['key']` will be a list, if multiple fields named "key" are provided
|
||||
form['key'], # $ tainted
|
||||
form['key'].value, # $ tainted
|
||||
form['key'].file, # $ tainted
|
||||
form['key'].filename, # $ tainted
|
||||
form['key'][0], # $ tainted
|
||||
form['key'][0].value, # $ tainted
|
||||
form['key'][0].file, # $ tainted
|
||||
form['key'][0].filename, # $ tainted
|
||||
[field.value for field in form['key']], # $ MISSING: tainted
|
||||
|
||||
form.getvalue('key'), # will be a list, if multiple fields named "key" are provided
|
||||
form.getvalue('key')[0],
|
||||
# `form.getvalue('key')` will be a list, if multiple fields named "key" are provided
|
||||
form.getvalue('key'), # $ tainted
|
||||
form.getvalue('key')[0], # $ tainted
|
||||
|
||||
form.getfirst('key'),
|
||||
form.getfirst('key'), # $ tainted
|
||||
|
||||
form.getlist('key'),
|
||||
form.getlist('key')[0],
|
||||
[field.value for field in form.getlist('key')],
|
||||
form.getlist('key'), # $ tainted
|
||||
form.getlist('key')[0], # $ tainted
|
||||
[field.value for field in form.getlist('key')], # $ MISSING: tainted
|
||||
)
|
||||
|
||||
|
||||
@@ -47,26 +49,26 @@ class MyHandler(BaseHTTPRequestHandler):
|
||||
def taint_sources(self):
|
||||
|
||||
ensure_tainted(
|
||||
self,
|
||||
self, # $ tainted
|
||||
|
||||
self.requestline,
|
||||
self.requestline, # $ tainted
|
||||
|
||||
self.path,
|
||||
self.path, # $ tainted
|
||||
|
||||
self.headers,
|
||||
self.headers['Foo'],
|
||||
self.headers.get('Foo'),
|
||||
self.headers.get_all('Foo'),
|
||||
self.headers.keys(),
|
||||
self.headers.values(),
|
||||
self.headers.items(),
|
||||
self.headers.as_bytes(),
|
||||
self.headers.as_string(),
|
||||
str(self.headers),
|
||||
bytes(self.headers),
|
||||
self.headers, # $ tainted
|
||||
self.headers['Foo'], # $ tainted
|
||||
self.headers.get('Foo'), # $ tainted
|
||||
self.headers.get_all('Foo'), # $ MISSING: tainted
|
||||
self.headers.keys(), # $ MISSING: tainted
|
||||
self.headers.values(), # $ tainted
|
||||
self.headers.items(), # $ tainted
|
||||
self.headers.as_bytes(), # $ MISSING: tainted
|
||||
self.headers.as_string(), # $ MISSING: tainted
|
||||
str(self.headers), # $ tainted
|
||||
bytes(self.headers), # $ tainted
|
||||
|
||||
self.rfile,
|
||||
self.rfile.read(),
|
||||
self.rfile, # $ tainted
|
||||
self.rfile.read(), # $ MISSING: tainted
|
||||
)
|
||||
|
||||
form = cgi.FieldStorage(
|
||||
@@ -75,7 +77,7 @@ class MyHandler(BaseHTTPRequestHandler):
|
||||
environ={'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': self.headers.get('content-type')},
|
||||
)
|
||||
|
||||
ensure_tainted(form)
|
||||
ensure_tainted(form) # $ tainted
|
||||
|
||||
|
||||
def do_GET(self): # $ requestHandler
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
failures
|
||||
@@ -0,0 +1 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
@@ -1,41 +0,0 @@
|
||||
| taint_test.py:6 | ok | get | name |
|
||||
| taint_test.py:6 | ok | get | number |
|
||||
| taint_test.py:7 | ok | get | foo |
|
||||
| taint_test.py:11 | ok | get | self.get_argument(..) |
|
||||
| taint_test.py:12 | ok | get | self.get_arguments(..) |
|
||||
| taint_test.py:13 | ok | get | self.get_arguments(..)[0] |
|
||||
| taint_test.py:15 | ok | get | self.get_body_argument(..) |
|
||||
| taint_test.py:16 | ok | get | self.get_body_arguments(..) |
|
||||
| taint_test.py:17 | ok | get | self.get_body_arguments(..)[0] |
|
||||
| taint_test.py:19 | ok | get | self.get_query_argument(..) |
|
||||
| taint_test.py:20 | ok | get | self.get_query_arguments(..) |
|
||||
| taint_test.py:21 | ok | get | self.get_query_arguments(..)[0] |
|
||||
| taint_test.py:23 | ok | get | self.path_args |
|
||||
| taint_test.py:24 | ok | get | self.path_args[0] |
|
||||
| taint_test.py:26 | ok | get | self.path_kwargs |
|
||||
| taint_test.py:27 | ok | get | self.path_kwargs["name"] |
|
||||
| taint_test.py:34 | ok | get | request |
|
||||
| taint_test.py:40 | ok | get | request.uri |
|
||||
| taint_test.py:41 | ok | get | request.path |
|
||||
| taint_test.py:42 | ok | get | request.query |
|
||||
| taint_test.py:43 | ok | get | request.full_url() |
|
||||
| taint_test.py:45 | ok | get | request.remote_ip |
|
||||
| taint_test.py:47 | ok | get | request.body |
|
||||
| taint_test.py:49 | ok | get | request.arguments |
|
||||
| taint_test.py:50 | ok | get | request.arguments["name"] |
|
||||
| taint_test.py:51 | ok | get | request.arguments["name"][0] |
|
||||
| taint_test.py:53 | ok | get | request.query_arguments |
|
||||
| taint_test.py:54 | ok | get | request.query_arguments["name"] |
|
||||
| taint_test.py:55 | ok | get | request.query_arguments["name"][0] |
|
||||
| taint_test.py:57 | ok | get | request.body_arguments |
|
||||
| taint_test.py:58 | ok | get | request.body_arguments["name"] |
|
||||
| taint_test.py:59 | ok | get | request.body_arguments["name"][0] |
|
||||
| taint_test.py:62 | ok | get | request.headers |
|
||||
| taint_test.py:63 | ok | get | request.headers["header-name"] |
|
||||
| taint_test.py:64 | fail | get | request.headers.get_list(..) |
|
||||
| taint_test.py:65 | fail | get | request.headers.get_all() |
|
||||
| taint_test.py:66 | fail | get | ListComp |
|
||||
| taint_test.py:69 | ok | get | request.cookies |
|
||||
| taint_test.py:70 | ok | get | request.cookies["cookie-name"] |
|
||||
| taint_test.py:71 | fail | get | request.cookies["cookie-name"].key |
|
||||
| taint_test.py:72 | fail | get | request.cookies["cookie-name"].value |
|
||||
@@ -1,6 +0,0 @@
|
||||
import experimental.dataflow.tainttracking.TestTaintLib
|
||||
import semmle.python.dataflow.new.RemoteFlowSources
|
||||
|
||||
class RemoteFlowTestTaintConfiguration extends TestTaintTrackingConfiguration {
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
}
|
||||
@@ -3,73 +3,73 @@ import tornado.web
|
||||
|
||||
class TaintTest(tornado.web.RequestHandler):
|
||||
def get(self, name = "World!", number="0", foo="foo"): # $ requestHandler routedParameter=name routedParameter=number
|
||||
ensure_tainted(name, number)
|
||||
ensure_tainted(name, number) # $ tainted
|
||||
ensure_not_tainted(foo)
|
||||
|
||||
ensure_tainted(
|
||||
# see https://www.tornadoweb.org/en/stable/web.html#input
|
||||
self.get_argument("name"),
|
||||
self.get_arguments("name"),
|
||||
self.get_arguments("name")[0],
|
||||
self.get_argument("name"), # $ tainted
|
||||
self.get_arguments("name"), # $ tainted
|
||||
self.get_arguments("name")[0], # $ tainted
|
||||
|
||||
self.get_body_argument("name"),
|
||||
self.get_body_arguments("name"),
|
||||
self.get_body_arguments("name")[0],
|
||||
self.get_body_argument("name"), # $ tainted
|
||||
self.get_body_arguments("name"), # $ tainted
|
||||
self.get_body_arguments("name")[0], # $ tainted
|
||||
|
||||
self.get_query_argument("name"),
|
||||
self.get_query_arguments("name"),
|
||||
self.get_query_arguments("name")[0],
|
||||
self.get_query_argument("name"), # $ tainted
|
||||
self.get_query_arguments("name"), # $ tainted
|
||||
self.get_query_arguments("name")[0], # $ tainted
|
||||
|
||||
self.path_args,
|
||||
self.path_args[0],
|
||||
self.path_args, # $ tainted
|
||||
self.path_args[0], # $ tainted
|
||||
|
||||
self.path_kwargs,
|
||||
self.path_kwargs["name"],
|
||||
self.path_kwargs, # $ tainted
|
||||
self.path_kwargs["name"], # $ tainted
|
||||
)
|
||||
|
||||
request = self.request
|
||||
|
||||
ensure_tainted(
|
||||
# see https://www.tornadoweb.org/en/stable/httputil.html#tornado.httputil.HTTPServerRequest
|
||||
request,
|
||||
request, # $ tainted
|
||||
|
||||
# For the URL https:://example.com/foo/bar?baz=42
|
||||
# request.uri="/foo/bar?baz=42"
|
||||
# request.path="/foo/bar"
|
||||
# request.query="baz=42"
|
||||
request.uri,
|
||||
request.path,
|
||||
request.query,
|
||||
request.full_url(),
|
||||
request.uri, # $ tainted
|
||||
request.path, # $ tainted
|
||||
request.query, # $ tainted
|
||||
request.full_url(), # $ tainted
|
||||
|
||||
request.remote_ip,
|
||||
request.remote_ip, # $ tainted
|
||||
|
||||
request.body,
|
||||
request.body, # $ tainted
|
||||
|
||||
request.arguments,
|
||||
request.arguments["name"],
|
||||
request.arguments["name"][0],
|
||||
request.arguments, # $ tainted
|
||||
request.arguments["name"], # $ tainted
|
||||
request.arguments["name"][0], # $ tainted
|
||||
|
||||
request.query_arguments,
|
||||
request.query_arguments["name"],
|
||||
request.query_arguments["name"][0],
|
||||
request.query_arguments, # $ tainted
|
||||
request.query_arguments["name"], # $ tainted
|
||||
request.query_arguments["name"][0], # $ tainted
|
||||
|
||||
request.body_arguments,
|
||||
request.body_arguments["name"],
|
||||
request.body_arguments["name"][0],
|
||||
request.body_arguments, # $ tainted
|
||||
request.body_arguments["name"], # $ tainted
|
||||
request.body_arguments["name"][0], # $ tainted
|
||||
|
||||
# dict-like, see https://www.tornadoweb.org/en/stable/httputil.html#tornado.httputil.HTTPHeaders
|
||||
request.headers,
|
||||
request.headers["header-name"],
|
||||
request.headers.get_list("header-name"),
|
||||
request.headers.get_all(),
|
||||
[(k, v) for (k, v) in request.headers.get_all()],
|
||||
request.headers, # $ tainted
|
||||
request.headers["header-name"], # $ tainted
|
||||
request.headers.get_list("header-name"), # $ MISSING: tainted
|
||||
request.headers.get_all(), # $ MISSING: tainted
|
||||
[(k, v) for (k, v) in request.headers.get_all()], # $ MISSING: tainted
|
||||
|
||||
# Dict[str, http.cookies.Morsel]
|
||||
request.cookies,
|
||||
request.cookies["cookie-name"],
|
||||
request.cookies["cookie-name"].key,
|
||||
request.cookies["cookie-name"].value,
|
||||
request.cookies, # $ tainted
|
||||
request.cookies["cookie-name"], # $ tainted
|
||||
request.cookies["cookie-name"].key, # $ MISSING: tainted
|
||||
request.cookies["cookie-name"].value, # $ MISSING: tainted
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user