Merge branch 'bazookamusic/python-prompt-injection' of https://github.com/github/codeql into bazookamusic/python-prompt-injection

This commit is contained in:
Sotiris Dragonas
2026-07-02 16:12:24 +02:00
1336 changed files with 34080 additions and 23580 deletions

View File

@@ -1 +1,2 @@
Classes/InitCallsSubclass/InitCallsSubclassMethod.ql
query: Classes/InitCallsSubclass/InitCallsSubclassMethod.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -5,7 +5,7 @@ def bad1():
def __init__(self, arg):
self._state = "Not OK"
self.set_up(arg) # BAD: set_up is overriden.
self.set_up(arg) # $ Alert # BAD: set_up is overriden.
self._state = "OK"
def set_up(self, arg):
@@ -29,7 +29,7 @@ def bad2():
self.a = arg
# BAD: postproc is called after initialization. This is still an issue
# since it may still occur before all initialization on a subclass is complete.
self.postproc()
self.postproc() # $ Alert
def postproc(self):
if self.a == 1:
@@ -72,4 +72,4 @@ def good4():
class Sub(Super):
def _set_b(self):
self.b = self.a+1
self.b = self.a+1

View File

@@ -1 +1,2 @@
Classes/ShouldBeContextManager.ql
query: Classes/ShouldBeContextManager.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,6 +1,6 @@
#Should be context manager
class MegaDel(object):
class MegaDel(object): # $ Alert
def __del__(self):
a = self.x + self.y
@@ -13,7 +13,7 @@ class MegaDel(object):
sum += a
print(sum)
class MiniDel(object):
class MiniDel(object): # $ Alert
def close(self):
pass

View File

@@ -1 +1,2 @@
Classes/UselessClass.ql
query: Classes/UselessClass.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -25,7 +25,7 @@ class Useful2(object):
pass
class Useless1(object):
class Useless1(object): # $ Alert
def __init__(self):
pass
@@ -34,7 +34,7 @@ class Useless1(object):
pass
class Useless2(object):
class Useless2(object): # $ Alert
def do_something(self):
pass

View File

@@ -1 +1,2 @@
Exceptions/NotImplementedIsNotAnException.ql
query: Exceptions/NotImplementedIsNotAnException.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -193,7 +193,7 @@ def ee8(x):
#These are so common, we give warnings not errors.
def foo():
raise NotImplemented
raise NotImplemented # $ Alert[py/raise-not-implemented]
def bar():
raise NotImplemented()
raise NotImplemented() # $ Alert[py/raise-not-implemented]

View File

@@ -1 +1,2 @@
Expressions/Formatting/MixedExplicitImplicitIn3101Format.ql
query: Expressions/Formatting/MixedExplicitImplicitIn3101Format.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Expressions/Formatting/UnusedArgumentIn3101Format.ql
query: Expressions/Formatting/UnusedArgumentIn3101Format.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Expressions/Formatting/UnusedNamedArgumentIn3101Format.ql
query: Expressions/Formatting/UnusedNamedArgumentIn3101Format.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Expressions/Formatting/WrongNameInArgumentsFor3101Format.ql
query: Expressions/Formatting/WrongNameInArgumentsFor3101Format.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Expressions/Formatting/WrongNumberArgumentsFor3101Format.ql
query: Expressions/Formatting/WrongNumberArgumentsFor3101Format.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,11 +1,11 @@
from __future__ import unicode_literals
mixed_format1 = "{}{1}"
mixed_format1 = "{}{1}" # $ Alert[py/str-format/mixed-fields]
named_format1 = "{name!r}, {0}"
explicit_format1 = "{0}, {1}"
implicit_format1 = "{}, {}"
mixed_format2 = "{}{1}"
mixed_format2 = "{}{1}" # $ Alert[py/str-format/mixed-fields]
named_format2 = "{name!r}, {0}"
explicit_format2 = "{0}, {1}"
implicit_format2 = "{}, {}"
@@ -14,23 +14,23 @@ implicit_format2 = "{}, {}"
mixed_format1.format("Hello", "World")
format(mixed_format2, "Hello", "World")
named_format1.format("Hello", world="World")
format(named_format2, "Hello", world="World")
named_format1.format("Hello", world="World") # $ Alert[py/str-format/missing-named-argument] Alert[py/str-format/surplus-named-argument]
format(named_format2, "Hello", world="World") # $ Alert[py/str-format/missing-named-argument] Alert[py/str-format/surplus-named-argument]
named_format1.format(name="Hello", world="World")
format(named_format2, name="Hello", world="World")
named_format1.format(name="Hello", world="World") # $ Alert[py/str-format/missing-argument] Alert[py/str-format/surplus-named-argument]
format(named_format2, name="Hello", world="World") # $ Alert[py/str-format/missing-argument] Alert[py/str-format/surplus-named-argument]
explicit_format1.format("Hello")
format(explicit_format2, "Hello")
explicit_format1.format("Hello") # $ Alert[py/str-format/missing-argument]
format(explicit_format2, "Hello") # $ Alert[py/str-format/missing-argument]
implicit_format1.format("Hello")
format(implicit_format2, "Hello")
implicit_format1.format("Hello") # $ Alert[py/str-format/missing-argument]
format(implicit_format2, "Hello") # $ Alert[py/str-format/missing-argument]
explicit_format1.format("Hello", "World", "Extra")
format(explicit_format2, "Hello", "World", "Extra")
explicit_format1.format("Hello", "World", "Extra") # $ Alert[py/str-format/surplus-argument]
format(explicit_format2, "Hello", "World", "Extra") # $ Alert[py/str-format/surplus-argument]
implicit_format1.format("Hello", "World", "Extra")
format(implicit_format2, "Hello", "World", "Extra")
implicit_format1.format("Hello", "World", "Extra") # $ Alert[py/str-format/surplus-argument]
format(implicit_format2, "Hello", "World", "Extra") # $ Alert[py/str-format/surplus-argument]
#OK ODASA-3197
if cond:
@@ -42,8 +42,8 @@ format(x_or_y, x="x", y="y")
x_or_y.format(x="x", y="y")
#Still fail for multiple formats
format(x_or_y, x="x", y="y", z="z")
x_or_y.format(x="x", y="y", z="z")
format(x_or_y, x="x", y="y", z="z") # $ Alert[py/str-format/surplus-named-argument]
x_or_y.format(x="x", y="y", z="z") # $ Alert[py/str-format/surplus-named-argument]
#False positive reported by customer. -- Verify fix.
"<td class={}>{{}}></td>".format(html_class)

View File

@@ -6,7 +6,7 @@ def possibly_unknown_format_string1(x):
fmt = user_specified
else:
fmt = "{a}"
return fmt.format(a=1,b=2)
return fmt.format(a=1,b=2) # $ Alert[py/str-format/surplus-named-argument]
def possibly_unknown_format_string2(x):
user_specified = input()
@@ -14,7 +14,7 @@ def possibly_unknown_format_string2(x):
fmt = user_specified
else:
fmt = "{a}"
return fmt.format(a=1,b=2)
return fmt.format(a=1,b=2) # $ Alert[py/str-format/surplus-named-argument]
def possibly_unknown_format_string3(x):
@@ -22,4 +22,4 @@ def possibly_unknown_format_string3(x):
fmt = input()
else:
fmt = "{a}"
return fmt.format(a=1,b=2)
return fmt.format(a=1,b=2) # $ Alert[py/str-format/surplus-named-argument]

View File

@@ -1 +1,2 @@
Expressions/Regex/BackspaceEscape.ql
query: Expressions/Regex/BackspaceEscape.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Expressions/Regex/DuplicateCharacterInSet.ql
query: Expressions/Regex/DuplicateCharacterInSet.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Expressions/Regex/MissingPartSpecialGroup.ql
query: Expressions/Regex/MissingPartSpecialGroup.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Expressions/Regex/UnmatchableCaret.ql
query: Expressions/Regex/UnmatchableCaret.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Expressions/Regex/UnmatchableDollar.ql
query: Expressions/Regex/UnmatchableDollar.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,9 +1,9 @@
import re
#Unmatchable caret
re.compile(b' ^abc')
re.compile(b"(?s) ^abc")
re.compile(b"\[^123]")
re.compile(b' ^abc') # $ Alert[py/regex/unmatchable-caret]
re.compile(b"(?s) ^abc") # $ Alert[py/regex/unmatchable-caret]
re.compile(b"\[^123]") # $ Alert[py/regex/unmatchable-caret]
#Likely false positives for unmatchable caret
re.compile(b"[^123]")
@@ -14,21 +14,21 @@ re.compile(b"(?:(?:\n\r?)|^)( *)\S")
re.compile(b"^diff (?:-r [0-9a-f]+ ){1,2}(.*)$")
#Backspace escape
re.compile(br"[\b\t ]") # Should warn
re.compile(br"[\b\t ]") # $ Alert[py/regex/backspace-escape] # Should warn
re.compile(br"E\d+\b.*") # Fine
re.compile(br"E\d+\b[ \b\t]") #Both
re.compile(br"E\d+\b[ \b\t]") # $ Alert[py/regex/backspace-escape] #Both
#Missing part in named group
re.compile(br'(P<name>[\w]+)')
re.compile(br'(_(P<name>[\w]+)|)')
re.compile(br'(P<name>[\w]+)') # $ Alert[py/regex/incomplete-special-group]
re.compile(br'(_(P<name>[\w]+)|)') # $ Alert[py/regex/incomplete-special-group]
#This is OK...
re.compile(br'(?P<name>\w+)')
#Unmatchable dollar
re.compile(b"abc$ ")
re.compile(b"abc$ (?s)")
re.compile(b"\[$] ")
re.compile(b"abc$ ") # $ Alert[py/regex/unmatchable-dollar]
re.compile(b"abc$ (?s)") # $ Alert[py/regex/unmatchable-dollar]
re.compile(b"\[$] ") # $ Alert[py/regex/unmatchable-dollar]
#Not unmatchable dollar
re.match(b"[$] ", b"$ ")
@@ -43,9 +43,9 @@ re.match(b"((a$\Z)|b){4}", b"bbba")
re.match(b"(a){00}b", b"b")
#Duplicate character in set
re.compile(b"[AA]")
re.compile(b"[000]")
re.compile(b"[-0-9-]")
re.compile(b"[AA]") # $ Alert[py/regex/duplicate-in-character-class]
re.compile(b"[000]") # $ Alert[py/regex/duplicate-in-character-class]
re.compile(b"[-0-9-]") # $ Alert[py/regex/duplicate-in-character-class]
#Possible false positives
re.compile(b"[S\S]")
@@ -76,8 +76,8 @@ re.compile(br'\w+$(?<=foo)')
#Not OK
re.compile(br'(?<=foo)^\w+')
re.compile(br'\w+$(?=foo)')
re.compile(br'(?<=foo)^\w+') # $ Alert[py/regex/unmatchable-caret]
re.compile(br'\w+$(?=foo)') # $ Alert[py/regex/unmatchable-dollar]
#OK -- ODASA-ODASA-3968
@@ -134,7 +134,7 @@ VERBOSE_REGEX = r"""
\[ # [
(?P<header>[^]]+) # very permissive!
\] # ]
"""
""" # $ Alert[py/regex/duplicate-in-character-class]
# Compiled regular expression marking it as verbose
ODASA_6786 = re.compile(VERBOSE_REGEX, re.VERBOSE)

View File

@@ -1 +1,2 @@
Expressions/Comparisons/UselessComparisonTest.ql
query: Expressions/Comparisons/UselessComparisonTest.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -3,16 +3,16 @@
def f(w, x, y, z):
if x < 0 or z < 0:
raise Exception()
if x >= 0: # Useless test due to x < 0 being false
if x >= 0: # $ Alert # Useless test due to x < 0 being false
y += 1
if z >= 0: # Useless test due to z < 0 being false
if z >= 0: # $ Alert # Useless test due to z < 0 being false
y += 1
while w >= 0:
if y < 10:
z += 1
if y == 15: # Useless test due to y < 10 being true
if y == 15: # $ Alert # Useless test due to y < 10 being true
z += 1
elif y > 7: # Useless test
elif y > 7: # $ Alert # Useless test
y -= 1
if y < 10:
y += 1
@@ -24,10 +24,10 @@ def f(w, x, y, z):
def g(w, x, y, z):
if w < x or y < z+2:
raise Exception()
if w >= x: # Useless test due to w < x being false
if w >= x: # $ Alert # Useless test due to w < x being false
pass
if cond:
if z > y-2: # Useless test due to y < z+2 being false
if z > y-2: # $ Alert # Useless test due to y < z+2 being false
y += 1
else:
if z >= y-2: # Not a useless test.
@@ -46,7 +46,7 @@ def validate_series(start, end):
def medium1(x, y):
if x + 1000000000000000 > y + 1000000000000000:
return
if x > y: # Redundant
if x > y: # $ Alert # Redundant
pass
def medium2(x, y):
@@ -70,19 +70,19 @@ def big2(x, y):
def odasa6782_v1(protocol):
if protocol < 0:
protocol = HIGHEST_PROTOCOL
elif not 0 <= protocol:
elif not 0 <= protocol: # $ Alert
raise ValueError()
def odasa6782_v2(protocol):
if protocol < 0:
protocol = HIGHEST_PROTOCOL
elif not 0 <= protocol <= HIGHEST_PROTOCOL:
elif not 0 <= protocol <= HIGHEST_PROTOCOL: # $ Alert
raise ValueError()
def odasa6782_v3(protocol):
if protocol < 0:
protocol = HIGHEST_PROTOCOL
elif 0 <= protocol <= HIGHEST_PROTOCOL:
elif 0 <= protocol <= HIGHEST_PROTOCOL: # $ Alert
pass
else:
raise ValueError()

View File

@@ -1 +1,2 @@
Expressions/IncorrectComparisonUsingIs.ql
query: Expressions/IncorrectComparisonUsingIs.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -43,7 +43,7 @@ class C:
#Using 'is' when should be using '=='
s = "Hello " + "World"
if "Hello World" is s:
if "Hello World" is s: # $ Alert[py/comparison-using-is]
print ("OK")
#This is OK in CPython, but may not be portable

View File

@@ -1 +1,2 @@
Expressions/CompareConstants.ql
query: Expressions/CompareConstants.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Expressions/CompareIdenticalValues.ql
query: Expressions/CompareIdenticalValues.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Expressions/CompareIdenticalValuesMissingSelf.ql
query: Expressions/CompareIdenticalValuesMissingSelf.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Expressions/DuplicateKeyInDictionaryLiteral.ql
query: Expressions/DuplicateKeyInDictionaryLiteral.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Expressions/EqualsNone.ql
query: Expressions/EqualsNone.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Expressions/ExplicitCallToDel.ql
query: Expressions/ExplicitCallToDel.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Expressions/UnsupportedFormatCharacter.ql
query: Expressions/UnsupportedFormatCharacter.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -5,12 +5,12 @@ a == b
a.x == b.x
#Same variables
a == a
a.x == a.x
a == a # $ Alert[py/comparison-of-identical-expressions]
a.x == a.x # $ Alert[py/comparison-of-identical-expressions]
#Compare constants
1 == 1
1 == 2
1 == 1 # $ Alert[py/comparison-of-constants]
1 == 2 # $ Alert[py/comparison-of-constants]
#Maybe missing self
class X(object):
@@ -19,7 +19,7 @@ class X(object):
self.x = x
def missing_self(self, x):
if x == x:
if x == x: # $ Alert[py/comparison-missing-self]
print ("Yes")
#Compare constants in assert -- ok

View File

@@ -1,8 +1,8 @@
#encoding: utf-8
def dup_key():
return { 1: -1,
return { 1: -1, # $ Alert[py/duplicate-key-dict-literal]
1: -2,
u'a' : u'A',
u'a' : u'A', # $ Alert[py/duplicate-key-dict-literal]
u'a' : u'B'
}
@@ -34,7 +34,7 @@ def call_non_callable(arg):
dont_know() # Not a violation
#Explicit call to __del__
x.__del__()
x.__del__() # $ Alert[py/explicit-call-to-delete]
#Unhashable object
def func():
@@ -112,7 +112,7 @@ def is_container():
#Equals none
def x(arg):
return arg == None
return arg == None # $ Alert[py/test-equals-none]
class NotMyDict(object):
@@ -130,7 +130,7 @@ class SubTest(Test):
# This is permitted and required.
Test.__del__(self)
# This is a violation.
self.__del__()
self.__del__() # $ Alert[py/explicit-call-to-delete]
# This is an alternate syntax for the super() call, and hence OK.
super(SubTest, self).__del__()
# This is the Python 3 spelling of the same.

View File

@@ -5,7 +5,7 @@ def expected_mapping_for_fmt_string():
print (u"%(name)s" % x)
def unsupported_format_char(arg):
print (u"%Z" % arg)
print (u"%Z" % arg) # $ Alert[py/percent-format/unsupported-character]
def wrong_arg_count_format(arg):
print(u"%s %s" % (arg, arg, 0))

View File

@@ -1 +1,2 @@
Expressions/UnintentionalImplicitStringConcatenation.ql
query: Expressions/UnintentionalImplicitStringConcatenation.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -15,13 +15,13 @@ def test():
error1 = [
"foo",
"/usr/local"
"/usr/bin"
"/usr/bin" # $ Alert
]
error2 = [
"foo" +
"bar",
"/usr/local"
"/usr/bin"
"/usr/bin" # $ Alert
]
#Examples from documentation
@@ -31,9 +31,9 @@ def unclear():
return [
"first part of long string"
" and the second part",
" and the second part", # $ Alert
"/usr/local"
"/usr/bin"
"/usr/bin" # $ Alert
]
def clarified():

View File

@@ -1 +1,2 @@
Expressions/CallToSuperWrongClass.ql
query: Expressions/CallToSuperWrongClass.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -7,7 +7,7 @@ class MyDict(dict):
class NotMyDict(object):
def f(self):
super(MyDict, self).f()
super(MyDict, self).f() # $ Alert
#Splitting
PY2 = sys.version_info[0] == 2

View File

@@ -1 +1,2 @@
Functions/ModificationOfParameterWithDefault.ql
query: Functions/ModificationOfParameterWithDefault.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,31 +1,31 @@
# Not OK
def simple(l = [0]):
l[0] = 1 # $ modification=l
def simple(l = [0]): # $ Source
l[0] = 1 # $ Alert modification=l
return l
# Not OK
def slice(l = [0]):
l[0:1] = 1 # $ modification=l
def slice(l = [0]): # $ Source
l[0:1] = 1 # $ Alert modification=l
return l
# Not OK
def list_del(l = [0]):
del l[0] # $ modification=l
def list_del(l = [0]): # $ Source
del l[0] # $ Alert modification=l
return l
# Not OK
def append_op(l = []):
l += [1, 2, 3] # $ modification=l
def append_op(l = []): # $ Source
l += [1, 2, 3] # $ Alert modification=l
return l
# Not OK
def repeat_op(l = [0]):
l *= 3 # $ modification=l
def repeat_op(l = [0]): # $ Source
l *= 3 # $ Alert modification=l
return l
# Not OK
def append(l = []):
l.append(1) # $ modification=l
def append(l = []): # $ Source
l.append(1) # $ Alert modification=l
return l
# OK
@@ -36,64 +36,64 @@ def includes(l = []):
return x
def extends(l):
l.extend([1]) # $ modification=l
l.extend([1]) # $ Alert modification=l
return l
# Not OK
def deferred(l = []):
def deferred(l = []): # $ Source
extends(l)
return l
# Not OK
def nonempty(l = [5]):
l.append(1) # $ modification=l
def nonempty(l = [5]): # $ Source
l.append(1) # $ Alert modification=l
return l
# Not OK
def dict(d = {}):
d['a'] = 1 # $ modification=d
def dict(d = {}): # $ Source
d['a'] = 1 # $ Alert modification=d
return d
# Not OK
def dict_nonempty(d = {'a': 1}):
d['a'] = 2 # $ modification=d
def dict_nonempty(d = {'a': 1}): # $ Source
d['a'] = 2 # $ Alert modification=d
return d
# OK
def dict_nonempty_nochange(d = {'a': 1}):
d['a'] = 1 # $ SPURIOUS: modification=d
def dict_nonempty_nochange(d = {'a': 1}): # $ Source
d['a'] = 1 # $ SPURIOUS: Alert modification=d
return d
def modifies(d):
d['a'] = 1 # $ modification=d
d['a'] = 1 # $ Alert modification=d
return d
# Not OK
def dict_deferred(d = {}):
def dict_deferred(d = {}): # $ Source
modifies(d)
return d
# Not OK
def dict_method(d = {}):
d.update({'a': 1}) # $ modification=d
def dict_method(d = {}): # $ Source
d.update({'a': 1}) # $ Alert modification=d
return d
# Not OK
def dict_method_nonempty(d = {'a': 1}):
d.update({'a': 2}) # $ modification=d
def dict_method_nonempty(d = {'a': 1}): # $ Source
d.update({'a': 2}) # $ Alert modification=d
return d
# OK
def dict_method_nonempty_nochange(d = {'a': 1}):
d.update({'a': 1}) # $ SPURIOUS:modification=d
def dict_method_nonempty_nochange(d = {'a': 1}): # $ Source
d.update({'a': 1}) # $ SPURIOUS: Alert modification=d
return d
def modifies_method(d):
d.update({'a': 1}) # $ modification=d
d.update({'a': 1}) # $ Alert modification=d
return d
# Not OK
def dict_deferred_method(d = {}):
def dict_deferred_method(d = {}): # $ Source
modifies_method(d)
return d
@@ -105,58 +105,58 @@ def dict_includes(d = {}):
return x
# Not OK
def dict_del(d = {'a': 1}):
del d['a'] # $ modification=d
def dict_del(d = {'a': 1}): # $ Source
del d['a'] # $ Alert modification=d
return d
# Not OK
def dict_update_op(d = {}):
def dict_update_op(d = {}): # $ Source
x = {'a': 1}
d |= x # $ modification=d
d |= x # $ Alert modification=d
return d
# OK
def dict_update_op_nochange(d = {}):
def dict_update_op_nochange(d = {}): # $ Source
x = {}
d |= x # $ SPURIOUS: modification=d
d |= x # $ SPURIOUS: Alert modification=d
return d
def sanitizer(l = []):
def sanitizer(l = []): # $ Source
if l:
l.append(1)
else:
l.append(1) # $ modification=l
l.append(1) # $ Alert modification=l
return l
def sanitizer_negated(l = [1]):
def sanitizer_negated(l = [1]): # $ Source
if not l:
l.append(1)
else:
l.append(1) # $ modification=l
l.append(1) # $ Alert modification=l
return l
def sanitizer(l = []):
def sanitizer(l = []): # $ Source
if not l:
l.append(1) # $ modification=l
l.append(1) # $ Alert modification=l
else:
l.append(1)
return l
def sanitizer_negated(l = [1]):
def sanitizer_negated(l = [1]): # $ Source
if l:
l.append(1) # $ modification=l
l.append(1) # $ Alert modification=l
else:
l.append(1)
return l
# indirect modification of parameter with default
def aug_assign_argument(x):
x += ['x'] # $ modification=x
x += ['x'] # $ Alert modification=x
def mutate_argument(x):
x.append('x') # $ modification=x
x.append('x') # $ Alert modification=x
def indirect_modification(y = []):
def indirect_modification(y = []): # $ Source
aug_assign_argument(y)
mutate_argument(y)
@@ -182,19 +182,19 @@ def do_stuff_based_on_type(x):
if isinstance(x, str):
x = x.split()
elif isinstance(x, dict):
x.setdefault('foo', 'bar') # $ modification=x
x.setdefault('foo', 'bar') # $ Alert modification=x
elif isinstance(x, list):
x.append(5) # $ modification=x
x.append(5) # $ Alert modification=x
elif isinstance(x, tuple):
x = x.unknown_method()
def str_default(x="hello world"):
do_stuff_based_on_type(x)
def dict_default(x={'baz':'quux'}):
def dict_default(x={'baz':'quux'}): # $ Source
do_stuff_based_on_type(x)
def list_default(x=[1,2,3,4]):
def list_default(x=[1,2,3,4]): # $ Source
do_stuff_based_on_type(x)
def tuple_default(x=(1,2)):

View File

@@ -1 +1,2 @@
Functions/DeprecatedSliceMethod.ql
query: Functions/DeprecatedSliceMethod.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Functions/InitIsGenerator.ql
query: Functions/InitIsGenerator.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Functions/SignatureOverriddenMethod.ql
query: Functions/SignatureOverriddenMethod.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Functions/SignatureSpecialMethods.ql
query: Functions/SignatureSpecialMethods.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -29,7 +29,7 @@ class InitCallsInit(InitCallsError):
class InitIsGenerator(object):
def __init__(self):
def __init__(self): # $ Alert[py/init-method-is-generator]
yield self
# OK as it returns result of a call to super().__init__()

View File

@@ -92,13 +92,13 @@ def ok_to_ignore():
class DeprecatedSliceMethods(object):
def __getslice__(self, start, stop):
def __getslice__(self, start, stop): # $ Alert[py/deprecated-slice-method]
pass
def __setslice__(self, start, stop, value):
def __setslice__(self, start, stop, value): # $ Alert[py/deprecated-slice-method]
pass
def __delslice__(self, start, stop):
def __delslice__(self, start, stop): # $ Alert[py/deprecated-slice-method]
pass

View File

@@ -29,10 +29,10 @@ class Derived(Base):
def ok2(self, arg1, arg2 = 2, arg3 = 3):
return arg1, arg2, arg3
def grossly_wrong1(self, arg1):
def grossly_wrong1(self, arg1): # $ Alert[py/inheritance/signature-mismatch]
return arg1
def grossly_wrong2(self, arg1, arg2, arg3):
def grossly_wrong2(self, arg1, arg2, arg3): # $ Alert[py/inheritance/signature-mismatch]
return arg1, arg2, arg3
def strictly_wrong1(self, arg1):
@@ -56,19 +56,19 @@ class Special(object):
class WrongSpecials(object):
def __div__(self, x, y):
def __div__(self, x, y): # $ Alert[py/special-method-wrong-signature]
return self, x, y
def __mul__(self):
def __mul__(self): # $ Alert[py/special-method-wrong-signature]
return self
def __neg__(self, other):
def __neg__(self, other): # $ Alert[py/special-method-wrong-signature]
return self, other
def __exit__(self, arg0, arg1):
def __exit__(self, arg0, arg1): # $ Alert[py/special-method-wrong-signature]
return arg0 == arg1
def __repr__():
def __repr__(): # $ Alert[py/special-method-wrong-signature]
return ""
def __add__(self, other="Unused default"):
@@ -80,7 +80,7 @@ class WrongSpecials(object):
class OKSpecials(object):
def __del__():
def __del__(): # $ Alert[py/special-method-wrong-signature]
state = some_state()
def __del__(self):

View File

@@ -1 +1,2 @@
Functions/IterReturnsNonSelf.ql
query: Functions/IterReturnsNonSelf.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -2,7 +2,7 @@ class Bad1:
def __next__(self):
return 0
def __iter__(self): # BAD: Iter does not return self
def __iter__(self): # $ Alert # BAD: Iter does not return self
yield 0
class Good1:
@@ -48,6 +48,6 @@ class FalsePositive1:
self._it = iter(self)
return next(self._it)
def __iter__(self): # SPURIOUS, GOOD: implementation of next ensures the iterator is equivalent to the one returned by iter, but this is not detected.
def __iter__(self): # $ Alert # SPURIOUS, GOOD: implementation of next ensures the iterator is equivalent to the one returned by iter, but this is not detected.
yield 0
yield 0
yield 0

View File

@@ -1 +1,2 @@
Functions/ReturnConsistentTupleSizes.ql
query: Functions/ReturnConsistentTupleSizes.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -303,7 +303,7 @@ y = foo()
# Returning tuples with different sizes
def returning_different_tuple_sizes(x):
def returning_different_tuple_sizes(x): # $ Alert[py/mixed-tuple-returns]
if x:
return 1,2
else:
@@ -326,7 +326,7 @@ def indirectly_returning_different_tuple_sizes(x): # OK, since we only look at l
return function_returning_2_tuple()
else:
return function_returning_3_tuple()
def mismatched_multi_assign(x):
a,b = returning_different_tuple_sizes(x)

View File

@@ -1 +1,2 @@
Imports/ImportandImportFrom.ql
query: Imports/ImportandImportFrom.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,7 +1,7 @@
#Import and import from
import test_module2
import test_module2 # $ Alert[py/import-and-import-from]
from test_module2 import func
#Module imports itself

View File

@@ -1,7 +1,7 @@
class Foo(object):
pass
import pkg_notok
import pkg_notok # $ Alert[py/import-and-import-from]
# This import is a bit tricky. It will make `bar` available in as `pkg_notok.bar` as a
# side effect (see https://docs.python.org/3/reference/import.html#submodules), but the

View File

@@ -1 +1,2 @@
Imports/DeprecatedModule.ql
query: Imports/DeprecatedModule.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,11 +1,11 @@
# Some deprecated modules
import rfc822
import posixfile
import rfc822 # $ Alert
import posixfile # $ Alert
# We should only report a bad import once
class Foo(object):
def foo(self):
import md5
import md5 # $ Alert
# Backwards compatible code, should not report
try:

View File

@@ -1 +1,2 @@
Imports/ImportShadowedByLoopVar.ql
query: Imports/ImportShadowedByLoopVar.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Imports/ImportStarUsed.ql
query: Imports/ImportStarUsed.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Imports/Imports.ql
query: Imports/Imports.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Imports/MultipleImports.ql
query: Imports/MultipleImports.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,5 +1,5 @@
#Multiple imports on a single line
import module1, module2
import module1, module2 # $ Alert[py/multiple-imports-on-line]
#Cyclic import
@@ -13,13 +13,13 @@ import top_level_cycle
import module
for module in range(10):
for module in range(10): # $ Alert[py/import-shadowed-loop-variable]
print(module)
#Import * used
from module import *
from module_without_all import *
from module import * # $ Alert[py/import-star-used]
from module_without_all import * # $ Alert[py/import-star-used]
#Unused import
@@ -30,8 +30,8 @@ module1.func
func1
#Duplicate import
import module1
import module2
import module1 # $ Alert[py/repeated-import]
import module2 # $ Alert[py/repeated-import]
#OK -- Import used in epytext documentation.
import used_in_docs
@@ -62,4 +62,4 @@ import module1 as different
different
# FP reported in https://github.com/github/codeql/issues/4003
from module_that_does_not_exist import *
from module_that_does_not_exist import * # $ Alert[py/import-star-used]

View File

@@ -1 +1 @@
Lexical/ToDoComment.ql
Lexical/ToDoComment.ql

View File

@@ -14,56 +14,56 @@ def f(x):
do_something()
#else:
# do_something_else()
# Some non-code comments.
# Some non-code comments.
# Space immediately after scope start and between functions.
#
#
#class CommentedOut:
#
#
# def __init__(self):
# pass
#
#
# def method(self):
#
# pass
#
#
#def g(y):
# assert y
# assert y
# with y:
# # Commented out comment
# if y:
# do_something()
# else:
# do_something_else()
#
#
#def h(z):
# '''Doc string
# '''
# # Commented out comment
#
#
# followed_by_space()
#
#
# more_code()
#def j():
# """ Doc string """
# pass
#def k():
#
# """ Doc string """
# pass
#def l():
#
# """
# Doc string
# """
# Doc string
# """
#
# pass
#
#
#
@@ -72,7 +72,7 @@ def f(x):
# pass
#
#
#
#
some_code_to_break_up_comments()
#with x:
@@ -88,7 +88,7 @@ def a_function_to_break_up_comments():
pass
# An example explaining
# something which contains
# something which contains
# the following code:
#
# def f():
@@ -96,5 +96,3 @@ def a_function_to_break_up_comments():
# x.y = z
# return x
#

View File

@@ -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 |

View File

@@ -1 +1,2 @@
Security/CWE-020/CookieInjection.ql
query: Security/CWE-020/CookieInjection.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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)
]
]

View File

@@ -1 +1,2 @@
Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.ql
query: Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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):

View File

@@ -1 +1,2 @@
Security/CWE-020/IncompleteHostnameRegExp.ql
query: Security/CWE-020/IncompleteHostnameRegExp.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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')

View File

@@ -1 +1,2 @@
Security/CWE-020/IncompleteUrlSubstringSanitization.ql
query: Security/CWE-020/IncompleteUrlSubstringSanitization.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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)

View File

@@ -1 +1,2 @@
Security/CWE-020/OverlyLargeRange.ql
query: Security/CWE-020/OverlyLargeRange.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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

View File

@@ -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 |

View File

@@ -1 +1,2 @@
Security/CWE-022/TarSlip.ql
query: Security/CWE-022/TarSlip.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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

View File

@@ -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))

View File

@@ -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 |

View File

@@ -1 +1,2 @@
Security/CWE-074/TemplateInjection.ql
query: Security/CWE-074/TemplateInjection.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Security/CWE-078/CommandInjection.ql
query: Security/CWE-078/CommandInjection.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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

View File

@@ -1 +1,2 @@
Security/CWE-078/CommandInjection.ql
query: Security/CWE-078/CommandInjection.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -2,7 +2,7 @@ import re
import os
import subprocess
from flask import Flask, request
from flask import Flask, request # $ Source
app = Flask(__name__)
@@ -10,27 +10,27 @@ app = Flask(__name__)
def command_injection1():
files = request.args.get('files', '')
# Don't let files be `; rm -rf /`
os.system("ls " + files) # $ result=BAD
os.system("ls " + files) # $ Alert result=BAD
@app.route("/command2")
def command_injection2():
files = request.args.get('files', '')
# Don't let files be `; rm -rf /`
subprocess.Popen("ls " + files, shell=True) # $ result=BAD
subprocess.Popen("ls " + files, shell=True) # $ Alert result=BAD
@app.route("/command3")
def first_arg_injection():
cmd = request.args.get('cmd', '')
subprocess.Popen([cmd, "param1"]) # $ result=BAD
subprocess.Popen([cmd, "param1"]) # $ Alert result=BAD
@app.route("/other_cases")
def others():
files = request.args.get('files', '')
# Don't let files be `; rm -rf /`
os.popen("ls " + files) # $ result=BAD
os.popen("ls " + files) # $ Alert result=BAD
@app.route("/multiple")
@@ -38,8 +38,8 @@ def multiple():
command = request.args.get('command', '')
# We should mark flow to both calls here, which conflicts with removing flow out of
# a sink due to use-use flow.
os.system(command) # $ result=BAD
os.system(command) # $ result=BAD
os.system(command) # $ Alert result=BAD
os.system(command) # $ Alert result=BAD
@app.route("/not-into-sink-impl")
@@ -52,11 +52,11 @@ def not_into_sink_impl():
subprocess.call implementation: https://github.com/python/cpython/blob/fa7ce080175f65d678a7d5756c94f82887fc9803/Lib/subprocess.py#L341
"""
command = request.args.get('command', '')
os.system(command) # $ result=BAD
os.popen(command) # $ result=BAD
subprocess.call(command) # $ result=BAD
subprocess.check_call(command) # $ result=BAD
subprocess.run(command) # $ result=BAD
os.system(command) # $ Alert result=BAD
os.popen(command) # $ Alert result=BAD
subprocess.call(command) # $ Alert result=BAD
subprocess.check_call(command) # $ Alert result=BAD
subprocess.run(command) # $ Alert result=BAD
@app.route("/path-exists-not-sanitizer")
@@ -70,11 +70,11 @@ def path_exists_not_sanitizer():
"""
path = request.args.get('path', '')
if os.path.exists(path):
os.system("ls " + path) # $ result=BAD
os.system("ls " + path) # $ Alert result=BAD
@app.route("/restricted-characters")
def restricted_characters():
path = request.args.get('path', '')
if re.match(r'^[a-zA-Z0-9_-]+$', path):
os.system("ls " + path) # $ SPURIOUS: result=BAD
os.system("ls " + path) # $ Alert SPURIOUS: result=BAD

View File

@@ -1 +1,2 @@
Security/CWE-078/UnsafeShellCommandConstruction.ql
query: Security/CWE-078/UnsafeShellCommandConstruction.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1,45 +1,45 @@
import os
import subprocess
def unsafe_shell_one(name):
os.system("ping " + name) # $ result=BAD
def unsafe_shell_one(name): # $ Source
os.system("ping " + name) # $ Alert result=BAD
# f-strings
os.system(f"ping {name}") # $ result=BAD
os.system(f"ping {name}") # $ Alert result=BAD
# array.join
os.system("ping " + " ".join(name)) # $ result=BAD
os.system("ping " + " ".join(name)) # $ Alert result=BAD
# array.join, with a list
os.system("ping " + " ".join([name])) # $ result=BAD
os.system("ping " + " ".join([name])) # $ Alert result=BAD
# format, using .format
os.system("ping {}".format(name)) # $ result=BAD
os.system("ping {}".format(name)) # $ Alert result=BAD
# format, using %
os.system("ping %s" % name) # $ result=BAD
os.system("ping %s" % name) # $ Alert result=BAD
os.system(name) # OK - seems intentional.
import fabric
def facbric_stuff (name):
def facbric_stuff (name): # $ Source
fabric.api.run("ping " + name, shell=False) # OK
fabric.api.run("ping " + name, shell=True) # $ result=BAD
fabric.api.run("ping " + name, shell=True) # $ Alert result=BAD
def indirect(flag):
fabric.api.run("ping " + name, shell=flag) # OK
indirect(False)
def subprocess_flag (name):
def subprocess_flag (name): # $ Source
subprocess.run("ping " + name, shell=False) # OK - and nonsensical
subprocess.run("ping " + name, shell=True) # $ result=BAD
subprocess.run("ping " + name, shell=True) # $ Alert result=BAD
def indirect(flag, x):
subprocess.run("ping " + x, shell=flag) # $ result=BAD
subprocess.run("ping " + x, shell=flag) # $ Alert result=BAD
indirect(True, name)

View File

@@ -1 +1,2 @@
Security/CWE-079/Jinja2WithoutEscaping.ql
query: Security/CWE-079/Jinja2WithoutEscaping.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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())

View File

@@ -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 |

View File

@@ -1 +1,2 @@
Security/CWE-079/ReflectedXss.ql
query: Security/CWE-079/ReflectedXss.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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")

View File

@@ -1,2 +1,4 @@
query: Security/CWE-089/SqlInjection.ql
postprocess: utils/test/PrettyPrintModels.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -3,4 +3,4 @@ import sys
import psycopg
conn = psycopg.connect(...)
conn.execute(sys.argv[1])
conn.execute(sys.argv[1]) # $ Alert

View File

@@ -1 +1,2 @@
Security/CWE-090/LdapInjection.ql
query: Security/CWE-090/LdapInjection.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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)

View File

@@ -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__":

View File

@@ -1 +1,2 @@
Security/CWE-113/HeaderInjection.ql
query: Security/CWE-113/HeaderInjection.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -1 +1,2 @@
Security/CWE-116/BadTagFilter.ql
query: Security/CWE-116/BadTagFilter.ql
postprocess: utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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)

Some files were not shown because too many files have changed in this diff Show More