mirror of
https://github.com/github/codeql.git
synced 2026-06-18 03:11:07 +02:00
Convert Python qlref tests to inline expectations
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
#select
|
||||
| django_tests.py:6:21:6:43 | ControlFlowNode for Attribute() | django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:6:21:6:43 | ControlFlowNode for Attribute() | Cookie is constructed from a $@. | django_tests.py:4:25:4:31 | ControlFlowNode for request | user-supplied input |
|
||||
| django_tests.py:7:21:7:44 | ControlFlowNode for Attribute() | django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:7:21:7:44 | ControlFlowNode for Attribute() | Cookie is constructed from a $@. | django_tests.py:4:25:4:31 | ControlFlowNode for request | user-supplied input |
|
||||
| django_tests.py:13:30:13:100 | ControlFlowNode for Fstring | django_tests.py:11:26:11:32 | ControlFlowNode for request | django_tests.py:13:30:13:100 | ControlFlowNode for Fstring | Cookie is constructed from a $@. | django_tests.py:11:26:11:32 | ControlFlowNode for request | user-supplied input |
|
||||
edges
|
||||
| django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:6:21:6:31 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep |
|
||||
| django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:7:21:7:31 | ControlFlowNode for Attribute | provenance | AdditionalTaintStep |
|
||||
@@ -22,7 +26,3 @@ nodes
|
||||
| django_tests.py:13:59:13:69 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
|
||||
| django_tests.py:13:59:13:82 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
subpaths
|
||||
#select
|
||||
| django_tests.py:6:21:6:43 | ControlFlowNode for Attribute() | django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:6:21:6:43 | ControlFlowNode for Attribute() | Cookie is constructed from a $@. | django_tests.py:4:25:4:31 | ControlFlowNode for request | user-supplied input |
|
||||
| django_tests.py:7:21:7:44 | ControlFlowNode for Attribute() | django_tests.py:4:25:4:31 | ControlFlowNode for request | django_tests.py:7:21:7:44 | ControlFlowNode for Attribute() | Cookie is constructed from a $@. | django_tests.py:4:25:4:31 | ControlFlowNode for request | user-supplied input |
|
||||
| django_tests.py:13:30:13:100 | ControlFlowNode for Fstring | django_tests.py:11:26:11:32 | ControlFlowNode for request | django_tests.py:13:30:13:100 | ControlFlowNode for Fstring | Cookie is constructed from a $@. | django_tests.py:11:26:11:32 | ControlFlowNode for request | user-supplied input |
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-020/CookieInjection.ql
|
||||
query: Security/CWE-020/CookieInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import django.http
|
||||
from django.urls import path
|
||||
|
||||
def django_response_bad(request):
|
||||
def django_response_bad(request): # $ Source
|
||||
resp = django.http.HttpResponse()
|
||||
resp.set_cookie(request.GET.get("name"), # BAD: Cookie is constructed from user input
|
||||
request.GET.get("value"))
|
||||
resp.set_cookie(request.GET.get("name"), # $ Alert # BAD: Cookie is constructed from user input
|
||||
request.GET.get("value")) # $ Alert
|
||||
return resp
|
||||
|
||||
|
||||
def django_response_bad2(request):
|
||||
def django_response_bad2(request): # $ Source
|
||||
response = django.http.HttpResponse()
|
||||
response['Set-Cookie'] = f"{request.GET.get('name')}={request.GET.get('value')}; SameSite=None;" # BAD: Cookie header is constructed from user input.
|
||||
response['Set-Cookie'] = f"{request.GET.get('name')}={request.GET.get('value')}; SameSite=None;" # $ Alert # BAD: Cookie header is constructed from user input.
|
||||
return response
|
||||
|
||||
# fake setup, you can't actually run this
|
||||
urlpatterns = [
|
||||
path("response_bad", django_response_bad),
|
||||
path("response_bd2", django_response_bad2)
|
||||
]
|
||||
]
|
||||
|
||||
@@ -1 +1 @@
|
||||
Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql
|
||||
query: Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.ql
|
||||
query: Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -2,7 +2,7 @@ import hashlib
|
||||
import hmac
|
||||
import base64
|
||||
|
||||
from flask import Flask, request, make_response
|
||||
from flask import Flask, request, make_response # $ Source
|
||||
app = Flask(__name__)
|
||||
|
||||
SECRET_KEY = b"SECRET_KEY"
|
||||
@@ -12,7 +12,7 @@ SECRET_KEY = b"SECRET_KEY"
|
||||
def hmac_example():
|
||||
data_raw = request.args.get("data").encode('utf-8')
|
||||
data = base64.decodebytes(data_raw)
|
||||
my_hmac = hmac.new(SECRET_KEY, data, hashlib.sha256)
|
||||
my_hmac = hmac.new(SECRET_KEY, data, hashlib.sha256) # $ Alert
|
||||
digest = my_hmac.digest()
|
||||
print(digest)
|
||||
return "ok"
|
||||
@@ -22,7 +22,7 @@ def hmac_example():
|
||||
def hmac_example2():
|
||||
data_raw = request.args.get("data").encode('utf-8')
|
||||
data = base64.decodebytes(data_raw)
|
||||
my_hmac = hmac.new(key=SECRET_KEY, msg=data, digestmod=hashlib.sha256)
|
||||
my_hmac = hmac.new(key=SECRET_KEY, msg=data, digestmod=hashlib.sha256) # $ Alert
|
||||
digest = my_hmac.digest()
|
||||
print(digest)
|
||||
return "ok"
|
||||
@@ -32,16 +32,16 @@ def hmac_example2():
|
||||
def unknown_lib_1():
|
||||
from unknown.lib import func
|
||||
data = request.args.get("data")
|
||||
func(data)
|
||||
func(kw=data)
|
||||
func(data) # $ Alert
|
||||
func(kw=data) # $ Alert
|
||||
|
||||
|
||||
@app.route("/unknown-lib-2")
|
||||
def unknown_lib_2():
|
||||
import unknown.lib
|
||||
data = request.args.get("data")
|
||||
unknown.lib.func(data)
|
||||
unknown.lib.func(kw=data)
|
||||
unknown.lib.func(data) # $ Alert
|
||||
unknown.lib.func(kw=data) # $ Alert
|
||||
|
||||
|
||||
def handle_this(arg, application = None):
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-020/IncompleteHostnameRegExp.ql
|
||||
query: Security/CWE-020/IncompleteHostnameRegExp.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -3,7 +3,7 @@ import re
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
UNSAFE_REGEX = re.compile("(www|beta).example.com/")
|
||||
UNSAFE_REGEX = re.compile("(www|beta).example.com/") # $ Alert
|
||||
SAFE_REGEX = re.compile(r"(www|beta)\.example\.com/")
|
||||
|
||||
@app.route('/some/path/bad')
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-020/IncompleteUrlSubstringSanitization.ql
|
||||
query: Security/CWE-020/IncompleteUrlSubstringSanitization.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -6,13 +6,13 @@ app = Flask(__name__)
|
||||
@app.route('/some/path/bad1')
|
||||
def unsafe1(request):
|
||||
target = request.args.get('target', '')
|
||||
if "example.com" in target:
|
||||
if "example.com" in target: # $ Alert
|
||||
return redirect(target)
|
||||
|
||||
@app.route('/some/path/bad2')
|
||||
def unsafe2(request):
|
||||
target = request.args.get('target', '')
|
||||
if target.endswith("example.com"):
|
||||
if target.endswith("example.com"): # $ Alert
|
||||
return redirect(target)
|
||||
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-020/OverlyLargeRange.ql
|
||||
query: Security/CWE-020/OverlyLargeRange.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import re
|
||||
|
||||
overlap1 = re.compile(r'^[0-93-5]$') # NOT OK
|
||||
overlap1 = re.compile(r'^[0-93-5]$') # $ Alert # NOT OK
|
||||
|
||||
overlap2 = re.compile(r'[A-ZA-z]') # NOT OK
|
||||
overlap2 = re.compile(r'[A-ZA-z]') # $ Alert # NOT OK
|
||||
|
||||
isEmpty = re.compile(r'^[z-a]$') # NOT OK
|
||||
isEmpty = re.compile(r'^[z-a]$') # $ Alert # NOT OK
|
||||
|
||||
isAscii = re.compile(r'^[\x00-\x7F]*$') # OK
|
||||
|
||||
@@ -14,18 +14,18 @@ codePoints = re.compile(r'[^\x21-\x7E]|[[\](){}<>/%]') # OK
|
||||
|
||||
NON_ALPHANUMERIC_REGEXP = re.compile(r'([^\#-~| |!])') # OK
|
||||
|
||||
smallOverlap = re.compile(r'[0-9a-fA-f]') # NOT OK
|
||||
smallOverlap = re.compile(r'[0-9a-fA-f]') # $ Alert # NOT OK
|
||||
|
||||
weirdRange = re.compile(r'[$-`]') # NOT OK
|
||||
weirdRange = re.compile(r'[$-`]') # $ Alert # NOT OK
|
||||
|
||||
keywordOperator = re.compile(r'[!\~\*\/%+-<>\^|=&]') # NOT OK
|
||||
keywordOperator = re.compile(r'[!\~\*\/%+-<>\^|=&]') # $ Alert # NOT OK
|
||||
|
||||
notYoutube = re.compile(r'youtu\.be\/[a-z1-9.-_]+') # NOT OK
|
||||
notYoutube = re.compile(r'youtu\.be\/[a-z1-9.-_]+') # $ Alert # NOT OK
|
||||
|
||||
numberToLetter = re.compile(r'[7-F]') # NOT OK
|
||||
numberToLetter = re.compile(r'[7-F]') # $ Alert # NOT OK
|
||||
|
||||
overlapsWithClass1 = re.compile(r'[0-9\d]') # NOT OK
|
||||
overlapsWithClass1 = re.compile(r'[0-9\d]') # $ Alert # NOT OK
|
||||
|
||||
overlapsWithClass2 = re.compile(r'[\w,.-?:*+]') # NOT OK
|
||||
overlapsWithClass2 = re.compile(r'[\w,.-?:*+]') # $ Alert # NOT OK
|
||||
|
||||
unicodeStuff = re.compile('[\U0001D173-\U0001D17A\U000E0020-\U000E007F\U000e0001]') # NOT OK
|
||||
unicodeStuff = re.compile('[\U0001D173-\U0001D17A\U000E0020-\U000E007F\U000e0001]') # $ Alert # NOT OK
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
#select
|
||||
| tarslip.py:15:1:15:3 | ControlFlowNode for tar | tarslip.py:14:7:14:39 | ControlFlowNode for Attribute() | tarslip.py:15:1:15:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:14:7:14:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:20:17:20:21 | ControlFlowNode for entry | tarslip.py:18:7:18:39 | ControlFlowNode for Attribute() | tarslip.py:20:17:20:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:18:7:18:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:39:17:39:21 | ControlFlowNode for entry | tarslip.py:35:7:35:39 | ControlFlowNode for Attribute() | tarslip.py:39:17:39:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:35:7:35:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:43:24:43:26 | ControlFlowNode for tar | tarslip.py:42:7:42:39 | ControlFlowNode for Attribute() | tarslip.py:43:24:43:26 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:42:7:42:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:61:21:61:25 | ControlFlowNode for entry | tarslip.py:58:7:58:39 | ControlFlowNode for Attribute() | tarslip.py:61:21:61:25 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:58:7:58:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:91:1:91:3 | ControlFlowNode for tar | tarslip.py:90:7:90:39 | ControlFlowNode for Attribute() | tarslip.py:91:1:91:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:90:7:90:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:96:17:96:21 | ControlFlowNode for entry | tarslip.py:94:7:94:39 | ControlFlowNode for Attribute() | tarslip.py:96:17:96:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:94:7:94:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:110:1:110:3 | ControlFlowNode for tar | tarslip.py:109:7:109:39 | ControlFlowNode for Attribute() | tarslip.py:110:1:110:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:109:7:109:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:113:24:113:26 | ControlFlowNode for tar | tarslip.py:112:7:112:39 | ControlFlowNode for Attribute() | tarslip.py:113:24:113:26 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:112:7:112:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
edges
|
||||
| tarslip.py:14:1:14:3 | ControlFlowNode for tar | tarslip.py:15:1:15:3 | ControlFlowNode for tar | provenance | |
|
||||
| tarslip.py:14:7:14:39 | ControlFlowNode for Attribute() | tarslip.py:14:1:14:3 | ControlFlowNode for tar | provenance | |
|
||||
@@ -54,13 +64,3 @@ nodes
|
||||
| tarslip.py:112:7:112:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| tarslip.py:113:24:113:26 | ControlFlowNode for tar | semmle.label | ControlFlowNode for tar |
|
||||
subpaths
|
||||
#select
|
||||
| tarslip.py:15:1:15:3 | ControlFlowNode for tar | tarslip.py:14:7:14:39 | ControlFlowNode for Attribute() | tarslip.py:15:1:15:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:14:7:14:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:20:17:20:21 | ControlFlowNode for entry | tarslip.py:18:7:18:39 | ControlFlowNode for Attribute() | tarslip.py:20:17:20:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:18:7:18:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:39:17:39:21 | ControlFlowNode for entry | tarslip.py:35:7:35:39 | ControlFlowNode for Attribute() | tarslip.py:39:17:39:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:35:7:35:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:43:24:43:26 | ControlFlowNode for tar | tarslip.py:42:7:42:39 | ControlFlowNode for Attribute() | tarslip.py:43:24:43:26 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:42:7:42:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:61:21:61:25 | ControlFlowNode for entry | tarslip.py:58:7:58:39 | ControlFlowNode for Attribute() | tarslip.py:61:21:61:25 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:58:7:58:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:91:1:91:3 | ControlFlowNode for tar | tarslip.py:90:7:90:39 | ControlFlowNode for Attribute() | tarslip.py:91:1:91:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:90:7:90:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:96:17:96:21 | ControlFlowNode for entry | tarslip.py:94:7:94:39 | ControlFlowNode for Attribute() | tarslip.py:96:17:96:21 | ControlFlowNode for entry | This file extraction depends on a $@. | tarslip.py:94:7:94:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:110:1:110:3 | ControlFlowNode for tar | tarslip.py:109:7:109:39 | ControlFlowNode for Attribute() | tarslip.py:110:1:110:3 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:109:7:109:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
| tarslip.py:113:24:113:26 | ControlFlowNode for tar | tarslip.py:112:7:112:39 | ControlFlowNode for Attribute() | tarslip.py:113:24:113:26 | ControlFlowNode for tar | This file extraction depends on a $@. | tarslip.py:112:7:112:39 | ControlFlowNode for Attribute() | potentially untrusted source |
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-022/TarSlip.ql
|
||||
query: Security/CWE-022/TarSlip.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -11,13 +11,13 @@ tar = tarfile.open(safe_filename_tar)
|
||||
for entry in tar:
|
||||
tar.extract(entry)
|
||||
|
||||
tar = tarfile.open(unsafe_filename_tar)
|
||||
tar.extractall()
|
||||
tar = tarfile.open(unsafe_filename_tar) # $ Source
|
||||
tar.extractall() # $ Alert
|
||||
tar.close()
|
||||
|
||||
tar = tarfile.open(unsafe_filename_tar)
|
||||
tar = tarfile.open(unsafe_filename_tar) # $ Source
|
||||
for entry in tar:
|
||||
tar.extract(entry)
|
||||
tar.extract(entry) # $ Alert
|
||||
|
||||
tar = tarfile.open(safe_filename_tar)
|
||||
tar.extractall()
|
||||
@@ -32,15 +32,15 @@ for entry in tar:
|
||||
tar.extract(entry, "/tmp/unpack/")
|
||||
|
||||
#Part Sanitized
|
||||
tar = tarfile.open(unsafe_filename_tar)
|
||||
tar = tarfile.open(unsafe_filename_tar) # $ Source
|
||||
for entry in tar:
|
||||
if ".." in entry.name:
|
||||
raise ValueError("Illegal tar archive entry")
|
||||
tar.extract(entry, "/tmp/unpack/")
|
||||
tar.extract(entry, "/tmp/unpack/") # $ Alert
|
||||
|
||||
#Unsanitized members
|
||||
tar = tarfile.open(unsafe_filename_tar)
|
||||
tar.extractall(members=tar)
|
||||
tar = tarfile.open(unsafe_filename_tar) # $ Source
|
||||
tar.extractall(members=tar) # $ Alert
|
||||
|
||||
|
||||
#Sanitize members
|
||||
@@ -55,10 +55,10 @@ tar.extractall(members=safemembers(tar))
|
||||
|
||||
|
||||
# Wrong sanitizer (is missing not)
|
||||
tar = tarfile.open(unsafe_filename_tar)
|
||||
tar = tarfile.open(unsafe_filename_tar) # $ Source
|
||||
for entry in tar:
|
||||
if os.path.isabs(entry.name) or ".." in entry.name:
|
||||
tar.extract(entry, "/tmp/unpack/")
|
||||
tar.extract(entry, "/tmp/unpack/") # $ Alert
|
||||
|
||||
|
||||
# OK Sanitized using not
|
||||
@@ -87,13 +87,13 @@ for entry in tar:
|
||||
|
||||
extraction_filter = "fully_trusted"
|
||||
|
||||
tar = tarfile.open(unsafe_filename_tar)
|
||||
tar.extractall(filter=extraction_filter) # unsafe
|
||||
tar = tarfile.open(unsafe_filename_tar) # $ Source
|
||||
tar.extractall(filter=extraction_filter) # $ Alert # unsafe
|
||||
tar.close()
|
||||
|
||||
tar = tarfile.open(unsafe_filename_tar)
|
||||
tar = tarfile.open(unsafe_filename_tar) # $ Source
|
||||
for entry in tar:
|
||||
tar.extract(entry, filter=extraction_filter) # unsafe
|
||||
tar.extract(entry, filter=extraction_filter) # $ Alert # unsafe
|
||||
|
||||
extraction_filter = "data"
|
||||
|
||||
@@ -106,11 +106,11 @@ for entry in tar:
|
||||
tar.extract(entry, filter=extraction_filter) # safe
|
||||
|
||||
extraction_filter = None
|
||||
tar = tarfile.open(unsafe_filename_tar)
|
||||
tar.extractall(filter=extraction_filter) # unsafe
|
||||
tar = tarfile.open(unsafe_filename_tar) # $ Source
|
||||
tar.extractall(filter=extraction_filter) # $ Alert # unsafe
|
||||
|
||||
tar = tarfile.open(unsafe_filename_tar)
|
||||
tar.extractall(members=tar, filter=extraction_filter) # unsafe
|
||||
tar = tarfile.open(unsafe_filename_tar) # $ Source
|
||||
tar.extractall(members=tar, filter=extraction_filter) # $ Alert # unsafe
|
||||
|
||||
tar = tarfile.open(unsafe_filename_tar)
|
||||
tar.extractall(members=safemembers(tar), filter=extraction_filter) # safe -- we assume `safemembers` makes up for the unsafe filter
|
||||
|
||||
@@ -4,21 +4,21 @@ from jinja2 import Template
|
||||
from jinja2 import Environment, DictLoader, escape
|
||||
|
||||
|
||||
def a(request):
|
||||
def a(request): # $ Source
|
||||
# Load the template
|
||||
template = request.GET['template']
|
||||
t = Template(template) # BAD: Template constructed from user input
|
||||
t = Template(template) # $ Alert # BAD: Template constructed from user input
|
||||
name = request.GET['name']
|
||||
# Render the template with the context data
|
||||
html = t.render(name=escape(name))
|
||||
return HttpResponse(html)
|
||||
|
||||
def b(request):
|
||||
def b(request): # $ Source
|
||||
import jinja2
|
||||
# Load the template
|
||||
template = request.GET['template']
|
||||
env = Environment()
|
||||
t = env.from_string(template) # BAD: Template constructed from user input
|
||||
t = env.from_string(template) # $ Alert # BAD: Template constructed from user input
|
||||
name = request.GET['name']
|
||||
# Render the template with the context data
|
||||
html = t.render(name=escape(name))
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#select
|
||||
| JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | This template construction depends on a $@. | JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | user-provided value |
|
||||
| JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | This template construction depends on a $@. | JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | user-provided value |
|
||||
edges
|
||||
| JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | JinjaSsti.py:9:5:9:12 | ControlFlowNode for template | provenance | AdditionalTaintStep |
|
||||
| JinjaSsti.py:9:5:9:12 | ControlFlowNode for template | JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | provenance | |
|
||||
@@ -11,6 +14,3 @@ nodes
|
||||
| JinjaSsti.py:19:5:19:12 | ControlFlowNode for template | semmle.label | ControlFlowNode for template |
|
||||
| JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | semmle.label | ControlFlowNode for template |
|
||||
subpaths
|
||||
#select
|
||||
| JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | JinjaSsti.py:10:18:10:25 | ControlFlowNode for template | This template construction depends on a $@. | JinjaSsti.py:7:7:7:13 | ControlFlowNode for request | user-provided value |
|
||||
| JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | JinjaSsti.py:21:25:21:32 | ControlFlowNode for template | This template construction depends on a $@. | JinjaSsti.py:16:7:16:13 | ControlFlowNode for request | user-provided value |
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-074/TemplateInjection.ql
|
||||
query: Security/CWE-074/TemplateInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-078/CommandInjection.ql
|
||||
query: Security/CWE-078/CommandInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -2,7 +2,7 @@ import os
|
||||
import platform
|
||||
import popen2
|
||||
|
||||
from flask import Flask, request
|
||||
from flask import Flask, request # $ Source
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@@ -16,14 +16,14 @@ def python2_specific():
|
||||
"""
|
||||
|
||||
files = request.args.get("files", "")
|
||||
os.popen2("ls " + files)
|
||||
os.popen3("ls " + files)
|
||||
os.popen4("ls " + files)
|
||||
os.popen2("ls " + files) # $ Alert
|
||||
os.popen3("ls " + files) # $ Alert
|
||||
os.popen4("ls " + files) # $ Alert
|
||||
|
||||
platform.popen("ls " + files)
|
||||
platform.popen("ls " + files) # $ Alert
|
||||
|
||||
popen2.popen2("ls " + files)
|
||||
popen2.popen3("ls " + files)
|
||||
popen2.popen4("ls " + files)
|
||||
popen2.Popen3("ls " + files)
|
||||
popen2.Popen4("ls " + files)
|
||||
popen2.popen2("ls " + files) # $ Alert
|
||||
popen2.popen3("ls " + files) # $ Alert
|
||||
popen2.popen4("ls " + files) # $ Alert
|
||||
popen2.Popen3("ls " + files) # $ Alert
|
||||
popen2.Popen4("ls " + files) # $ Alert
|
||||
|
||||
@@ -1 +1 @@
|
||||
Security/CWE-078/CommandInjection.ql
|
||||
query: Security/CWE-078/CommandInjection.ql
|
||||
|
||||
@@ -1 +1 @@
|
||||
Security/CWE-078/UnsafeShellCommandConstruction.ql
|
||||
query: Security/CWE-078/UnsafeShellCommandConstruction.ql
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-079/Jinja2WithoutEscaping.ql
|
||||
query: Security/CWE-079/Jinja2WithoutEscaping.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -6,7 +6,7 @@ from jinja2 import Environment, select_autoescape, FileSystemLoader, Template
|
||||
app = Flask(__name__)
|
||||
loader = FileSystemLoader( searchpath="templates/" )
|
||||
|
||||
unsafe_env = Environment(loader=loader)
|
||||
unsafe_env = Environment(loader=loader) # $ Alert
|
||||
safe1_env = Environment(loader=loader, autoescape=True)
|
||||
safe2_env = Environment(loader=loader, autoescape=select_autoescape())
|
||||
|
||||
@@ -38,18 +38,18 @@ e = Environment(
|
||||
auto = select_autoescape
|
||||
e = Environment(autoescape=auto) # GOOD
|
||||
z = 0
|
||||
e = Environment(autoescape=z) # BAD
|
||||
e = Environment(autoescape=z) # $ Alert # BAD
|
||||
E = Environment
|
||||
E() # BAD
|
||||
E(autoescape=z) # BAD
|
||||
E() # $ Alert # BAD
|
||||
E(autoescape=z) # $ Alert # BAD
|
||||
E(autoescape=auto) # GOOD
|
||||
E(autoescape=0+1) # GOOD
|
||||
|
||||
def checked(cond=False):
|
||||
if cond:
|
||||
e = Environment(autoescape=cond) # GOOD
|
||||
e = Environment(autoescape=cond) # $ Alert # GOOD
|
||||
|
||||
|
||||
unsafe_tmpl = Template('Hello {{ name }}!')
|
||||
unsafe_tmpl = Template('Hello {{ name }}!') # $ Alert
|
||||
safe1_tmpl = Template('Hello {{ name }}!', autoescape=True)
|
||||
safe2_tmpl = Template('Hello {{ name }}!', autoescape=select_autoescape())
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#select
|
||||
| reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
edges
|
||||
| reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:2:26:2:32 | ControlFlowNode for request | provenance | |
|
||||
| reflected_xss.py:2:26:2:32 | ControlFlowNode for request | reflected_xss.py:9:18:9:24 | ControlFlowNode for request | provenance | |
|
||||
@@ -28,7 +32,3 @@ nodes
|
||||
| reflected_xss.py:27:23:27:29 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
|
||||
| reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
subpaths
|
||||
#select
|
||||
| reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:10:26:10:53 | ControlFlowNode for BinaryExpr | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:22:26:22:41 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | reflected_xss.py:28:26:28:41 | ControlFlowNode for Attribute() | Cross-site scripting vulnerability due to a $@. | reflected_xss.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-079/ReflectedXss.ql
|
||||
query: Security/CWE-079/ReflectedXss.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import json
|
||||
from flask import Flask, request, make_response, escape, jsonify
|
||||
from flask import Flask, request, make_response, escape, jsonify # $ Source
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@@ -7,7 +7,7 @@ app = Flask(__name__)
|
||||
@app.route("/unsafe")
|
||||
def unsafe():
|
||||
first_name = request.args.get("name", "")
|
||||
return make_response("Your name is " + first_name) # NOT OK
|
||||
return make_response("Your name is " + first_name) # $ Alert # NOT OK
|
||||
|
||||
|
||||
@app.route("/safe")
|
||||
@@ -19,13 +19,13 @@ def safe():
|
||||
@app.route("/unsafe/json")
|
||||
def unsafe_json():
|
||||
data = json.loads(request.data)
|
||||
return make_response(json.dumps(data)) # NOT OK
|
||||
return make_response(json.dumps(data)) # $ Alert # NOT OK
|
||||
|
||||
|
||||
@app.route("/safe/json")
|
||||
def safe_json():
|
||||
data = json.loads(request.data)
|
||||
return make_response(json.dumps(data), 200, {'Content-Type': 'application/json'}) # OK, FP
|
||||
return make_response(json.dumps(data), 200, {'Content-Type': 'application/json'}) # $ SPURIOUS: Alert # OK, FP
|
||||
|
||||
|
||||
@app.route("/jsonify")
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
query: Security/CWE-089/SqlInjection.ql
|
||||
postprocess: utils/test/PrettyPrintModels.ql
|
||||
postprocess:
|
||||
- utils/test/PrettyPrintModels.ql
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -3,4 +3,4 @@ import sys
|
||||
import psycopg
|
||||
|
||||
conn = psycopg.connect(...)
|
||||
conn.execute(sys.argv[1])
|
||||
conn.execute(sys.argv[1]) # $ Alert
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-089/SqlInjection.ql
|
||||
query: Security/CWE-089/SqlInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -11,19 +11,19 @@ class User(models.Model):
|
||||
pass
|
||||
|
||||
@app.route("/users/<username>")
|
||||
def show_user(username):
|
||||
def show_user(username): # $ Source
|
||||
with connection.cursor() as cursor:
|
||||
# GOOD -- Using parameters
|
||||
cursor.execute("SELECT * FROM users WHERE username = %s", username)
|
||||
User.objects.raw("SELECT * FROM users WHERE username = %s", (username,))
|
||||
|
||||
# BAD -- Using string formatting
|
||||
cursor.execute("SELECT * FROM users WHERE username = '%s'" % username)
|
||||
cursor.execute("SELECT * FROM users WHERE username = '%s'" % username) # $ Alert
|
||||
|
||||
# BAD -- other ways of executing raw SQL code with string interpolation
|
||||
User.objects.annotate(RawSQL("insert into names_file ('name') values ('%s')" % username))
|
||||
User.objects.raw("insert into names_file ('name') values ('%s')" % username)
|
||||
User.objects.extra("insert into names_file ('name') values ('%s')" % username)
|
||||
User.objects.annotate(RawSQL("insert into names_file ('name') values ('%s')" % username)) # $ Alert
|
||||
User.objects.raw("insert into names_file ('name') values ('%s')" % username) # $ Alert
|
||||
User.objects.extra("insert into names_file ('name') values ('%s')" % username) # $ Alert
|
||||
|
||||
# BAD (but currently no custom query to find this)
|
||||
#
|
||||
|
||||
@@ -20,15 +20,15 @@ class User(Base):
|
||||
|
||||
|
||||
@app.route("/users/<username>")
|
||||
def show_user(username):
|
||||
def show_user(username): # $ Source
|
||||
session = sqlalchemy.orm.Session(engine)
|
||||
|
||||
# BAD, normal SQL injection
|
||||
stmt = sqlalchemy.text("SELECT * FROM users WHERE username = '{}'".format(username))
|
||||
stmt = sqlalchemy.text("SELECT * FROM users WHERE username = '{}'".format(username)) # $ Alert
|
||||
results = session.execute(stmt).fetchall()
|
||||
|
||||
# BAD, allows SQL injection
|
||||
username_formatted_for_sql = sqlalchemy.text("'{}'".format(username))
|
||||
username_formatted_for_sql = sqlalchemy.text("'{}'".format(username)) # $ Alert
|
||||
stmt = sqlalchemy.select(User).where(User.username == username_formatted_for_sql)
|
||||
results = session.execute(stmt).scalars().all()
|
||||
|
||||
@@ -38,14 +38,14 @@ def show_user(username):
|
||||
|
||||
|
||||
# All of these should be flagged by query
|
||||
t1 = sqlalchemy.text(username)
|
||||
t2 = sqlalchemy.text(text=username)
|
||||
t3 = sqlalchemy.sql.text(username)
|
||||
t4 = sqlalchemy.sql.text(text=username)
|
||||
t5 = sqlalchemy.sql.expression.text(username)
|
||||
t6 = sqlalchemy.sql.expression.text(text=username)
|
||||
t7 = sqlalchemy.sql.expression.TextClause(username)
|
||||
t8 = sqlalchemy.sql.expression.TextClause(text=username)
|
||||
t1 = sqlalchemy.text(username) # $ Alert
|
||||
t2 = sqlalchemy.text(text=username) # $ Alert
|
||||
t3 = sqlalchemy.sql.text(username) # $ Alert
|
||||
t4 = sqlalchemy.sql.text(text=username) # $ Alert
|
||||
t5 = sqlalchemy.sql.expression.text(username) # $ Alert
|
||||
t6 = sqlalchemy.sql.expression.text(text=username) # $ Alert
|
||||
t7 = sqlalchemy.sql.expression.TextClause(username) # $ Alert
|
||||
t8 = sqlalchemy.sql.expression.TextClause(text=username) # $ Alert
|
||||
|
||||
t9 = db.text(username)
|
||||
t10 = db.text(text=username)
|
||||
t9 = db.text(username) # $ Alert
|
||||
t10 = db.text(text=username) # $ Alert
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-090/LdapInjection.ql
|
||||
query: Security/CWE-090/LdapInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import request, Flask
|
||||
from flask import request, Flask # $ Source
|
||||
import ldap3
|
||||
|
||||
app = Flask(__name__)
|
||||
@@ -18,7 +18,7 @@ def normal():
|
||||
|
||||
srv = ldap3.Server('ldap://127.0.0.1')
|
||||
conn = ldap3.Connection(srv, user=dn, auto_bind=True)
|
||||
conn.search(dn, search_filter)
|
||||
conn.search(dn, search_filter) # $ Alert
|
||||
|
||||
|
||||
@app.route("/direct")
|
||||
@@ -35,7 +35,7 @@ def direct():
|
||||
|
||||
srv = ldap3.Server('ldap://127.0.0.1')
|
||||
conn = ldap3.Connection(srv, user=dn, auto_bind=True).search(
|
||||
dn, search_filter)
|
||||
dn, search_filter) # $ Alert
|
||||
|
||||
# if __name__ == "__main__":
|
||||
# app.run(debug=True)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import request, Flask
|
||||
from flask import request, Flask # $ Source
|
||||
import ldap
|
||||
|
||||
app = Flask(__name__)
|
||||
@@ -18,7 +18,7 @@ def normal():
|
||||
|
||||
ldap_connection = ldap.initialize("ldap://127.0.0.1")
|
||||
user = ldap_connection.search_s(
|
||||
dn, ldap.SCOPE_SUBTREE, search_filter)
|
||||
dn, ldap.SCOPE_SUBTREE, search_filter) # $ Alert
|
||||
|
||||
|
||||
@app.route("/direct")
|
||||
@@ -34,7 +34,7 @@ def direct():
|
||||
search_filter = "(user={})".format(unsafe_filter)
|
||||
|
||||
user = ldap.initialize("ldap://127.0.0.1").search_s(
|
||||
dn, ldap.SCOPE_SUBTREE, search_filter)
|
||||
dn, ldap.SCOPE_SUBTREE, search_filter) # $ Alert
|
||||
|
||||
|
||||
@app.route("/normal_argbyname")
|
||||
@@ -52,7 +52,7 @@ def normal_argbyname():
|
||||
|
||||
ldap_connection = ldap.initialize("ldap://127.0.0.1")
|
||||
user = ldap_connection.search_s(
|
||||
dn, ldap.SCOPE_SUBTREE, filterstr=search_filter)
|
||||
dn, ldap.SCOPE_SUBTREE, filterstr=search_filter) # $ Alert
|
||||
|
||||
|
||||
# if __name__ == "__main__":
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-113/HeaderInjection.ql
|
||||
query: Security/CWE-113/HeaderInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-116/BadTagFilter.ql
|
||||
query: Security/CWE-116/BadTagFilter.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import re
|
||||
|
||||
filters = [
|
||||
re.compile(r"""<script.*?>.*?<\/script>""", re.IGNORECASE), # NOT OK - doesn't match newlines or `</script >`
|
||||
re.compile(r"""<script.*?>.*?<\/script>""", re.IGNORECASE | re.DOTALL), # NOT OK - doesn't match `</script >`
|
||||
re.compile(r"""<script.*?>.*?<\/script>""", re.IGNORECASE), # $ Alert # NOT OK - doesn't match newlines or `</script >`
|
||||
re.compile(r"""<script.*?>.*?<\/script>""", re.IGNORECASE | re.DOTALL), # $ Alert # NOT OK - doesn't match `</script >`
|
||||
re.compile(r"""<script.*?>.*?<\/script[^>]*>""", re.IGNORECASE | re.DOTALL), # OK
|
||||
re.compile(r"""<!--.*-->""", re.IGNORECASE | re.DOTALL), # OK - we don't care regexps that only match comments
|
||||
re.compile(r"""<!--.*--!?>""", re.IGNORECASE | re.DOTALL), # OK
|
||||
re.compile(r"""<!--.*--!?>""", re.IGNORECASE), # NOT OK, does not match newlines
|
||||
re.compile(r"""<!--.*--!?>""", re.IGNORECASE), # $ Alert # NOT OK, does not match newlines
|
||||
re.compile(r"""(?is)<!--.*--!?>"""), # OK
|
||||
re.compile(r"""(?i)<!--.*--!?>"""), # NOT OK, does not match newlines [NOT DETECTED]
|
||||
re.compile(r"""<script.*?>(.|\s)*?<\/script[^>]*>""", re.IGNORECASE), # NOT OK - doesn't match inside the script tag
|
||||
re.compile(r"""<script[^>]*?>.*?<\/script[^>]*>""", re.IGNORECASE), # NOT OK - doesn't match newlines inside the content
|
||||
re.compile(r"""<script(\s|\w|=|")*?>.*?<\/script[^>]*>""", re.IGNORECASE | re.DOTALL), # NOT OK - does not match single quotes for attribute values
|
||||
re.compile(r"""<script(\s|\w|=|')*?>.*?<\/script[^>]*>""", re.IGNORECASE | re.DOTALL), # NOT OK - does not match double quotes for attribute values
|
||||
re.compile(r"""<script( |\n|\w|=|'|")*?>.*?<\/script[^>]*>""", re.IGNORECASE | re.DOTALL), # NOT OK - does not match tabs between attributes
|
||||
re.compile(r"""<script.*?>.*?<\/script[^>]*>""", re.re.DOTALL), # NOT OK - does not match uppercase SCRIPT tags
|
||||
re.compile(r"""<(script|SCRIPT).*?>.*?<\/(script|SCRIPT)[^>]*>""", re.DOTALL), # NOT OK - does not match mixed case script tags
|
||||
re.compile(r"""<script[^>]*?>[\s\S]*?<\/script.*>""", re.IGNORECASE), # NOT OK - doesn't match newlines in the end tag
|
||||
re.compile(r"""(?i)<!--.*--!?>"""), # $ Alert # NOT OK, does not match newlines [NOT DETECTED]
|
||||
re.compile(r"""<script.*?>(.|\s)*?<\/script[^>]*>""", re.IGNORECASE), # $ Alert # NOT OK - doesn't match inside the script tag
|
||||
re.compile(r"""<script[^>]*?>.*?<\/script[^>]*>""", re.IGNORECASE), # $ Alert # NOT OK - doesn't match newlines inside the content
|
||||
re.compile(r"""<script(\s|\w|=|")*?>.*?<\/script[^>]*>""", re.IGNORECASE | re.DOTALL), # $ Alert # NOT OK - does not match single quotes for attribute values
|
||||
re.compile(r"""<script(\s|\w|=|')*?>.*?<\/script[^>]*>""", re.IGNORECASE | re.DOTALL), # $ Alert # NOT OK - does not match double quotes for attribute values
|
||||
re.compile(r"""<script( |\n|\w|=|'|")*?>.*?<\/script[^>]*>""", re.IGNORECASE | re.DOTALL), # $ Alert # NOT OK - does not match tabs between attributes
|
||||
re.compile(r"""<script.*?>.*?<\/script[^>]*>""", re.re.DOTALL), # $ Alert # NOT OK - does not match uppercase SCRIPT tags
|
||||
re.compile(r"""<(script|SCRIPT).*?>.*?<\/(script|SCRIPT)[^>]*>""", re.DOTALL), # $ Alert # NOT OK - does not match mixed case script tags
|
||||
re.compile(r"""<script[^>]*?>[\s\S]*?<\/script.*>""", re.IGNORECASE), # $ Alert # NOT OK - doesn't match newlines in the end tag
|
||||
re.compile(r"""<script[^>]*?>[\s\S]*?<\/script[^>]*?>""", re.IGNORECASE), # OK
|
||||
re.compile(r"""<script\b[^>]*>([\s\S]*?)<\/script>""", re.IGNORECASE | re.DOTALL), # NOT OK - too strict matching on the end tag
|
||||
re.compile(r"""<(?:!--([\S|\s]*?)-->)|([^\/\s>]+)[\S\s]*?>"""), #// NOT OK - doesn't match comments with the right capture groups
|
||||
re.compile(r"""<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))"""), # NOT OK - capture groups
|
||||
re.compile(r"""(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)""", re.IGNORECASE), # NOT OK - capture groups
|
||||
re.compile(r"""<(?:(?:!--([\w\W]*?)-->)|(?:!\[CDATA\[([\w\W]*?)\]\]>)|(?:!DOCTYPE([\w\W]*?)>)|(?:\?([^\s\/<>]+) ?([\w\W]*?)[?/]>)|(?:\/([A-Za-z][A-Za-z0-9\-_\:\.]*)>)|(?:([A-Za-z][A-Za-z0-9\-_\:\.]*)((?:\s+[^"'>]+(?:(?:"[^"]*")|(?:'[^']*')|[^>]*))*|\/|\s+)>))"""), # NOT OK - capture groups
|
||||
re.compile(r"""<script\b[^>]*>([\s\S]*?)<\/script>""", re.IGNORECASE | re.DOTALL), # $ Alert # NOT OK - too strict matching on the end tag
|
||||
re.compile(r"""<(?:!--([\S|\s]*?)-->)|([^\/\s>]+)[\S\s]*?>"""), # $ Alert #// NOT OK - doesn't match comments with the right capture groups
|
||||
re.compile(r"""<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))"""), # $ Alert # NOT OK - capture groups
|
||||
re.compile(r"""(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)""", re.IGNORECASE), # $ Alert # NOT OK - capture groups
|
||||
re.compile(r"""<(?:(?:!--([\w\W]*?)-->)|(?:!\[CDATA\[([\w\W]*?)\]\]>)|(?:!DOCTYPE([\w\W]*?)>)|(?:\?([^\s\/<>]+) ?([\w\W]*?)[?/]>)|(?:\/([A-Za-z][A-Za-z0-9\-_\:\.]*)>)|(?:([A-Za-z][A-Za-z0-9\-_\:\.]*)((?:\s+[^"'>]+(?:(?:"[^"]*")|(?:'[^']*')|[^>]*))*|\/|\s+)>))"""), # $ Alert # NOT OK - capture groups
|
||||
]
|
||||
|
||||
doFilters(filters)
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
#select
|
||||
| LogInjectionBad.py:18:21:18:40 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:18:21:18:40 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| LogInjectionBad.py:24:18:24:37 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:24:18:24:37 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| LogInjectionBad.py:30:25:30:44 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:30:25:30:44 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| LogInjectionBad.py:37:19:37:38 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:37:19:37:38 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value |
|
||||
edges
|
||||
| LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for request | provenance | |
|
||||
| LogInjectionBad.py:7:19:7:25 | ControlFlowNode for request | LogInjectionBad.py:17:12:17:18 | ControlFlowNode for request | provenance | |
|
||||
@@ -44,8 +49,3 @@ nodes
|
||||
| LogInjectionBad.py:35:12:35:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| LogInjectionBad.py:37:19:37:38 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
||||
subpaths
|
||||
#select
|
||||
| LogInjectionBad.py:18:21:18:40 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:18:21:18:40 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| LogInjectionBad.py:24:18:24:37 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:24:18:24:37 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| LogInjectionBad.py:30:25:30:44 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:30:25:30:44 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| LogInjectionBad.py:37:19:37:38 | ControlFlowNode for BinaryExpr | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | LogInjectionBad.py:37:19:37:38 | ControlFlowNode for BinaryExpr | This log entry depends on a $@. | LogInjectionBad.py:7:19:7:25 | ControlFlowNode for ImportMember | user-provided value |
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-117/LogInjection.ql
|
||||
query: Security/CWE-117/LogInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
@Desc :Log Injection
|
||||
"""
|
||||
from flask import Flask
|
||||
from flask import request
|
||||
from flask import request # $ Source
|
||||
from django.utils.log import request_logger
|
||||
import logging
|
||||
|
||||
@@ -15,26 +15,26 @@ app = Flask(__name__)
|
||||
@app.route('/bad1')
|
||||
def bad1():
|
||||
name = request.args.get('name')
|
||||
app.logger.info('User name: ' + name) # Bad
|
||||
app.logger.info('User name: ' + name) # $ Alert # Bad
|
||||
return 'bad1'
|
||||
|
||||
@app.route('/bad2')
|
||||
def bad2():
|
||||
name = request.args.get('name')
|
||||
logging.info('User name: ' + name) # Bad
|
||||
logging.info('User name: ' + name) # $ Alert # Bad
|
||||
return 'bad2'
|
||||
|
||||
@app.route('/bad3')
|
||||
def bad3():
|
||||
name = request.args.get('name')
|
||||
request_logger.warn('User name: ' + name) # Bad
|
||||
request_logger.warn('User name: ' + name) # $ Alert # Bad
|
||||
return 'bad3'
|
||||
|
||||
@app.route('/bad4')
|
||||
def bad4():
|
||||
name = request.args.get('name')
|
||||
logtest = logging.getLogger('test')
|
||||
logtest.debug('User name: ' + name) # Bad
|
||||
logtest.debug('User name: ' + name) # $ Alert # Bad
|
||||
return 'bad4'
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1 +1 @@
|
||||
Security/CWE-209/StackTraceExposure.ql
|
||||
query: Security/CWE-209/StackTraceExposure.ql
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-215/FlaskDebug.ql
|
||||
query: Security/CWE-215/FlaskDebug.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -7,8 +7,8 @@ def main():
|
||||
raise Exception()
|
||||
|
||||
# bad
|
||||
app.run(debug=True)
|
||||
app.run('host', 8080, True)
|
||||
app.run(debug=True) # $ Alert
|
||||
app.run('host', 8080, True) # $ Alert
|
||||
|
||||
# okay
|
||||
app.run()
|
||||
@@ -23,11 +23,11 @@ app.notrun(debug=True)
|
||||
|
||||
DEBUG = True
|
||||
|
||||
app.run(debug=DEBUG) # NOT OK
|
||||
app.run(debug=DEBUG) # $ Alert # NOT OK
|
||||
|
||||
DEBUG = 1
|
||||
|
||||
app.run(debug=DEBUG) # NOT OK
|
||||
app.run(debug=DEBUG) # $ Alert # NOT OK
|
||||
|
||||
if False:
|
||||
app.run(debug=True)
|
||||
@@ -35,12 +35,12 @@ if False:
|
||||
|
||||
|
||||
runapp = app.run
|
||||
runapp(debug=True) # NOT OK
|
||||
runapp(debug=True) # $ Alert # NOT OK
|
||||
|
||||
|
||||
# imports from other module
|
||||
import settings
|
||||
app.run(debug=settings.ALWAYS_TRUE) # NOT OK
|
||||
app.run(debug=settings.ALWAYS_TRUE) # $ Alert # NOT OK
|
||||
|
||||
|
||||
# depending on environment values
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-285/PamAuthorization.ql
|
||||
query: Security/CWE-285/PamAuthorization.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from ctypes import CDLL, POINTER, Structure, byref
|
||||
from ctypes import c_char_p, c_int
|
||||
from ctypes.util import find_library
|
||||
from flask import Flask, request, redirect
|
||||
from flask import Flask, request, redirect # $ Source
|
||||
|
||||
|
||||
class PamHandle(Structure):
|
||||
@@ -73,7 +73,7 @@ def bad():
|
||||
conv = PamConv(None, 0)
|
||||
retval = pam_start(service, username, byref(conv), byref(handle))
|
||||
|
||||
retval = pam_authenticate(handle, 0)
|
||||
retval = pam_authenticate(handle, 0) # $ Alert
|
||||
# NOT OK: no call to `pam_acct_mgmt`
|
||||
auth_success = retval == 0
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-295/MissingHostKeyValidation.ql
|
||||
query: Security/CWE-295/MissingHostKeyValidation.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -2,19 +2,19 @@ from paramiko.client import AutoAddPolicy, WarningPolicy, RejectPolicy, SSHClien
|
||||
|
||||
client = SSHClient()
|
||||
|
||||
client.set_missing_host_key_policy(AutoAddPolicy) # bad
|
||||
client.set_missing_host_key_policy(AutoAddPolicy) # $ Alert # bad
|
||||
client.set_missing_host_key_policy(RejectPolicy) # good
|
||||
client.set_missing_host_key_policy(WarningPolicy) # bad
|
||||
client.set_missing_host_key_policy(WarningPolicy) # $ Alert # bad
|
||||
|
||||
# Using instances
|
||||
|
||||
client.set_missing_host_key_policy(AutoAddPolicy()) # bad
|
||||
client.set_missing_host_key_policy(AutoAddPolicy()) # $ Alert # bad
|
||||
client.set_missing_host_key_policy(RejectPolicy()) # good
|
||||
client.set_missing_host_key_policy(WarningPolicy()) # bad
|
||||
client.set_missing_host_key_policy(WarningPolicy()) # $ Alert # bad
|
||||
|
||||
# different import
|
||||
|
||||
import paramiko
|
||||
|
||||
client = paramiko.SSHClient()
|
||||
client.set_missing_host_key_policy(paramiko.AutoAddPolicy) # bad
|
||||
client.set_missing_host_key_policy(paramiko.AutoAddPolicy) # $ Alert # bad
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-295/RequestWithoutValidation.ql
|
||||
query: Security/CWE-295/RequestWithoutValidation.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -2,14 +2,14 @@ import requests
|
||||
|
||||
#Simple cases
|
||||
requests.get('https://semmle.com', verify=True) # GOOD
|
||||
requests.get('https://semmle.com', verify=False) # BAD
|
||||
requests.get('https://semmle.com', verify=False) # $ Alert # BAD
|
||||
requests.post('https://semmle.com', verify=True) # GOOD
|
||||
requests.post('https://semmle.com', verify=False) # BAD
|
||||
requests.post('https://semmle.com', verify=False) # $ Alert # BAD
|
||||
|
||||
# Simple flow
|
||||
put = requests.put
|
||||
put('https://semmle.com', verify="/path/to/cert/") # GOOD
|
||||
put('https://semmle.com', verify=False) # BAD
|
||||
put('https://semmle.com', verify=False) # $ Alert # BAD
|
||||
|
||||
#Other flow
|
||||
delete = requests.delete
|
||||
@@ -25,17 +25,17 @@ def req1(verify=False):
|
||||
patch = requests.patch
|
||||
|
||||
def req2(verify):
|
||||
patch('https://semmle.com', verify=verify) # BAD (from line 30)
|
||||
patch('https://semmle.com', verify=verify) # $ Alert # BAD (from line 30)
|
||||
|
||||
req2(False) # BAD (at line 28)
|
||||
req2("/path/to/cert/") # GOOD
|
||||
|
||||
#Falsey value
|
||||
requests.post('https://semmle.com', verify=0) # BAD
|
||||
requests.post('https://semmle.com', verify=0) # $ Alert # BAD
|
||||
|
||||
# requests treat `None` as default value, which means it is turned on
|
||||
requests.get('https://semmle.com') # OK
|
||||
requests.get('https://semmle.com', verify=None) # OK
|
||||
|
||||
s = requests.Session()
|
||||
s.get("url", verify=False) # BAD
|
||||
s.get("url", verify=False) # $ Alert # BAD
|
||||
|
||||
@@ -1,3 +1,28 @@
|
||||
#select
|
||||
| test.py:20:48:20:55 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:22:58:22:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:22:58:22:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:23:58:23:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:23:58:23:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:27:40:27:47 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:27:40:27:47 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:30:58:30:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:30:58:30:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:37:11:37:24 | ControlFlowNode for get_password() | test.py:37:11:37:24 | ControlFlowNode for get_password() | test.py:37:11:37:24 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:37:11:37:24 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:39:22:39:35 | ControlFlowNode for get_password() | test.py:39:22:39:35 | ControlFlowNode for get_password() | test.py:39:22:39:35 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:39:22:39:35 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:40:22:40:35 | ControlFlowNode for get_password() | test.py:40:22:40:35 | ControlFlowNode for get_password() | test.py:40:22:40:35 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:40:22:40:35 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:45:11:45:11 | ControlFlowNode for x | test.py:44:9:44:25 | ControlFlowNode for Attribute() | test.py:45:11:45:11 | ControlFlowNode for x | This expression logs $@ as clear text. | test.py:44:9:44:25 | ControlFlowNode for Attribute() | sensitive data (password) |
|
||||
| test.py:49:15:49:36 | ControlFlowNode for social_security_number | test.py:48:14:48:35 | ControlFlowNode for social_security_number | test.py:49:15:49:36 | ControlFlowNode for social_security_number | This expression logs $@ as clear text. | test.py:48:14:48:35 | ControlFlowNode for social_security_number | sensitive data (private) |
|
||||
| test.py:50:15:50:17 | ControlFlowNode for ssn | test.py:48:38:48:40 | ControlFlowNode for ssn | test.py:50:15:50:17 | ControlFlowNode for ssn | This expression logs $@ as clear text. | test.py:48:38:48:40 | ControlFlowNode for ssn | sensitive data (private) |
|
||||
| test.py:52:15:52:24 | ControlFlowNode for passportNo | test.py:48:54:48:63 | ControlFlowNode for passportNo | test.py:52:15:52:24 | ControlFlowNode for passportNo | This expression logs $@ as clear text. | test.py:48:54:48:63 | ControlFlowNode for passportNo | sensitive data (private) |
|
||||
| test.py:55:15:55:23 | ControlFlowNode for post_code | test.py:54:14:54:22 | ControlFlowNode for post_code | test.py:55:15:55:23 | ControlFlowNode for post_code | This expression logs $@ as clear text. | test.py:54:14:54:22 | ControlFlowNode for post_code | sensitive data (private) |
|
||||
| test.py:56:15:56:21 | ControlFlowNode for zipCode | test.py:54:25:54:31 | ControlFlowNode for zipCode | test.py:56:15:56:21 | ControlFlowNode for zipCode | This expression logs $@ as clear text. | test.py:54:25:54:31 | ControlFlowNode for zipCode | sensitive data (private) |
|
||||
| test.py:57:15:57:26 | ControlFlowNode for home_address | test.py:54:34:54:45 | ControlFlowNode for home_address | test.py:57:15:57:26 | ControlFlowNode for home_address | This expression logs $@ as clear text. | test.py:54:34:54:45 | ControlFlowNode for home_address | sensitive data (private) |
|
||||
| test.py:60:15:60:27 | ControlFlowNode for user_latitude | test.py:59:14:59:26 | ControlFlowNode for user_latitude | test.py:60:15:60:27 | ControlFlowNode for user_latitude | This expression logs $@ as clear text. | test.py:59:14:59:26 | ControlFlowNode for user_latitude | sensitive data (private) |
|
||||
| test.py:61:15:61:28 | ControlFlowNode for user_longitude | test.py:59:29:59:42 | ControlFlowNode for user_longitude | test.py:61:15:61:28 | ControlFlowNode for user_longitude | This expression logs $@ as clear text. | test.py:59:29:59:42 | ControlFlowNode for user_longitude | sensitive data (private) |
|
||||
| test.py:64:15:64:27 | ControlFlowNode for mobile_number | test.py:63:14:63:26 | ControlFlowNode for mobile_number | test.py:64:15:64:27 | ControlFlowNode for mobile_number | This expression logs $@ as clear text. | test.py:63:14:63:26 | ControlFlowNode for mobile_number | sensitive data (private) |
|
||||
| test.py:65:15:65:21 | ControlFlowNode for phoneNo | test.py:63:29:63:35 | ControlFlowNode for phoneNo | test.py:65:15:65:21 | ControlFlowNode for phoneNo | This expression logs $@ as clear text. | test.py:63:29:63:35 | ControlFlowNode for phoneNo | sensitive data (private) |
|
||||
| test.py:68:15:68:24 | ControlFlowNode for creditcard | test.py:67:14:67:23 | ControlFlowNode for creditcard | test.py:68:15:68:24 | ControlFlowNode for creditcard | This expression logs $@ as clear text. | test.py:67:14:67:23 | ControlFlowNode for creditcard | sensitive data (private) |
|
||||
| test.py:69:15:69:24 | ControlFlowNode for debit_card | test.py:67:26:67:35 | ControlFlowNode for debit_card | test.py:69:15:69:24 | ControlFlowNode for debit_card | This expression logs $@ as clear text. | test.py:67:26:67:35 | ControlFlowNode for debit_card | sensitive data (private) |
|
||||
| test.py:70:15:70:25 | ControlFlowNode for bank_number | test.py:67:38:67:48 | ControlFlowNode for bank_number | test.py:70:15:70:25 | ControlFlowNode for bank_number | This expression logs $@ as clear text. | test.py:67:38:67:48 | ControlFlowNode for bank_number | sensitive data (private) |
|
||||
| test.py:73:15:73:17 | ControlFlowNode for ccn | test.py:67:76:67:78 | ControlFlowNode for ccn | test.py:73:15:73:17 | ControlFlowNode for ccn | This expression logs $@ as clear text. | test.py:67:76:67:78 | ControlFlowNode for ccn | sensitive data (private) |
|
||||
| test.py:74:15:74:22 | ControlFlowNode for user_ccn | test.py:67:81:67:88 | ControlFlowNode for user_ccn | test.py:74:15:74:22 | ControlFlowNode for user_ccn | This expression logs $@ as clear text. | test.py:67:81:67:88 | ControlFlowNode for user_ccn | sensitive data (private) |
|
||||
edges
|
||||
| test.py:19:5:19:12 | ControlFlowNode for password | test.py:20:48:20:55 | ControlFlowNode for password | provenance | |
|
||||
| test.py:19:5:19:12 | ControlFlowNode for password | test.py:22:58:22:65 | ControlFlowNode for password | provenance | |
|
||||
@@ -67,28 +92,3 @@ nodes
|
||||
| test.py:73:15:73:17 | ControlFlowNode for ccn | semmle.label | ControlFlowNode for ccn |
|
||||
| test.py:74:15:74:22 | ControlFlowNode for user_ccn | semmle.label | ControlFlowNode for user_ccn |
|
||||
subpaths
|
||||
#select
|
||||
| test.py:20:48:20:55 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:20:48:20:55 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:22:58:22:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:22:58:22:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:23:58:23:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:23:58:23:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:27:40:27:47 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:27:40:27:47 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:30:58:30:65 | ControlFlowNode for password | test.py:19:16:19:29 | ControlFlowNode for get_password() | test.py:30:58:30:65 | ControlFlowNode for password | This expression logs $@ as clear text. | test.py:19:16:19:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:37:11:37:24 | ControlFlowNode for get_password() | test.py:37:11:37:24 | ControlFlowNode for get_password() | test.py:37:11:37:24 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:37:11:37:24 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:39:22:39:35 | ControlFlowNode for get_password() | test.py:39:22:39:35 | ControlFlowNode for get_password() | test.py:39:22:39:35 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:39:22:39:35 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:40:22:40:35 | ControlFlowNode for get_password() | test.py:40:22:40:35 | ControlFlowNode for get_password() | test.py:40:22:40:35 | ControlFlowNode for get_password() | This expression logs $@ as clear text. | test.py:40:22:40:35 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:45:11:45:11 | ControlFlowNode for x | test.py:44:9:44:25 | ControlFlowNode for Attribute() | test.py:45:11:45:11 | ControlFlowNode for x | This expression logs $@ as clear text. | test.py:44:9:44:25 | ControlFlowNode for Attribute() | sensitive data (password) |
|
||||
| test.py:49:15:49:36 | ControlFlowNode for social_security_number | test.py:48:14:48:35 | ControlFlowNode for social_security_number | test.py:49:15:49:36 | ControlFlowNode for social_security_number | This expression logs $@ as clear text. | test.py:48:14:48:35 | ControlFlowNode for social_security_number | sensitive data (private) |
|
||||
| test.py:50:15:50:17 | ControlFlowNode for ssn | test.py:48:38:48:40 | ControlFlowNode for ssn | test.py:50:15:50:17 | ControlFlowNode for ssn | This expression logs $@ as clear text. | test.py:48:38:48:40 | ControlFlowNode for ssn | sensitive data (private) |
|
||||
| test.py:52:15:52:24 | ControlFlowNode for passportNo | test.py:48:54:48:63 | ControlFlowNode for passportNo | test.py:52:15:52:24 | ControlFlowNode for passportNo | This expression logs $@ as clear text. | test.py:48:54:48:63 | ControlFlowNode for passportNo | sensitive data (private) |
|
||||
| test.py:55:15:55:23 | ControlFlowNode for post_code | test.py:54:14:54:22 | ControlFlowNode for post_code | test.py:55:15:55:23 | ControlFlowNode for post_code | This expression logs $@ as clear text. | test.py:54:14:54:22 | ControlFlowNode for post_code | sensitive data (private) |
|
||||
| test.py:56:15:56:21 | ControlFlowNode for zipCode | test.py:54:25:54:31 | ControlFlowNode for zipCode | test.py:56:15:56:21 | ControlFlowNode for zipCode | This expression logs $@ as clear text. | test.py:54:25:54:31 | ControlFlowNode for zipCode | sensitive data (private) |
|
||||
| test.py:57:15:57:26 | ControlFlowNode for home_address | test.py:54:34:54:45 | ControlFlowNode for home_address | test.py:57:15:57:26 | ControlFlowNode for home_address | This expression logs $@ as clear text. | test.py:54:34:54:45 | ControlFlowNode for home_address | sensitive data (private) |
|
||||
| test.py:60:15:60:27 | ControlFlowNode for user_latitude | test.py:59:14:59:26 | ControlFlowNode for user_latitude | test.py:60:15:60:27 | ControlFlowNode for user_latitude | This expression logs $@ as clear text. | test.py:59:14:59:26 | ControlFlowNode for user_latitude | sensitive data (private) |
|
||||
| test.py:61:15:61:28 | ControlFlowNode for user_longitude | test.py:59:29:59:42 | ControlFlowNode for user_longitude | test.py:61:15:61:28 | ControlFlowNode for user_longitude | This expression logs $@ as clear text. | test.py:59:29:59:42 | ControlFlowNode for user_longitude | sensitive data (private) |
|
||||
| test.py:64:15:64:27 | ControlFlowNode for mobile_number | test.py:63:14:63:26 | ControlFlowNode for mobile_number | test.py:64:15:64:27 | ControlFlowNode for mobile_number | This expression logs $@ as clear text. | test.py:63:14:63:26 | ControlFlowNode for mobile_number | sensitive data (private) |
|
||||
| test.py:65:15:65:21 | ControlFlowNode for phoneNo | test.py:63:29:63:35 | ControlFlowNode for phoneNo | test.py:65:15:65:21 | ControlFlowNode for phoneNo | This expression logs $@ as clear text. | test.py:63:29:63:35 | ControlFlowNode for phoneNo | sensitive data (private) |
|
||||
| test.py:68:15:68:24 | ControlFlowNode for creditcard | test.py:67:14:67:23 | ControlFlowNode for creditcard | test.py:68:15:68:24 | ControlFlowNode for creditcard | This expression logs $@ as clear text. | test.py:67:14:67:23 | ControlFlowNode for creditcard | sensitive data (private) |
|
||||
| test.py:69:15:69:24 | ControlFlowNode for debit_card | test.py:67:26:67:35 | ControlFlowNode for debit_card | test.py:69:15:69:24 | ControlFlowNode for debit_card | This expression logs $@ as clear text. | test.py:67:26:67:35 | ControlFlowNode for debit_card | sensitive data (private) |
|
||||
| test.py:70:15:70:25 | ControlFlowNode for bank_number | test.py:67:38:67:48 | ControlFlowNode for bank_number | test.py:70:15:70:25 | ControlFlowNode for bank_number | This expression logs $@ as clear text. | test.py:67:38:67:48 | ControlFlowNode for bank_number | sensitive data (private) |
|
||||
| test.py:73:15:73:17 | ControlFlowNode for ccn | test.py:67:76:67:78 | ControlFlowNode for ccn | test.py:73:15:73:17 | ControlFlowNode for ccn | This expression logs $@ as clear text. | test.py:67:76:67:78 | ControlFlowNode for ccn | sensitive data (private) |
|
||||
| test.py:74:15:74:22 | ControlFlowNode for user_ccn | test.py:67:81:67:88 | ControlFlowNode for user_ccn | test.py:74:15:74:22 | ControlFlowNode for user_ccn | This expression logs $@ as clear text. | test.py:67:81:67:88 | ControlFlowNode for user_ccn | sensitive data (private) |
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-312/CleartextLogging.ql
|
||||
query: Security/CWE-312/CleartextLogging.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -16,62 +16,62 @@ def get_cert():
|
||||
|
||||
|
||||
def log_password():
|
||||
password = get_password()
|
||||
logging.info("logging.info Password '%s'", password) # NOT OK
|
||||
password = get_password() # $ Source
|
||||
logging.info("logging.info Password '%s'", password) # $ Alert # NOT OK
|
||||
|
||||
LOGGER.log(logging.INFO, "LOGGER.log Password '%s'", password) # NOT OK
|
||||
logging.root.info("logging.root.info Password '%s'", password) # NOT OK
|
||||
LOGGER.log(logging.INFO, "LOGGER.log Password '%s'", password) # $ Alert # NOT OK
|
||||
logging.root.info("logging.root.info Password '%s'", password) # $ Alert # NOT OK
|
||||
|
||||
# name of logger variable should not matter
|
||||
foo = LOGGER
|
||||
foo.info("foo.info Password '%s'", password) # NOT OK
|
||||
foo.info("foo.info Password '%s'", password) # $ Alert # NOT OK
|
||||
|
||||
# return value from function
|
||||
get_logger().info("get_logger().info Password '%s'", password) # NOT OK
|
||||
get_logger().info("get_logger().info Password '%s'", password) # $ Alert # NOT OK
|
||||
|
||||
|
||||
def log_cert():
|
||||
logging.debug("Cert=%s", get_cert()) # OK
|
||||
|
||||
def print_password():
|
||||
print(get_password()) # NOT OK
|
||||
print(get_password()) # $ Alert # NOT OK
|
||||
|
||||
sys.stdout.write(get_password()) # NOT OK
|
||||
sys.stderr.write(get_password()) # NOT OK
|
||||
sys.stdout.write(get_password()) # $ Alert # NOT OK
|
||||
sys.stderr.write(get_password()) # $ Alert # NOT OK
|
||||
|
||||
import getpass
|
||||
|
||||
x = getpass.getpass()
|
||||
print(x) # NOT OK
|
||||
x = getpass.getpass() # $ Source
|
||||
print(x) # $ Alert # NOT OK
|
||||
|
||||
def log_private():
|
||||
def log1(social_security_number, ssn, className, passportNo):
|
||||
print(social_security_number) # NOT OK
|
||||
print(ssn) # NOT OK
|
||||
def log1(social_security_number, ssn, className, passportNo): # $ Source
|
||||
print(social_security_number) # $ Alert # NOT OK
|
||||
print(ssn) # $ Alert # NOT OK
|
||||
print(className) # OK
|
||||
print(passportNo) # NOT OK
|
||||
print(passportNo) # $ Alert # NOT OK
|
||||
|
||||
def log2(post_code, zipCode, home_address):
|
||||
print(post_code) # NOT OK
|
||||
print(zipCode) # NOT OK
|
||||
print(home_address) # NOT OK
|
||||
def log2(post_code, zipCode, home_address): # $ Source
|
||||
print(post_code) # $ Alert # NOT OK
|
||||
print(zipCode) # $ Alert # NOT OK
|
||||
print(home_address) # $ Alert # NOT OK
|
||||
|
||||
def log3(user_latitude, user_longitude):
|
||||
print(user_latitude) # NOT OK
|
||||
print(user_longitude) # NOT OK
|
||||
def log3(user_latitude, user_longitude): # $ Source
|
||||
print(user_latitude) # $ Alert # NOT OK
|
||||
print(user_longitude) # $ Alert # NOT OK
|
||||
|
||||
def log4(mobile_number, phoneNo):
|
||||
print(mobile_number) # NOT OK
|
||||
print(phoneNo) # NOT OK
|
||||
def log4(mobile_number, phoneNo): # $ Source
|
||||
print(mobile_number) # $ Alert # NOT OK
|
||||
print(phoneNo) # $ Alert # NOT OK
|
||||
|
||||
def log5(creditcard, debit_card, bank_number, bank_account, accountNo, ccn, user_ccn, succNode):
|
||||
print(creditcard) # NOT OK
|
||||
print(debit_card) # NOT OK
|
||||
print(bank_number) # NOT OK
|
||||
def log5(creditcard, debit_card, bank_number, bank_account, accountNo, ccn, user_ccn, succNode): # $ Source
|
||||
print(creditcard) # $ Alert # NOT OK
|
||||
print(debit_card) # $ Alert # NOT OK
|
||||
print(bank_number) # $ Alert # NOT OK
|
||||
print(bank_account) # NOT OK, but NOT FOUND - "account" is treated as having the "id" classification and thus excluded.
|
||||
print(accountNo) # NOT OK, but NOT FOUND - "account" is treated as having the "id" classification and thus excluded.
|
||||
print(ccn) # NOT OK
|
||||
print(user_ccn) # NOT OK
|
||||
print(ccn) # $ Alert # NOT OK
|
||||
print(user_ccn) # $ Alert # NOT OK
|
||||
print(succNode) # OK
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#select
|
||||
| test.py:12:21:12:28 | ControlFlowNode for password | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:12:21:12:28 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:13:22:13:45 | ControlFlowNode for Attribute() | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:13:22:13:45 | ControlFlowNode for Attribute() | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:15:26:15:33 | ControlFlowNode for password | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:15:26:15:33 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
edges
|
||||
| test.py:9:5:9:12 | ControlFlowNode for password | test.py:12:21:12:28 | ControlFlowNode for password | provenance | |
|
||||
| test.py:9:5:9:12 | ControlFlowNode for password | test.py:13:22:13:45 | ControlFlowNode for Attribute() | provenance | |
|
||||
@@ -10,7 +14,3 @@ nodes
|
||||
| test.py:13:22:13:45 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:15:26:15:33 | ControlFlowNode for password | semmle.label | ControlFlowNode for password |
|
||||
subpaths
|
||||
#select
|
||||
| test.py:12:21:12:28 | ControlFlowNode for password | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:12:21:12:28 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:13:22:13:45 | ControlFlowNode for Attribute() | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:13:22:13:45 | ControlFlowNode for Attribute() | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:15:26:15:33 | ControlFlowNode for password | test.py:9:16:9:29 | ControlFlowNode for get_password() | test.py:15:26:15:33 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:9:16:9:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-312/CleartextStorage.ql
|
||||
query: Security/CWE-312/CleartextStorage.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -6,10 +6,10 @@ def get_password():
|
||||
|
||||
|
||||
def write_password(filename):
|
||||
password = get_password()
|
||||
password = get_password() # $ Source
|
||||
|
||||
path = pathlib.Path(filename)
|
||||
path.write_text(password) # NOT OK
|
||||
path.write_bytes(password.encode("utf-8")) # NOT OK
|
||||
path.write_text(password) # $ Alert # NOT OK
|
||||
path.write_bytes(password.encode("utf-8")) # $ Alert # NOT OK
|
||||
|
||||
path.open("w").write(password) # NOT OK
|
||||
path.open("w").write(password) # $ Alert # NOT OK
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
#select
|
||||
| password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | This expression stores $@ as clear text. | password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | sensitive data (password) |
|
||||
| password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | This expression stores $@ as clear text. | password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | sensitive data (password) |
|
||||
| test.py:17:20:17:27 | ControlFlowNode for password | test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:17:20:17:27 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:15:16:15:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:19:25:19:29 | ControlFlowNode for lines | test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:19:25:19:29 | ControlFlowNode for lines | This expression stores $@ as clear text. | test.py:15:16:15:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
edges
|
||||
| password_in_cookie.py:7:5:7:12 | ControlFlowNode for password | password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | provenance | |
|
||||
| password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | password_in_cookie.py:7:5:7:12 | ControlFlowNode for password | provenance | |
|
||||
@@ -24,8 +29,3 @@ nodes
|
||||
| test.py:18:18:18:32 | ControlFlowNode for BinaryExpr | semmle.label | ControlFlowNode for BinaryExpr |
|
||||
| test.py:19:25:19:29 | ControlFlowNode for lines | semmle.label | ControlFlowNode for lines |
|
||||
subpaths
|
||||
#select
|
||||
| password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | password_in_cookie.py:9:33:9:40 | ControlFlowNode for password | This expression stores $@ as clear text. | password_in_cookie.py:7:16:7:43 | ControlFlowNode for Attribute() | sensitive data (password) |
|
||||
| password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | password_in_cookie.py:16:33:16:40 | ControlFlowNode for password | This expression stores $@ as clear text. | password_in_cookie.py:14:16:14:43 | ControlFlowNode for Attribute() | sensitive data (password) |
|
||||
| test.py:17:20:17:27 | ControlFlowNode for password | test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:17:20:17:27 | ControlFlowNode for password | This expression stores $@ as clear text. | test.py:15:16:15:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
| test.py:19:25:19:29 | ControlFlowNode for lines | test.py:15:16:15:29 | ControlFlowNode for get_password() | test.py:19:25:19:29 | ControlFlowNode for lines | This expression stores $@ as clear text. | test.py:15:16:15:29 | ControlFlowNode for get_password() | sensitive data (password) |
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-312/CleartextStorage.ql
|
||||
query: Security/CWE-312/CleartextStorage.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -4,14 +4,14 @@ app = Flask("Leak password")
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
password = request.args.get("password")
|
||||
password = request.args.get("password") # $ Source
|
||||
resp = make_response(render_template(...))
|
||||
resp.set_cookie("password", password) # NOT OK
|
||||
resp.set_cookie("password", password) # $ Alert # NOT OK
|
||||
return resp
|
||||
|
||||
@app.route('/')
|
||||
def index2():
|
||||
password = request.args.get("password")
|
||||
password = request.args.get("password") # $ Source
|
||||
resp = Response(...)
|
||||
resp.set_cookie("password", password) # NOT OK
|
||||
resp.set_cookie("password", password) # $ Alert # NOT OK
|
||||
return resp
|
||||
|
||||
@@ -12,11 +12,11 @@ def write_cert(filename):
|
||||
file.writelines(lines) # OK
|
||||
|
||||
def write_password(filename):
|
||||
password = get_password()
|
||||
password = get_password() # $ Source
|
||||
with open(filename, "w") as file:
|
||||
file.write(password) # NOT OK
|
||||
file.write(password) # $ Alert # NOT OK
|
||||
lines = [password + "\n"]
|
||||
file.writelines(lines) # NOT OK
|
||||
file.writelines(lines) # $ Alert # NOT OK
|
||||
|
||||
def FPs():
|
||||
# just like for cleartext-logging see that file for more elaborate tests
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-326/WeakCryptoKey.ql
|
||||
query: Security/CWE-326/WeakCryptoKey.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -65,23 +65,23 @@ RSA.generate(RSA_STRONG)
|
||||
|
||||
# Weak keys
|
||||
|
||||
dsa_gen_key(DSA_WEAK)
|
||||
ec_gen_key(EC_WEAK)
|
||||
rsa_gen_key(65537, RSA_WEAK)
|
||||
dsa_gen_key(DSA_WEAK) # $ Alert
|
||||
ec_gen_key(EC_WEAK) # $ Alert
|
||||
rsa_gen_key(65537, RSA_WEAK) # $ Alert
|
||||
|
||||
dsa_gen_key(key_size=DSA_WEAK)
|
||||
ec_gen_key(curve=EC_WEAK)
|
||||
rsa_gen_key(65537, key_size=RSA_WEAK)
|
||||
dsa_gen_key(key_size=DSA_WEAK) # $ Alert
|
||||
ec_gen_key(curve=EC_WEAK) # $ Alert
|
||||
rsa_gen_key(65537, key_size=RSA_WEAK) # $ Alert
|
||||
|
||||
DSA.generate(DSA_WEAK)
|
||||
RSA.generate(RSA_WEAK)
|
||||
DSA.generate(DSA_WEAK) # $ Alert
|
||||
RSA.generate(RSA_WEAK) # $ Alert
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Through function calls
|
||||
|
||||
def make_new_rsa_key_weak(bits):
|
||||
return RSA.generate(bits) # NOT OK
|
||||
return RSA.generate(bits) # $ Alert # NOT OK
|
||||
make_new_rsa_key_weak(RSA_WEAK)
|
||||
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-327/BrokenCryptoAlgorithm.ql
|
||||
query: Security/CWE-327/BrokenCryptoAlgorithm.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -8,11 +8,11 @@ key = os.urandom(256//8)
|
||||
secret_message = b"secret message"
|
||||
|
||||
cipher = ARC4.new(key)
|
||||
encrypted = cipher.encrypt(secret_message) # NOT OK
|
||||
encrypted = cipher.encrypt(secret_message) # $ Alert # NOT OK
|
||||
|
||||
print(secret_message, encrypted)
|
||||
|
||||
cipher = AES.new(key, AES.MODE_ECB)
|
||||
encrypted = cipher.encrypt(secret_message) # NOT OK
|
||||
encrypted = cipher.encrypt(secret_message) # $ Alert # NOT OK
|
||||
|
||||
print(secret_message, encrypted)
|
||||
|
||||
@@ -10,7 +10,7 @@ cipher = Cipher(algorithm, mode=None)
|
||||
secret_message = b"secret message"
|
||||
|
||||
encryptor = cipher.encryptor()
|
||||
encrypted = encryptor.update(secret_message) # NOT OK
|
||||
encrypted = encryptor.update(secret_message) # $ Alert # NOT OK
|
||||
encrypted += encryptor.finalize()
|
||||
|
||||
print(secret_message, encrypted)
|
||||
@@ -19,7 +19,7 @@ algorithm = algorithms.AES(key)
|
||||
cipher = Cipher(algorithm, mode=modes.ECB())
|
||||
|
||||
encryptor = cipher.encryptor()
|
||||
encrypted = encryptor.update(secret_message + b'\x80\x00') # NOT OK
|
||||
encrypted = encryptor.update(secret_message + b'\x80\x00') # $ Alert # NOT OK
|
||||
encrypted += encryptor.finalize()
|
||||
|
||||
print(secret_message, encrypted)
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-327/InsecureDefaultProtocol.ql
|
||||
query: Security/CWE-327/InsecureDefaultProtocol.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -4,4 +4,4 @@ import ssl
|
||||
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1_2)
|
||||
|
||||
# possibly insecure default
|
||||
ssl.wrap_socket()
|
||||
ssl.wrap_socket() # $ Alert
|
||||
|
||||
@@ -3,25 +3,25 @@ from OpenSSL import SSL
|
||||
from ssl import SSLContext
|
||||
|
||||
# insecure versions specified
|
||||
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv2)
|
||||
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv3)
|
||||
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1)
|
||||
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv2) # $ Alert
|
||||
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_SSLv3) # $ Alert
|
||||
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1) # $ Alert
|
||||
|
||||
SSLContext(protocol=ssl.PROTOCOL_SSLv2)
|
||||
SSLContext(protocol=ssl.PROTOCOL_SSLv3)
|
||||
SSLContext(protocol=ssl.PROTOCOL_TLSv1)
|
||||
SSLContext(protocol=ssl.PROTOCOL_SSLv2) # $ Alert
|
||||
SSLContext(protocol=ssl.PROTOCOL_SSLv3) # $ Alert
|
||||
SSLContext(protocol=ssl.PROTOCOL_TLSv1) # $ Alert
|
||||
|
||||
SSL.Context(SSL.SSLv2_METHOD)
|
||||
SSL.Context(SSL.SSLv3_METHOD)
|
||||
SSL.Context(SSL.TLSv1_METHOD)
|
||||
SSL.Context(SSL.SSLv2_METHOD) # $ Alert
|
||||
SSL.Context(SSL.SSLv3_METHOD) # $ Alert
|
||||
SSL.Context(SSL.TLSv1_METHOD) # $ Alert
|
||||
|
||||
METHOD = SSL.SSLv2_METHOD
|
||||
SSL.Context(METHOD)
|
||||
SSL.Context(METHOD) # $ Alert
|
||||
|
||||
# importing the protocol constant directly
|
||||
from ssl import PROTOCOL_SSLv2
|
||||
ssl.wrap_socket(ssl_version=PROTOCOL_SSLv2)
|
||||
SSLContext(protocol=PROTOCOL_SSLv2)
|
||||
ssl.wrap_socket(ssl_version=PROTOCOL_SSLv2) # $ Alert
|
||||
SSLContext(protocol=PROTOCOL_SSLv2) # $ Alert
|
||||
|
||||
# secure versions specified
|
||||
ssl.wrap_socket(ssl_version=ssl.PROTOCOL_TLSv1_2)
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-327/InsecureProtocol.ql
|
||||
query: Security/CWE-327/InsecureProtocol.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -22,9 +22,9 @@ with socket.create_connection((hostname, 443)) as sock:
|
||||
print(ssock.version())
|
||||
|
||||
with socket.create_connection((hostname, 443)) as sock:
|
||||
with copy_completely_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
with copy_completely_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert
|
||||
print(ssock.version())
|
||||
|
||||
with socket.create_connection((hostname, 443)) as sock:
|
||||
with copy_also_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
with copy_also_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert
|
||||
print(ssock.version())
|
||||
|
||||
@@ -10,9 +10,9 @@ with socket.create_connection((hostname, 443)) as sock:
|
||||
print(ssock.version())
|
||||
|
||||
with socket.create_connection((hostname, 443)) as sock:
|
||||
with completely_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
with completely_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert
|
||||
print(ssock.version())
|
||||
|
||||
with socket.create_connection((hostname, 443)) as sock:
|
||||
with also_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
with also_insecure_context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert
|
||||
print(ssock.version())
|
||||
|
||||
@@ -5,7 +5,7 @@ def test_fluent():
|
||||
hostname = 'www.python.org'
|
||||
context = SSL.Context(SSL.SSLv23_METHOD)
|
||||
|
||||
conn = SSL.Connection(context, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
|
||||
conn = SSL.Connection(context, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) # $ Alert
|
||||
r = conn.connect((hostname, 443))
|
||||
print(conn.get_protocol_version_name())
|
||||
|
||||
@@ -15,7 +15,7 @@ def test_fluent_no_TLSv1():
|
||||
context = SSL.Context(SSL.SSLv23_METHOD)
|
||||
context.set_options(SSL.OP_NO_TLSv1)
|
||||
|
||||
conn = SSL.Connection(context, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
|
||||
conn = SSL.Connection(context, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) # $ Alert
|
||||
r = conn.connect((hostname, 443))
|
||||
print(conn.get_protocol_version_name())
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ def test_fluent_tls():
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLS)
|
||||
|
||||
with socket.create_connection((hostname, 443)) as sock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert
|
||||
print(ssock.version())
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ def test_fluent_tls_no_TLSv1():
|
||||
context.options |= ssl.OP_NO_TLSv1
|
||||
|
||||
with socket.create_connection((hostname, 443)) as sock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert
|
||||
print(ssock.version())
|
||||
|
||||
def test_fluent_tls_client_no_TLSv1():
|
||||
@@ -25,7 +25,7 @@ def test_fluent_tls_client_no_TLSv1():
|
||||
context.options |= ssl.OP_NO_TLSv1
|
||||
|
||||
with socket.create_connection((hostname, 443)) as sock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert
|
||||
print(ssock.version())
|
||||
|
||||
def test_fluent_tls_server_no_TLSv1():
|
||||
@@ -34,7 +34,7 @@ def test_fluent_tls_server_no_TLSv1():
|
||||
context.options |= ssl.OP_NO_TLSv1
|
||||
|
||||
with socket.create_server((hostname, 443)) as sock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert
|
||||
print(ssock.version())
|
||||
|
||||
def test_fluent_tls_safe():
|
||||
@@ -54,7 +54,7 @@ def test_fluent_ssl():
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||
|
||||
with socket.create_connection((hostname, 443)) as sock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert
|
||||
print(ssock.version())
|
||||
|
||||
|
||||
@@ -68,13 +68,13 @@ def create_secure_context():
|
||||
|
||||
def create_connection(context):
|
||||
with socket.create_connection(('www.python.org', 443)) as sock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert
|
||||
print(ssock.version())
|
||||
|
||||
def test_delegated_context_unsafe():
|
||||
context = create_relaxed_context()
|
||||
with socket.create_connection(('www.python.org', 443)) as sock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert
|
||||
print(ssock.version())
|
||||
|
||||
def test_delegated_context_safe():
|
||||
@@ -94,7 +94,7 @@ def test_delegated_context_made_unsafe():
|
||||
context = create_secure_context()
|
||||
context.options &= ~ssl.OP_NO_TLSv1_1
|
||||
with socket.create_connection(('www.python.org', 443)) as sock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert
|
||||
print(ssock.version())
|
||||
|
||||
def test_delegated_connection_unsafe():
|
||||
@@ -143,7 +143,7 @@ def test_fluent_ssl_unsafe_version():
|
||||
context.minimum_version = ssl.TLSVersion.TLSv1_1
|
||||
|
||||
with socket.create_connection((hostname, 443)) as sock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert
|
||||
print(ssock.version())
|
||||
|
||||
def test_fluent_ssl_safe_version():
|
||||
@@ -162,5 +162,5 @@ def test_fluent_explicitly_unsafe():
|
||||
context.options &= ~ssl.OP_NO_SSLv3
|
||||
|
||||
with socket.create_connection((hostname, 443)) as sock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||
with context.wrap_socket(sock, server_hostname=hostname) as ssock: # $ Alert
|
||||
print(ssock.version())
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
#select
|
||||
| test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:37:2:51 | ControlFlowNode for ImportMember | test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptodome.py:2:37:2:51 | ControlFlowNode for ImportMember | Sensitive data (certificate) |
|
||||
| test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() | test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() | Sensitive data (certificate) |
|
||||
| test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | Sensitive data (password) |
|
||||
| test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() | test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() | Sensitive data (password) |
|
||||
| test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | Sensitive data (password) |
|
||||
| test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() | test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() | Sensitive data (password) |
|
||||
| test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | test_cryptography.py:3:37:3:51 | ControlFlowNode for ImportMember | test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptography.py:3:37:3:51 | ControlFlowNode for ImportMember | Sensitive data (certificate) |
|
||||
| test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() | test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() | Sensitive data (certificate) |
|
||||
| test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | Sensitive data (password) |
|
||||
| test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() | test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() | Sensitive data (password) |
|
||||
| test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | Sensitive data (password) |
|
||||
| test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | Sensitive data (password) |
|
||||
edges
|
||||
| test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | test_cryptodome.py:2:23:2:34 | ControlFlowNode for get_password | provenance | |
|
||||
| test_cryptodome.py:2:23:2:34 | ControlFlowNode for get_password | test_cryptodome.py:13:17:13:28 | ControlFlowNode for get_password | provenance | |
|
||||
@@ -61,16 +74,3 @@ nodes
|
||||
| test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | semmle.label | ControlFlowNode for get_password() |
|
||||
| test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | semmle.label | ControlFlowNode for dangerous |
|
||||
subpaths
|
||||
#select
|
||||
| test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:37:2:51 | ControlFlowNode for ImportMember | test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptodome.py:2:37:2:51 | ControlFlowNode for ImportMember | Sensitive data (certificate) |
|
||||
| test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() | test_cryptodome.py:8:19:8:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptodome.py:6:17:6:33 | ControlFlowNode for get_certificate() | Sensitive data (certificate) |
|
||||
| test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | Sensitive data (password) |
|
||||
| test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() | test_cryptodome.py:15:19:15:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:13:17:13:30 | ControlFlowNode for get_password() | Sensitive data (password) |
|
||||
| test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:2:23:2:34 | ControlFlowNode for ImportMember | Sensitive data (password) |
|
||||
| test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() | test_cryptodome.py:24:19:24:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptodome.py:20:17:20:30 | ControlFlowNode for get_password() | Sensitive data (password) |
|
||||
| test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | test_cryptography.py:3:37:3:51 | ControlFlowNode for ImportMember | test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptography.py:3:37:3:51 | ControlFlowNode for ImportMember | Sensitive data (certificate) |
|
||||
| test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() | test_cryptography.py:9:19:9:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure. | test_cryptography.py:7:17:7:33 | ControlFlowNode for get_certificate() | Sensitive data (certificate) |
|
||||
| test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | Sensitive data (password) |
|
||||
| test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() | test_cryptography.py:17:19:17:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:15:17:15:30 | ControlFlowNode for get_password() | Sensitive data (password) |
|
||||
| test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:3:23:3:34 | ControlFlowNode for ImportMember | Sensitive data (password) |
|
||||
| test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | test_cryptography.py:27:19:27:27 | ControlFlowNode for dangerous | $@ is used in a hashing algorithm (SHA256) that is insecure for password hashing, since it is not a computationally expensive hash function. | test_cryptography.py:23:17:23:30 | ControlFlowNode for get_password() | Sensitive data (password) |
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-327/WeakSensitiveDataHashing.ql
|
||||
query: Security/CWE-327/WeakSensitiveDataHashing.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
from Cryptodome.Hash import MD5, SHA256
|
||||
from my_module import get_password, get_certificate
|
||||
from my_module import get_password, get_certificate # $ Source
|
||||
|
||||
|
||||
def get_badly_hashed_certificate():
|
||||
dangerous = get_certificate()
|
||||
dangerous = get_certificate() # $ Source
|
||||
hasher = MD5.new()
|
||||
hasher.update(dangerous) # NOT OK
|
||||
hasher.update(dangerous) # $ Alert # NOT OK
|
||||
return hasher.hexdigest()
|
||||
|
||||
|
||||
def get_badly_hashed_password():
|
||||
dangerous = get_password()
|
||||
dangerous = get_password() # $ Source
|
||||
hasher = MD5.new()
|
||||
hasher.update(dangerous) # NOT OK
|
||||
hasher.update(dangerous) # $ Alert # NOT OK
|
||||
return hasher.hexdigest()
|
||||
|
||||
|
||||
def get_badly_hashed_password2():
|
||||
dangerous = get_password()
|
||||
dangerous = get_password() # $ Source
|
||||
# Although SHA-256 is a strong cryptographic hash functions,
|
||||
# it is not suitable for password hashing.
|
||||
hasher = SHA256.new()
|
||||
hasher.update(dangerous) # NOT OK
|
||||
hasher.update(dangerous) # $ Alert # NOT OK
|
||||
return hasher.hexdigest()
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from binascii import hexlify
|
||||
from my_module import get_password, get_certificate
|
||||
from my_module import get_password, get_certificate # $ Source
|
||||
|
||||
|
||||
def get_badly_hashed_certificate():
|
||||
dangerous = get_certificate()
|
||||
dangerous = get_certificate() # $ Source
|
||||
hasher = hashes.Hash(hashes.MD5())
|
||||
hasher.update(dangerous) # NOT OK
|
||||
hasher.update(dangerous) # $ Alert # NOT OK
|
||||
digest = hasher.finalize()
|
||||
return hexlify(digest).decode("utf-8")
|
||||
|
||||
|
||||
def get_badly_hashed_password():
|
||||
dangerous = get_password()
|
||||
dangerous = get_password() # $ Source
|
||||
hasher = hashes.Hash(hashes.MD5())
|
||||
hasher.update(dangerous) # NOT OK
|
||||
hasher.update(dangerous) # $ Alert # NOT OK
|
||||
digest = hasher.finalize()
|
||||
return hexlify(digest).decode("utf-8")
|
||||
|
||||
|
||||
def get_badly_hashed_password2():
|
||||
dangerous = get_password()
|
||||
dangerous = get_password() # $ Source
|
||||
# Although SHA-256 is a strong cryptographic hash functions,
|
||||
# it is not suitable for password hashing.
|
||||
hasher = hashes.Hash(hashes.SHA256())
|
||||
hasher.update(dangerous) # NOT OK
|
||||
hasher.update(dangerous) # $ Alert # NOT OK
|
||||
digest = hasher.finalize()
|
||||
return hexlify(digest).decode("utf-8")
|
||||
|
||||
@@ -2,19 +2,19 @@ from tempfile import mktemp
|
||||
import os
|
||||
|
||||
def write_results1(results):
|
||||
filename = mktemp()
|
||||
filename = mktemp() # $ Alert
|
||||
with open(filename, "w+") as f:
|
||||
f.write(results)
|
||||
print("Results written to", filename)
|
||||
|
||||
def write_results2(results):
|
||||
filename = os.tempnam()
|
||||
filename = os.tempnam() # $ Alert
|
||||
with open(filename, "w+") as f:
|
||||
f.write(results)
|
||||
print("Results written to", filename)
|
||||
|
||||
def write_results3(results):
|
||||
filename = os.tmpnam()
|
||||
filename = os.tmpnam() # $ Alert
|
||||
with open(filename, "w+") as f:
|
||||
f.write(results)
|
||||
print("Results written to", filename)
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-377/InsecureTemporaryFile.ql
|
||||
query: Security/CWE-377/InsecureTemporaryFile.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
#select
|
||||
| unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| unsafe_deserialization.py:24:24:24:30 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:24:24:24:30 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
edges
|
||||
| unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for request | provenance | |
|
||||
| unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for request | unsafe_deserialization.py:14:15:14:21 | ControlFlowNode for request | provenance | |
|
||||
@@ -22,9 +28,3 @@ nodes
|
||||
| unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | semmle.label | ControlFlowNode for payload |
|
||||
| unsafe_deserialization.py:24:24:24:30 | ControlFlowNode for payload | semmle.label | ControlFlowNode for payload |
|
||||
subpaths
|
||||
#select
|
||||
| unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:15:18:15:24 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:16:15:16:21 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:18:19:18:25 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:21:16:21:22 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| unsafe_deserialization.py:24:24:24:30 | ControlFlowNode for payload | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | unsafe_deserialization.py:24:24:24:30 | ControlFlowNode for payload | Unsafe deserialization depends on a $@. | unsafe_deserialization.py:8:26:8:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-502/UnsafeDeserialization.ql
|
||||
query: Security/CWE-502/UnsafeDeserialization.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -5,20 +5,20 @@ import marshal
|
||||
|
||||
from yaml import SafeLoader
|
||||
|
||||
from flask import Flask, request
|
||||
from flask import Flask, request # $ Source
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def hello():
|
||||
payload = request.args.get("payload")
|
||||
pickle.loads(payload) # NOT OK
|
||||
yaml.load(payload) # NOT OK
|
||||
pickle.loads(payload) # $ Alert # NOT OK
|
||||
yaml.load(payload) # $ Alert # NOT OK
|
||||
yaml.load(payload, Loader=SafeLoader) # OK
|
||||
marshal.loads(payload) # NOT OK
|
||||
marshal.loads(payload) # $ Alert # NOT OK
|
||||
|
||||
import dill
|
||||
dill.loads(payload) # NOT OK
|
||||
dill.loads(payload) # $ Alert # NOT OK
|
||||
|
||||
import pandas
|
||||
pandas.read_pickle(payload) # NOT OK
|
||||
pandas.read_pickle(payload) # $ Alert # NOT OK
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
#select
|
||||
| test.py:8:21:8:26 | ControlFlowNode for target | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:8:21:8:26 | ControlFlowNode for target | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:32:21:32:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:32:21:32:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:39:21:39:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:39:21:39:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:46:21:46:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:46:21:46:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:62:21:62:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:62:21:62:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:69:21:69:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:69:21:69:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:76:21:76:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:76:21:76:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:83:21:83:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:83:21:83:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:93:18:93:26 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:93:18:93:26 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:114:25:114:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:114:25:114:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:140:25:140:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:140:25:140:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:148:25:148:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:148:25:148:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
edges
|
||||
| test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:1:26:1:32 | ControlFlowNode for request | provenance | |
|
||||
| test.py:1:26:1:32 | ControlFlowNode for request | test.py:7:14:7:20 | ControlFlowNode for request | provenance | |
|
||||
@@ -138,16 +151,3 @@ nodes
|
||||
| test.py:145:17:145:46 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:148:25:148:33 | ControlFlowNode for untrusted | semmle.label | ControlFlowNode for untrusted |
|
||||
subpaths
|
||||
#select
|
||||
| test.py:8:21:8:26 | ControlFlowNode for target | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:8:21:8:26 | ControlFlowNode for target | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:32:21:32:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:32:21:32:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:39:21:39:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:39:21:39:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:46:21:46:24 | ControlFlowNode for safe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:46:21:46:24 | ControlFlowNode for safe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:62:21:62:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:62:21:62:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:69:21:69:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:69:21:69:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:76:21:76:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:76:21:76:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:83:21:83:26 | ControlFlowNode for unsafe | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:83:21:83:26 | ControlFlowNode for unsafe | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:93:18:93:26 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:93:18:93:26 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:114:25:114:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:114:25:114:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:140:25:140:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:140:25:140:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:148:25:148:33 | ControlFlowNode for untrusted | test.py:1:26:1:32 | ControlFlowNode for ImportMember | test.py:148:25:148:33 | ControlFlowNode for untrusted | Untrusted URL redirection depends on a $@. | test.py:1:26:1:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Security/CWE-601/UrlRedirect.ql
|
||||
|
||||
query: Security/CWE-601/UrlRedirect.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
from flask import Flask, request, redirect
|
||||
from flask import Flask, request, redirect # $ Source
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/')
|
||||
def hello():
|
||||
target = request.args.get('target', '')
|
||||
return redirect(target, code=302)
|
||||
return redirect(target, code=302) # $ Alert
|
||||
|
||||
|
||||
# Check for safe prefixes
|
||||
@@ -29,21 +29,21 @@ def ok2():
|
||||
def ok3():
|
||||
untrusted = request.args.get('target', '')
|
||||
safe = "https://safe.com/{}".format(untrusted)
|
||||
return redirect(safe, code=302) # FP
|
||||
return redirect(safe, code=302) # $ SPURIOUS: Alert # FP
|
||||
|
||||
|
||||
@app.route('/ok4')
|
||||
def ok4():
|
||||
untrusted = request.args.get('target', '')
|
||||
safe = f"https://safe.com/{untrusted}"
|
||||
return redirect(safe, code=302) # FP
|
||||
return redirect(safe, code=302) # $ SPURIOUS: Alert # FP
|
||||
|
||||
|
||||
@app.route('/ok5')
|
||||
def ok5():
|
||||
untrusted = request.args.get('target', '')
|
||||
safe = "https://safe.com/%s" % untrusted
|
||||
return redirect(safe, code=302) # FP
|
||||
return redirect(safe, code=302) # $ SPURIOUS: Alert # FP
|
||||
|
||||
|
||||
@app.route('/const-str-compare')
|
||||
@@ -59,41 +59,41 @@ def const_str_compare():
|
||||
def not_ok1():
|
||||
untrusted = request.args.get('target', '')
|
||||
unsafe = untrusted + "?login=success"
|
||||
return redirect(unsafe, code=302)
|
||||
return redirect(unsafe, code=302) # $ Alert
|
||||
|
||||
|
||||
@app.route('/not_ok2')
|
||||
def not_ok2():
|
||||
untrusted = request.args.get('target', '')
|
||||
unsafe = "{}?login=success".format(untrusted)
|
||||
return redirect(unsafe, code=302)
|
||||
return redirect(unsafe, code=302) # $ Alert
|
||||
|
||||
|
||||
@app.route('/not_ok3')
|
||||
def not_ok3():
|
||||
untrusted = request.args.get('target', '')
|
||||
unsafe = f"{untrusted}?login=success"
|
||||
return redirect(unsafe, code=302)
|
||||
return redirect(unsafe, code=302) # $ Alert
|
||||
|
||||
|
||||
@app.route('/not_ok4')
|
||||
def not_ok4():
|
||||
untrusted = request.args.get('target', '')
|
||||
unsafe = "%s?login=success" % untrusted
|
||||
return redirect(unsafe, code=302)
|
||||
return redirect(unsafe, code=302) # $ Alert
|
||||
|
||||
from django.utils.http import url_has_allowed_host_and_scheme
|
||||
import math
|
||||
import math
|
||||
|
||||
@app.route('/ok6')
|
||||
def ok6():
|
||||
untrusted = request.args.get('target', '')
|
||||
# random chance.
|
||||
# random chance.
|
||||
if math.random() > 0.5:
|
||||
redirect(untrusted, code=302) # NOT OK
|
||||
redirect(untrusted, code=302) # $ Alert # NOT OK
|
||||
if url_has_allowed_host_and_scheme(untrusted, allowed_hosts=None):
|
||||
return redirect(untrusted, code=302) # OK
|
||||
|
||||
|
||||
return redirect("https://example.com", code=302) # OK
|
||||
|
||||
import yarl
|
||||
@@ -111,7 +111,7 @@ def not_ok5():
|
||||
untrusted = request.args.get('target', '')
|
||||
# no backslash replace
|
||||
if not yarl.URL(untrusted).is_absolute():
|
||||
return redirect(untrusted, code=302) # NOT OK
|
||||
return redirect(untrusted, code=302) # $ Alert # NOT OK
|
||||
return redirect("/", code=302)
|
||||
|
||||
from urllib.parse import urlparse
|
||||
@@ -137,7 +137,7 @@ def not_ok6():
|
||||
untrusted = request.args.get('target', '')
|
||||
# no backslash replace
|
||||
if not urlparse(untrusted).netloc:
|
||||
return redirect(untrusted, code=302) # NOT OK
|
||||
return redirect(untrusted, code=302) # $ Alert # NOT OK
|
||||
return redirect("/", code=302)
|
||||
|
||||
@app.route('/not_ok7')
|
||||
@@ -145,7 +145,7 @@ def not_ok7():
|
||||
untrusted = request.args.get('target', '')
|
||||
# wrong check
|
||||
if urlparse(untrusted).netloc != "":
|
||||
return redirect(untrusted, code=302) # NOT OK
|
||||
return redirect(untrusted, code=302) # $ Alert # NOT OK
|
||||
return redirect("/", code=302)
|
||||
|
||||
@app.route('/ok10')
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-611/Xxe.ql
|
||||
query: Security/CWE-611/Xxe.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import Flask, request
|
||||
from flask import Flask, request # $ Source
|
||||
import lxml.etree
|
||||
import markupsafe
|
||||
|
||||
@@ -7,7 +7,7 @@ app = Flask(__name__)
|
||||
@app.route("/vuln-handler")
|
||||
def vuln_handler():
|
||||
xml_content = request.args['xml_content']
|
||||
return lxml.etree.fromstring(xml_content).text
|
||||
return lxml.etree.fromstring(xml_content).text # $ Alert
|
||||
|
||||
@app.route("/safe-handler")
|
||||
def safe_handler():
|
||||
@@ -28,7 +28,7 @@ def super_vuln_handler():
|
||||
# allows DoS attacks
|
||||
huge_tree=True,
|
||||
)
|
||||
return lxml.etree.fromstring(xml_content, parser=parser).text
|
||||
return lxml.etree.fromstring(xml_content, parser=parser).text # $ Alert
|
||||
|
||||
@app.route("/sanitized-handler")
|
||||
def sanitized_handler():
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-643/XpathInjection.ql
|
||||
query: Security/CWE-643/XpathInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -6,11 +6,11 @@ from django.http import HttpResponse
|
||||
from django.template import Template, Context, Engine, engines
|
||||
|
||||
|
||||
def a(request):
|
||||
def a(request): # $ Source
|
||||
value = request.GET['xpath']
|
||||
f = StringIO('<foo><bar></bar></foo>')
|
||||
tree = etree.parse(f)
|
||||
r = tree.xpath("/tag[@id='%s']" % value)
|
||||
r = tree.xpath("/tag[@id='%s']" % value) # $ Alert
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from io import StringIO
|
||||
from flask import Flask, request
|
||||
from flask import Flask, request # $ Source
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@@ -11,7 +11,7 @@ def xpath1():
|
||||
xpathQuery = request.args.get('xml', '')
|
||||
f = StringIO('<foo><bar></bar></foo>')
|
||||
tree = etree.parse(f)
|
||||
r = tree.xpath(xpathQuery)
|
||||
r = tree.xpath(xpathQuery) # $ Alert
|
||||
|
||||
|
||||
@app.route("/xpath2")
|
||||
@@ -20,7 +20,7 @@ def xpath2():
|
||||
xpathQuery = request.args.get('xml', '')
|
||||
|
||||
root = etree.XML("<root><a>TEXT</a></root>")
|
||||
find_text = etree.XPath(xpathQuery)
|
||||
find_text = etree.XPath(xpathQuery) # $ Alert
|
||||
text = find_text(root)[0]
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ def xpath3():
|
||||
from lxml import etree
|
||||
xpathQuery = request.args.get('xml', '')
|
||||
root = etree.XML("<root><a>TEXT</a></root>")
|
||||
find_text = etree.XPath(xpathQuery, smart_strings=False)
|
||||
find_text = etree.XPath(xpathQuery, smart_strings=False) # $ Alert
|
||||
text = find_text(root)[0]
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ def xpath4():
|
||||
from lxml import etree
|
||||
xpathQuery = request.args.get('xml', '')
|
||||
root = etree.XML("<root><a>TEXT</a></root>")
|
||||
find_text = etree.ETXPath(xpathQuery)
|
||||
find_text = etree.ETXPath(xpathQuery) # $ Alert
|
||||
text = find_text(root)[0]
|
||||
|
||||
@app.route("/xpath5")
|
||||
@@ -46,4 +46,4 @@ def xpath5():
|
||||
import libxml2
|
||||
xpathQuery = request.args.get('xml', '')
|
||||
doc = libxml2.parseFile('xpath_injection/credential.xml')
|
||||
results = doc.xpathEval(xpathQuery)
|
||||
results = doc.xpathEval(xpathQuery) # $ Alert
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
#select
|
||||
| test.py:8:30:8:33 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:8:30:8:33 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:8:19:8:21 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:9:32:9:35 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:9:32:9:35 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings starting with '0.9' and with many repetitions of '99'. | test.py:9:25:9:27 | \\d+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:12:17:12:20 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:12:17:12:20 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:11:29:11:31 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:16:24:16:30 | ControlFlowNode for my_text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:16:24:16:30 | ControlFlowNode for my_text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:18:21:18:23 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:21:18:21:21 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:21:18:21:21 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings starting with 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC' and with many repetitions of 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC'. | test.py:20:271:20:272 | .* | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
edges
|
||||
| test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:2:26:2:32 | ControlFlowNode for request | provenance | |
|
||||
| test.py:2:26:2:32 | ControlFlowNode for request | test.py:7:12:7:18 | ControlFlowNode for request | provenance | |
|
||||
@@ -26,9 +32,3 @@ nodes
|
||||
| test.py:18:28:18:31 | ControlFlowNode for text | semmle.label | ControlFlowNode for text |
|
||||
| test.py:21:18:21:21 | ControlFlowNode for text | semmle.label | ControlFlowNode for text |
|
||||
subpaths
|
||||
#select
|
||||
| test.py:8:30:8:33 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:8:30:8:33 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:8:19:8:21 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:9:32:9:35 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:9:32:9:35 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings starting with '0.9' and with many repetitions of '99'. | test.py:9:25:9:27 | \\d+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:12:17:12:20 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:12:17:12:20 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:11:29:11:31 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:16:24:16:30 | ControlFlowNode for my_text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:16:24:16:30 | ControlFlowNode for my_text | This $@ that depends on a $@ may run slow on strings with many repetitions of ' '. | test.py:18:21:18:23 | \\s+ | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
| test.py:21:18:21:21 | ControlFlowNode for text | test.py:2:26:2:32 | ControlFlowNode for ImportMember | test.py:21:18:21:21 | ControlFlowNode for text | This $@ that depends on a $@ may run slow on strings starting with 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC' and with many repetitions of 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC'. | test.py:20:271:20:272 | .* | regular expression | test.py:2:26:2:32 | ControlFlowNode for ImportMember | user-provided value |
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-730/PolynomialReDoS.ql
|
||||
query: Security/CWE-730/PolynomialReDoS.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import re
|
||||
from flask import Flask, request
|
||||
from flask import Flask, request # $ Source
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/poly-redos")
|
||||
def code_execution():
|
||||
text = request.args.get("text")
|
||||
re.sub(r"^\s+|\s+$", "", text) # NOT OK
|
||||
re.match(r"^0\.\d+E?\d+$", text) # NOT OK
|
||||
re.sub(r"^\s+|\s+$", "", text) # $ Alert # NOT OK
|
||||
re.match(r"^0\.\d+E?\d+$", text) # $ Alert # NOT OK
|
||||
|
||||
reg = re.compile(r"^\s+|\s+$")
|
||||
reg.sub("", text) # NOT OK
|
||||
reg.sub("", text) # $ Alert # NOT OK
|
||||
|
||||
def indirect(input_reg_str, my_text):
|
||||
my_reg = re.compile(input_reg_str)
|
||||
my_reg.sub("", my_text) # NOT OK
|
||||
my_reg.sub("", my_text) # $ Alert # NOT OK
|
||||
|
||||
indirect(r"^\s+|\s+$", text)
|
||||
|
||||
reg2 = re.compile(r"(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)(AA|BB)C.*Y")
|
||||
reg2.sub("", text) # NOT OK
|
||||
reg2.sub("", text) # $ Alert # NOT OK
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ newline = whitespace_optional + newline_only + whitespace_optional
|
||||
toFlag = re.compile(newline)
|
||||
|
||||
# https://github.com/github/codeql-python-CVE-coverage/issues/400
|
||||
re.compile(r'[+-]?(\d+)*\.\d+%?')
|
||||
re.compile(r'[+-]?(\d+)*\.\d+%?') # $ Alert
|
||||
re.compile(r'"""\s+(?:.|\n)*?\s+"""')
|
||||
re.compile(r'(\{\s+)(\S+)(\s+[^}]+\s+\}\s)')
|
||||
re.compile(r'".*``.*``.*"')
|
||||
@@ -27,12 +27,12 @@ re.compile(r'(\.\w+\b)(\s*=\s*)([^;]*)(\s*;)')
|
||||
simple_email_re = re.compile(r"^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$")
|
||||
|
||||
# https://github.com/github/codeql-python-CVE-coverage/issues/249
|
||||
rx = re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+'
|
||||
rx = re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+' # $ Alert
|
||||
'realm=(["\']?)([^"\']*)\\2', re.I)
|
||||
|
||||
# https://github.com/github/codeql-python-CVE-coverage/issues/248
|
||||
gauntlet = re.compile(
|
||||
r"""^([-/:,#%.'"\s!\w]|\w-\w|'[\s\w]+'\s*|"[\s\w]+"|\([\d,%\.\s]+\))*$""",
|
||||
r"""^([-/:,#%.'"\s!\w]|\w-\w|'[\s\w]+'\s*|"[\s\w]+"|\([\d,%\.\s]+\))*$""", # $ Alert
|
||||
flags=re.U
|
||||
)
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-730/ReDoS.ql
|
||||
query: Security/CWE-730/ReDoS.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -3,7 +3,7 @@ import re
|
||||
# NOT GOOD; attack: "_" + "__".repeat(100)
|
||||
# Adapted from marked (https://github.com/markedjs/marked), which is licensed
|
||||
# under the MIT license; see file marked-LICENSE.
|
||||
bad1 = re.compile(r'''^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)''')
|
||||
bad1 = re.compile(r'''^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
# Adapted from marked (https://github.com/markedjs/marked), which is licensed
|
||||
@@ -18,7 +18,7 @@ good2 = re.compile(r'(.*,)+.+')
|
||||
# NOT GOOD; attack: " '" + "\\\\".repeat(100)
|
||||
# Adapted from CodeMirror (https://github.com/codemirror/codemirror),
|
||||
# which is licensed under the MIT license; see file CodeMirror-LICENSE.
|
||||
bad2 = re.compile(r'''^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?''')
|
||||
bad2 = re.compile(r'''^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
# Adapted from lulucms2 (https://github.com/yiifans/lulucms2).
|
||||
@@ -30,53 +30,53 @@ good2 = re.compile(r'''\(\*(?:[\s\S]*?\(\*[\s\S]*?\*\))*[\s\S]*?\*\)''')
|
||||
good3 = re.compile(r'''^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*''')
|
||||
|
||||
# NOT GOOD, variant of good3; attack: "a|\n:|\n" + "||\n".repeat(100)
|
||||
bad4 = re.compile(r'''^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)a''')
|
||||
bad4 = re.compile(r'''^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)a''') # $ Alert
|
||||
|
||||
# NOT GOOD; attack: "/" + "\\/a".repeat(100)
|
||||
# Adapted from ANodeBlog (https://github.com/gefangshuai/ANodeBlog),
|
||||
# which is licensed under the Apache License 2.0; see file ANodeBlog-LICENSE.
|
||||
bad5 = re.compile(r'''\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)''')
|
||||
bad5 = re.compile(r'''\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)''') # $ Alert
|
||||
|
||||
# NOT GOOD; attack: "##".repeat(100) + "\na"
|
||||
# Adapted from CodeMirror (https://github.com/codemirror/codemirror),
|
||||
# which is licensed under the MIT license; see file CodeMirror-LICENSE.
|
||||
bad6 = re.compile(r'''^([\s\[\{\(]|#.*)*$''')
|
||||
bad6 = re.compile(r'''^([\s\[\{\(]|#.*)*$''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good4 = re.compile(r'''(\r\n|\r|\n)+''')
|
||||
|
||||
# BAD - PoC: `node -e "/((?:[^\"\']|\".*?\"|\'.*?\')*?)([(,)]|$)/.test(\"'''''''''''''''''''''''''''''''''''''''''''''\\\"\");"`. It's complicated though, because the regexp still matches something, it just matches the empty-string after the attack string.
|
||||
actuallyBad = re.compile(r'''((?:[^"']|".*?"|'.*?')*?)([(,)]|$)''')
|
||||
actuallyBad = re.compile(r'''((?:[^"']|".*?"|'.*?')*?)([(,)]|$)''') # $ Alert
|
||||
|
||||
# NOT GOOD; attack: "a" + "[]".repeat(100) + ".b\n"
|
||||
# Adapted from Knockout (https://github.com/knockout/knockout), which is
|
||||
# licensed under the MIT license; see file knockout-LICENSE
|
||||
bad6 = re.compile(r'''^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$''')
|
||||
bad6 = re.compile(r'''^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good6 = re.compile(r'''(a|.)*''')
|
||||
|
||||
# Testing the NFA - only some of the below are detected.
|
||||
bad7 = re.compile(r'''^([a-z]+)+$''')
|
||||
bad8 = re.compile(r'''^([a-z]*)*$''')
|
||||
bad9 = re.compile(r'''^([a-zA-Z0-9])(([\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$''')
|
||||
bad10 = re.compile(r'''^(([a-z])+.)+[A-Z]([a-z])+$''')
|
||||
bad7 = re.compile(r'''^([a-z]+)+$''') # $ Alert
|
||||
bad8 = re.compile(r'''^([a-z]*)*$''') # $ Alert
|
||||
bad9 = re.compile(r'''^([a-zA-Z0-9])(([\\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$''') # $ Alert
|
||||
bad10 = re.compile(r'''^(([a-z])+.)+[A-Z]([a-z])+$''') # $ Alert
|
||||
|
||||
# NOT GOOD; attack: "[" + "][".repeat(100) + "]!"
|
||||
# Adapted from Prototype.js (https://github.com/prototypejs/prototype), which
|
||||
# is licensed under the MIT license; see file Prototype.js-LICENSE.
|
||||
bad11 = re.compile(r'''(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)''')
|
||||
bad11 = re.compile(r'''(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)''') # $ Alert
|
||||
|
||||
# NOT GOOD; attack: "'" + "\\a".repeat(100) + '"'
|
||||
# Adapted from Prism (https://github.com/PrismJS/prism), which is licensed
|
||||
# under the MIT license; see file Prism-LICENSE.
|
||||
bad12 = re.compile(r'''("|')(\\?.)*?\1''')
|
||||
bad12 = re.compile(r'''("|')(\\?.)*?\1''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad13 = re.compile(r'''(b|a?b)*c''')
|
||||
bad13 = re.compile(r'''(b|a?b)*c''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad15 = re.compile(r'''(a|aa?)*b''')
|
||||
bad15 = re.compile(r'''(a|aa?)*b''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good7 = re.compile(r'''(.|\n)*!''')
|
||||
@@ -88,31 +88,31 @@ bad16 = re.compile(r'''(.|\n)*!''')
|
||||
good8 = re.compile(r'''([\w.]+)*''')
|
||||
|
||||
# NOT GOOD
|
||||
bad17 = re.compile(r'''(a|aa?)*b''')
|
||||
bad17 = re.compile(r'''(a|aa?)*b''') # $ Alert
|
||||
|
||||
# GOOD - not used as regexp
|
||||
good9 = '(a|aa?)*b'
|
||||
|
||||
# NOT GOOD
|
||||
bad18 = re.compile(r'''(([\s\S]|[^a])*)"''')
|
||||
bad18 = re.compile(r'''(([\s\S]|[^a])*)"''') # $ Alert
|
||||
|
||||
# GOOD - there is no witness in the end that could cause the regexp to not match
|
||||
good10 = re.compile(r'''([^"']+)*''')
|
||||
|
||||
# NOT GOOD
|
||||
bad20 = re.compile(r'''((.|[^a])*)"''')
|
||||
bad20 = re.compile(r'''((.|[^a])*)"''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good10 = re.compile(r'''((a|[^a])*)"''')
|
||||
|
||||
# NOT GOOD
|
||||
bad21 = re.compile(r'''((b|[^a])*)"''')
|
||||
bad21 = re.compile(r'''((b|[^a])*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad22 = re.compile(r'''((G|[^a])*)"''')
|
||||
bad22 = re.compile(r'''((G|[^a])*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad23 = re.compile(r'''(([0-9]|[^a])*)"''')
|
||||
bad23 = re.compile(r'''(([0-9]|[^a])*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad24 = re.compile(r'''(?:=(?:([!#\$%&'\*\+\-\.\^_`\|~0-9A-Za-z]+)|"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)"))?''')
|
||||
@@ -124,55 +124,55 @@ bad25 = re.compile(r'''"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"])*)"''')
|
||||
bad26 = re.compile(r'''"((?:\\[\x00-\x7f]|[^\x00-\x08\x0a-\x1f\x7f"\\])*)"''')
|
||||
|
||||
# NOT GOOD
|
||||
bad27 = re.compile(r'''(([a-z]|[d-h])*)"''')
|
||||
bad27 = re.compile(r'''(([a-z]|[d-h])*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad27 = re.compile(r'''(([^a-z]|[^0-9])*)"''')
|
||||
bad27 = re.compile(r'''(([^a-z]|[^0-9])*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad28 = re.compile(r'''((\d|[0-9])*)"''')
|
||||
bad28 = re.compile(r'''((\d|[0-9])*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad29 = re.compile(r'''((\s|\s)*)"''')
|
||||
bad29 = re.compile(r'''((\s|\s)*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad30 = re.compile(r'''((\w|G)*)"''')
|
||||
bad30 = re.compile(r'''((\w|G)*)"''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good11 = re.compile(r'''((\s|\d)*)"''')
|
||||
|
||||
# NOT GOOD
|
||||
bad31 = re.compile(r'''((\d|\w)*)"''')
|
||||
bad31 = re.compile(r'''((\d|\w)*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad32 = re.compile(r'''((\d|5)*)"''')
|
||||
bad32 = re.compile(r'''((\d|5)*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad33 = re.compile(r'''((\s|[\f])*)"''')
|
||||
bad33 = re.compile(r'''((\s|[\f])*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad34 = re.compile(r'''((\s|[\v]|\\v)*)"''')
|
||||
bad34 = re.compile(r'''((\s|[\v]|\\v)*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad35 = re.compile(r'''((\f|[\f])*)"''')
|
||||
bad35 = re.compile(r'''((\f|[\f])*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad36 = re.compile(r'''((\W|\D)*)"''')
|
||||
bad36 = re.compile(r'''((\W|\D)*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad37 = re.compile(r'''((\S|\w)*)"''')
|
||||
bad37 = re.compile(r'''((\S|\w)*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad38 = re.compile(r'''((\S|[\w])*)"''')
|
||||
bad38 = re.compile(r'''((\S|[\w])*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad39 = re.compile(r'''((1s|[\da-z])*)"''')
|
||||
bad39 = re.compile(r'''((1s|[\da-z])*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad40 = re.compile(r'''((0|[\d])*)"''')
|
||||
bad40 = re.compile(r'''((0|[\d])*)"''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad41 = re.compile(r'''(([\d]+)*)"''')
|
||||
bad41 = re.compile(r'''(([\d]+)*)"''') # $ Alert
|
||||
|
||||
# GOOD - there is no witness in the end that could cause the regexp to not match
|
||||
good12 = re.compile(r'''(\d+(X\d+)?)+''')
|
||||
@@ -184,49 +184,49 @@ good13 = re.compile(r'''([0-9]+(X[0-9]*)?)*''')
|
||||
good15 = re.compile(r'''^([^>]+)*(>|$)''')
|
||||
|
||||
# NOT GOOD
|
||||
bad43 = re.compile(r'''^([^>a]+)*(>|$)''')
|
||||
bad43 = re.compile(r'''^([^>a]+)*(>|$)''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad44 = re.compile(r'''(\n\s*)+$''')
|
||||
bad44 = re.compile(r'''(\n\s*)+$''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad45 = re.compile(r'''^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})''')
|
||||
bad45 = re.compile(r'''^(?:\s+|#.*|\(\?#[^)]*\))*(?:[?*+]|{\d+(?:,\d*)?})''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad46 = re.compile(r'''\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\}''')
|
||||
bad46 = re.compile(r'''\{\[\s*([a-zA-Z]+)\(([a-zA-Z]+)\)((\s*([a-zA-Z]+)\: ?([ a-zA-Z{}]+),?)+)*\s*\]\}''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad47 = re.compile(r'''(a+|b+|c+)*c''')
|
||||
bad47 = re.compile(r'''(a+|b+|c+)*c''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad48 = re.compile(r'''(((a+a?)*)+b+)''')
|
||||
bad48 = re.compile(r'''(((a+a?)*)+b+)''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad49 = re.compile(r'''(a+)+bbbb''')
|
||||
bad49 = re.compile(r'''(a+)+bbbb''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good16 = re.compile(r'''(a+)+aaaaa*a+''')
|
||||
|
||||
# NOT GOOD
|
||||
bad50 = re.compile(r'''(a+)+aaaaa$''')
|
||||
bad50 = re.compile(r'''(a+)+aaaaa$''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good17 = re.compile(r'''(\n+)+\n\n''')
|
||||
|
||||
# NOT GOOD
|
||||
bad51 = re.compile(r'''(\n+)+\n\n$''')
|
||||
bad51 = re.compile(r'''(\n+)+\n\n$''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad52 = re.compile(r'''([^X]+)*$''')
|
||||
bad52 = re.compile(r'''([^X]+)*$''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad53 = re.compile(r'''(([^X]b)+)*$''')
|
||||
bad53 = re.compile(r'''(([^X]b)+)*$''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good18 = re.compile(r'''(([^X]b)+)*($|[^X]b)''')
|
||||
|
||||
# NOT GOOD
|
||||
bad54 = re.compile(r'''(([^X]b)+)*($|[^X]c)''')
|
||||
bad54 = re.compile(r'''(([^X]b)+)*($|[^X]c)''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good20 = re.compile(r'''((ab)+)*ababab''')
|
||||
@@ -238,13 +238,13 @@ good21 = re.compile(r'''((ab)+)*abab(ab)*(ab)+''')
|
||||
good22 = re.compile(r'''((ab)+)*''')
|
||||
|
||||
# NOT GOOD
|
||||
bad55 = re.compile(r'''((ab)+)*$''')
|
||||
bad55 = re.compile(r'''((ab)+)*$''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good23 = re.compile(r'''((ab)+)*[a1][b1][a2][b2][a3][b3]''')
|
||||
|
||||
# NOT GOOD
|
||||
bad56 = re.compile(r'''([\n\s]+)*(.)''')
|
||||
bad56 = re.compile(r'''([\n\s]+)*(.)''') # $ Alert
|
||||
|
||||
# GOOD - any witness passes through the accept state.
|
||||
good24 = re.compile(r'''(A*A*X)*''')
|
||||
@@ -253,76 +253,76 @@ good24 = re.compile(r'''(A*A*X)*''')
|
||||
good26 = re.compile(r'''([^\\\]]+)*''')
|
||||
|
||||
# NOT GOOD
|
||||
bad59 = re.compile(r'''(\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+-''')
|
||||
bad59 = re.compile(r'''(\w*foobarbaz\w*foobarbaz\w*foobarbaz\w*foobarbaz\s*foobarbaz\d*foobarbaz\w*)+-''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad60 = re.compile(r'''(.thisisagoddamnlongstringforstresstestingthequery|\sthisisagoddamnlongstringforstresstestingthequery)*-''')
|
||||
bad60 = re.compile(r'''(.thisisagoddamnlongstringforstresstestingthequery|\sthisisagoddamnlongstringforstresstestingthequery)*-''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad61 = re.compile(r'''(thisisagoddamnlongstringforstresstestingthequery|this\w+query)*-''')
|
||||
bad61 = re.compile(r'''(thisisagoddamnlongstringforstresstestingthequery|this\w+query)*-''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good27 = re.compile(r'''(thisisagoddamnlongstringforstresstestingthequery|imanotherbutunrelatedstringcomparedtotheotherstring)*-''')
|
||||
|
||||
# GOOD (but false positive caused by the extractor converting all four unpaired surrogates to \uFFFD)
|
||||
good28 = re.compile('''foo([\uDC66\uDC67]|[\uDC68\uDC69])*foo''')
|
||||
good28 = re.compile('''foo([\uDC66\uDC67]|[\uDC68\uDC69])*foo''') # $ Alert
|
||||
|
||||
# GOOD (but false positive caused by the extractor converting all four unpaired surrogates to \uFFFD)
|
||||
good29 = re.compile('''foo((\uDC66|\uDC67)|(\uDC68|\uDC69))*foo''')
|
||||
good29 = re.compile('''foo((\uDC66|\uDC67)|(\uDC68|\uDC69))*foo''') # $ Alert
|
||||
|
||||
# NOT GOOD (but cannot currently construct a prefix)
|
||||
bad62 = re.compile(r'''a{2,3}(b+)+X''')
|
||||
bad62 = re.compile(r'''a{2,3}(b+)+X''') # $ Alert
|
||||
|
||||
# NOT GOOD (and a good prefix test)
|
||||
bad63 = re.compile(r'''^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>''')
|
||||
bad63 = re.compile(r'''^<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good30 = re.compile(r'''(a+)*[\s\S][\s\S][\s\S]?''')
|
||||
|
||||
# GOOD - but we fail to see that repeating the attack string ends in the "accept any" state (due to not parsing the range `[\s\S]{2,3}`).
|
||||
good31 = re.compile(r'''(a+)*[\s\S]{2,3}''')
|
||||
good31 = re.compile(r'''(a+)*[\s\S]{2,3}''') # $ Alert
|
||||
|
||||
# GOOD - but we spuriously conclude that a rejecting suffix exists (due to not parsing the range `[\s\S]{2,}` when constructing the NFA).
|
||||
good32 = re.compile(r'''(a+)*([\s\S]{2,}|X)$''')
|
||||
good32 = re.compile(r'''(a+)*([\s\S]{2,}|X)$''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good33 = re.compile(r'''(a+)*([\s\S]*|X)$''')
|
||||
|
||||
# NOT GOOD
|
||||
bad64 = re.compile(r'''((a+)*$|[\s\S]+)''')
|
||||
bad64 = re.compile(r'''((a+)*$|[\s\S]+)''') # $ Alert
|
||||
|
||||
# GOOD - but still flagged. The only change compared to the above is the order of alternatives, which we don't model.
|
||||
good34 = re.compile(r'''([\s\S]+|(a+)*$)''')
|
||||
good34 = re.compile(r'''([\s\S]+|(a+)*$)''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good35 = re.compile(r'''((;|^)a+)+$''')
|
||||
|
||||
# NOT GOOD (a good prefix test)
|
||||
bad65 = re.compile(r'''(^|;)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(e+)+f''')
|
||||
bad65 = re.compile(r'''(^|;)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(e+)+f''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad66 = re.compile(r'''^ab(c+)+$''')
|
||||
bad66 = re.compile(r'''^ab(c+)+$''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad67 = re.compile(r'''(\d(\s+)*){20}''')
|
||||
bad67 = re.compile(r'''(\d(\s+)*){20}''') # $ Alert
|
||||
|
||||
# GOOD - but we spuriously conclude that a rejecting suffix exists.
|
||||
good36 = re.compile(r'''(([^/]|X)+)(\/[\s\S]*)*$''')
|
||||
good36 = re.compile(r'''(([^/]|X)+)(\/[\s\S]*)*$''') # $ Alert
|
||||
|
||||
# GOOD - but we spuriously conclude that a rejecting suffix exists.
|
||||
good37 = re.compile(r'''^((x([^Y]+)?)*(Y|$))''')
|
||||
good37 = re.compile(r'''^((x([^Y]+)?)*(Y|$))''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad68 = re.compile(r'''(a*)+b''')
|
||||
bad68 = re.compile(r'''(a*)+b''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad69 = re.compile(r'''foo([\w-]*)+bar''')
|
||||
bad69 = re.compile(r'''foo([\w-]*)+bar''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad70 = re.compile(r'''((ab)*)+c''')
|
||||
bad70 = re.compile(r'''((ab)*)+c''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad71 = re.compile(r'''(a?a?)*b''')
|
||||
bad71 = re.compile(r'''(a?a?)*b''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good38 = re.compile(r'''(a?)*b''')
|
||||
@@ -331,44 +331,44 @@ good38 = re.compile(r'''(a?)*b''')
|
||||
bad72 = re.compile(r'''(c?a?)*b''')
|
||||
|
||||
# NOT GOOD
|
||||
bad73 = re.compile(r'''(?:a|a?)+b''')
|
||||
bad73 = re.compile(r'''(?:a|a?)+b''') # $ Alert
|
||||
|
||||
# NOT GOOD - but not detected.
|
||||
bad74 = re.compile(r'''(a?b?)*$''')
|
||||
|
||||
# NOT GOOD
|
||||
bad76 = re.compile(r'''PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$)''')
|
||||
bad76 = re.compile(r'''PRE(([a-c]|[c-d])T(e?e?e?e?|X))+(cTcT|cTXcTX$)''') # $ Alert
|
||||
|
||||
# NOT GOOD - but not detected
|
||||
bad77 = re.compile(r'''^((a)+\w)+$''')
|
||||
bad77 = re.compile(r'''^((a)+\w)+$''') # $ Alert
|
||||
|
||||
# NOT GOOD
|
||||
bad78 = re.compile(r'''^(b+.)+$''')
|
||||
bad78 = re.compile(r'''^(b+.)+$''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good39 = re.compile(r'''a*b''')
|
||||
|
||||
# All 4 bad combinations of nested * and +
|
||||
bad79 = re.compile(r'''(a*)*b''')
|
||||
bad80 = re.compile(r'''(a+)*b''')
|
||||
bad81 = re.compile(r'''(a*)+b''')
|
||||
bad82 = re.compile(r'''(a+)+b''')
|
||||
bad79 = re.compile(r'''(a*)*b''') # $ Alert
|
||||
bad80 = re.compile(r'''(a+)*b''') # $ Alert
|
||||
bad81 = re.compile(r'''(a*)+b''') # $ Alert
|
||||
bad82 = re.compile(r'''(a+)+b''') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good40 = re.compile(r'''(a|b)+''')
|
||||
good41 = re.compile(r'''(?:[\s;,"'<>(){}|[\]@=+*]|:(?![/\\]))+''') # parses wrongly, sees column 42 as a char set start
|
||||
|
||||
# NOT GOOD
|
||||
bad83 = re.compile(r'''^((?:a{|-)|\w\{)+X$''')
|
||||
bad84 = re.compile(r'''^((?:a{0|-)|\w\{\d)+X$''')
|
||||
bad85 = re.compile(r'''^((?:a{0,|-)|\w\{\d,)+X$''')
|
||||
bad86 = re.compile(r'''^((?:a{0,2|-)|\w\{\d,\d)+X$''')
|
||||
bad83 = re.compile(r'''^((?:a{|-)|\w\{)+X$''') # $ Alert
|
||||
bad84 = re.compile(r'''^((?:a{0|-)|\w\{\d)+X$''') # $ Alert
|
||||
bad85 = re.compile(r'''^((?:a{0,|-)|\w\{\d,)+X$''') # $ Alert
|
||||
bad86 = re.compile(r'''^((?:a{0,2|-)|\w\{\d,\d)+X$''') # $ Alert
|
||||
|
||||
# GOOD:
|
||||
good42 = re.compile(r'''^((?:a{0,2}|-)|\w\{\d,\d\})+X$''')
|
||||
|
||||
# NOT GOOD
|
||||
bad87 = re.compile(r'X(\u0061|a)*Y')
|
||||
bad87 = re.compile(r'X(\u0061|a)*Y') # $ Alert
|
||||
|
||||
# GOOD
|
||||
good43 = re.compile(r'X(\u0061|b)+Y')
|
||||
@@ -377,17 +377,17 @@ good43 = re.compile(r'X(\u0061|b)+Y')
|
||||
good44 = re.compile(r'("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)')
|
||||
|
||||
# BAD
|
||||
bad88 = re.compile(r'/("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X')
|
||||
bad89 = re.compile(r'/("[^"]*?"|[^"\s]+)+(?=X)')
|
||||
bad88 = re.compile(r'/("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)X') # $ Alert
|
||||
bad89 = re.compile(r'/("[^"]*?"|[^"\s]+)+(?=X)') # $ Alert
|
||||
|
||||
# BAD
|
||||
bad90 = re.compile(r'\A(\d|0)*x')
|
||||
bad91 = re.compile(r'(\d|0)*\Z')
|
||||
bad92 = re.compile(r'\b(\d|0)*x')
|
||||
bad90 = re.compile(r'\A(\d|0)*x') # $ Alert
|
||||
bad91 = re.compile(r'(\d|0)*\Z') # $ Alert
|
||||
bad92 = re.compile(r'\b(\d|0)*x') # $ Alert
|
||||
|
||||
# GOOD
|
||||
stress1 = re.compile(r"(?<!&)#(\w+|(?:[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u2388\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2694\u2696\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD79\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED0\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3]|\uD83E[\uDD10-\uDD18\uDD80-\uDD84\uDDC0]|(?:0\u20E3|1\u20E3|2\u20E3|3\u20E3|4\u20E3|5\u20E3|6\u20E3|7\u20E3|8\u20E3|9\u20E3|#\u20E3|\\*\u20E3|\uD83C(?:\uDDE6\uD83C(?:\uDDEB|\uDDFD|\uDDF1|\uDDF8|\uDDE9|\uDDF4|\uDDEE|\uDDF6|\uDDEC|\uDDF7|\uDDF2|\uDDFC|\uDDE8|\uDDFA|\uDDF9|\uDDFF|\uDDEA)|\uDDE7\uD83C(?:\uDDF8|\uDDED|\uDDE9|\uDDE7|\uDDFE|\uDDEA|\uDDFF|\uDDEF|\uDDF2|\uDDF9|\uDDF4|\uDDE6|\uDDFC|\uDDFB|\uDDF7|\uDDF3|\uDDEC|\uDDEB|\uDDEE|\uDDF6|\uDDF1)|\uDDE8\uD83C(?:\uDDF2|\uDDE6|\uDDFB|\uDDEB|\uDDF1|\uDDF3|\uDDFD|\uDDF5|\uDDE8|\uDDF4|\uDDEC|\uDDE9|\uDDF0|\uDDF7|\uDDEE|\uDDFA|\uDDFC|\uDDFE|\uDDFF|\uDDED)|\uDDE9\uD83C(?:\uDDFF|\uDDF0|\uDDEC|\uDDEF|\uDDF2|\uDDF4|\uDDEA)|\uDDEA\uD83C(?:\uDDE6|\uDDE8|\uDDEC|\uDDF7|\uDDEA|\uDDF9|\uDDFA|\uDDF8|\uDDED)|\uDDEB\uD83C(?:\uDDF0|\uDDF4|\uDDEF|\uDDEE|\uDDF7|\uDDF2)|\uDDEC\uD83C(?:\uDDF6|\uDDEB|\uDDE6|\uDDF2|\uDDEA|\uDDED|\uDDEE|\uDDF7|\uDDF1|\uDDE9|\uDDF5|\uDDFA|\uDDF9|\uDDEC|\uDDF3|\uDDFC|\uDDFE|\uDDF8|\uDDE7)|\uDDED\uD83C(?:\uDDF7|\uDDF9|\uDDF2|\uDDF3|\uDDF0|\uDDFA)|\uDDEE\uD83C(?:\uDDF4|\uDDE8|\uDDF8|\uDDF3|\uDDE9|\uDDF7|\uDDF6|\uDDEA|\uDDF2|\uDDF1|\uDDF9)|\uDDEF\uD83C(?:\uDDF2|\uDDF5|\uDDEA|\uDDF4)|\uDDF0\uD83C(?:\uDDED|\uDDFE|\uDDF2|\uDDFF|\uDDEA|\uDDEE|\uDDFC|\uDDEC|\uDDF5|\uDDF7|\uDDF3)|\uDDF1\uD83C(?:\uDDE6|\uDDFB|\uDDE7|\uDDF8|\uDDF7|\uDDFE|\uDDEE|\uDDF9|\uDDFA|\uDDF0|\uDDE8)|\uDDF2\uD83C(?:\uDDF4|\uDDF0|\uDDEC|\uDDFC|\uDDFE|\uDDFB|\uDDF1|\uDDF9|\uDDED|\uDDF6|\uDDF7|\uDDFA|\uDDFD|\uDDE9|\uDDE8|\uDDF3|\uDDEA|\uDDF8|\uDDE6|\uDDFF|\uDDF2|\uDDF5|\uDDEB)|\uDDF3\uD83C(?:\uDDE6|\uDDF7|\uDDF5|\uDDF1|\uDDE8|\uDDFF|\uDDEE|\uDDEA|\uDDEC|\uDDFA|\uDDEB|\uDDF4)|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C(?:\uDDEB|\uDDF0|\uDDFC|\uDDF8|\uDDE6|\uDDEC|\uDDFE|\uDDEA|\uDDED|\uDDF3|\uDDF1|\uDDF9|\uDDF7|\uDDF2)|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C(?:\uDDEA|\uDDF4|\uDDFA|\uDDFC|\uDDF8)|\uDDF8\uD83C(?:\uDDFB|\uDDF2|\uDDF9|\uDDE6|\uDDF3|\uDDE8|\uDDF1|\uDDEC|\uDDFD|\uDDF0|\uDDEE|\uDDE7|\uDDF4|\uDDF8|\uDDED|\uDDE9|\uDDF7|\uDDEF|\uDDFF|\uDDEA|\uDDFE)|\uDDF9\uD83C(?:\uDDE9|\uDDEB|\uDDFC|\uDDEF|\uDDFF|\uDDED|\uDDF1|\uDDEC|\uDDF0|\uDDF4|\uDDF9|\uDDE6|\uDDF3|\uDDF7|\uDDF2|\uDDE8|\uDDFB)|\uDDFA\uD83C(?:\uDDEC|\uDDE6|\uDDF8|\uDDFE|\uDDF2|\uDDFF)|\uDDFB\uD83C(?:\uDDEC|\uDDE8|\uDDEE|\uDDFA|\uDDE6|\uDDEA|\uDDF3)|\uDDFC\uD83C(?:\uDDF8|\uDDEB)|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C(?:\uDDF9|\uDDEA)|\uDDFF\uD83C(?:\uDDE6|\uDDF2|\uDDFC))))[\ufe00-\ufe0f\u200d]?)+")
|
||||
|
||||
MY_REG = r'X(\u0061|a)*Y'
|
||||
MY_REG = r'X(\u0061|a)*Y' # $ Alert
|
||||
def matcher(name):
|
||||
re.match(MY_REG, name)
|
||||
@@ -2,12 +2,12 @@ import re
|
||||
|
||||
# Treatment of escapes
|
||||
re.compile(r"X([^\.]|\.)*$") # No ReDoS.
|
||||
re.compile(r"X(Æ|\Æ)+$") # Has ReDoS.
|
||||
re.compile(r"X(Æ|\Æ)+$") # $ Alert # Has ReDoS.
|
||||
|
||||
# Treatment of line breaks
|
||||
re.compile(r'(?:.|\n)*b') # No ReDoS.
|
||||
re.compile(r'(?:.|\n)*b', re.DOTALL) # Has ReDoS.
|
||||
re.compile(r'(?:.|\n)*b', re.DOTALL) # $ Alert # Has ReDoS.
|
||||
re.compile(r'(?i)(?:.|\n)*b') # No ReDoS.
|
||||
re.compile(r'(?s)(?:.|\n)*b') # Has ReDoS.
|
||||
re.compile(r'(?is)(?:.|\n)*b') # Has ReDoS.
|
||||
re.compile(r'(?is)X(?:.|\n)*Y') # Has ReDoS.
|
||||
re.compile(r'(?s)(?:.|\n)*b') # $ Alert # Has ReDoS.
|
||||
re.compile(r'(?is)(?:.|\n)*b') # $ Alert # Has ReDoS.
|
||||
re.compile(r'(?is)X(?:.|\n)*Y') # $ Alert # Has ReDoS.
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-730/RegexInjection.ql
|
||||
query: Security/CWE-730/RegexInjection.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from flask import request, Flask
|
||||
from flask import request, Flask # $ Source
|
||||
import re
|
||||
|
||||
app = Flask(__name__)
|
||||
@@ -11,7 +11,7 @@ def direct():
|
||||
"""
|
||||
|
||||
unsafe_pattern = request.args["pattern"]
|
||||
re.search(unsafe_pattern, "")
|
||||
re.search(unsafe_pattern, "") # $ Alert
|
||||
|
||||
|
||||
@app.route("/compile")
|
||||
@@ -22,7 +22,7 @@ def compile():
|
||||
"""
|
||||
|
||||
unsafe_pattern = request.args["pattern"]
|
||||
compiled_pattern = re.compile(unsafe_pattern)
|
||||
compiled_pattern = re.compile(unsafe_pattern) # $ Alert
|
||||
compiled_pattern.search("")
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ def compile_direct():
|
||||
"""
|
||||
|
||||
unsafe_pattern = request.args["pattern"]
|
||||
re.compile(unsafe_pattern).search("")
|
||||
re.compile(unsafe_pattern).search("") # $ Alert
|
||||
|
||||
# if __name__ == "__main__":
|
||||
# app.run(debug=True)
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
Security/CWE-732/WeakFilePermissions.ql
|
||||
query: Security/CWE-732/WeakFilePermissions.ql
|
||||
postprocess: utils/test/InlineExpectationsTestQuery.ql
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user