mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
Merge branch 'master' of github.com:github/codeql into UnmatchableDollar
to make CodeScan happy
This commit is contained in:
@@ -31,8 +31,8 @@ predicate calls_super(FunctionObject f) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if the given name is white-listed for some reason */
|
||||
predicate whitelisted(string name) {
|
||||
/** Holds if the given name is allowed for some reason */
|
||||
predicate allowed(string name) {
|
||||
/*
|
||||
* The standard library specifically recommends this :(
|
||||
* See https://docs.python.org/3/library/socketserver.html#asynchronous-mixins
|
||||
@@ -53,7 +53,7 @@ where
|
||||
not name.matches("\\_\\_%\\_\\_") and
|
||||
not calls_super(o1) and
|
||||
not does_nothing(o2) and
|
||||
not whitelisted(name) and
|
||||
not allowed(name) and
|
||||
not o1.overrides(o2) and
|
||||
not o2.overrides(o1) and
|
||||
not c.declaresAttribute(name)
|
||||
|
||||
@@ -14,21 +14,21 @@ import python
|
||||
import semmle.python.SelfAttribute
|
||||
import Equality
|
||||
|
||||
predicate class_stores_to_attribute(ClassObject cls, SelfAttributeStore store, string name) {
|
||||
exists(FunctionObject f |
|
||||
f = cls.declaredAttribute(_) and store.getScope() = f.getFunction() and store.getName() = name
|
||||
predicate class_stores_to_attribute(ClassValue cls, SelfAttributeStore store, string name) {
|
||||
exists(FunctionValue f |
|
||||
f = cls.declaredAttribute(_) and store.getScope() = f.getScope() and store.getName() = name
|
||||
) and
|
||||
/* Exclude classes used as metaclasses */
|
||||
not cls.getASuperType() = theTypeType()
|
||||
not cls.getASuperType() = ClassValue::type()
|
||||
}
|
||||
|
||||
predicate should_override_eq(ClassObject cls, Object base_eq) {
|
||||
predicate should_override_eq(ClassValue cls, Value base_eq) {
|
||||
not cls.declaresAttribute("__eq__") and
|
||||
exists(ClassObject sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq |
|
||||
not exists(GenericEqMethod eq | eq.getScope() = sup.getPyClass()) and
|
||||
not exists(IdentityEqMethod eq | eq.getScope() = sup.getPyClass()) and
|
||||
not base_eq.(FunctionObject).getFunction() instanceof IdentityEqMethod and
|
||||
not base_eq = theObjectType().declaredAttribute("__eq__")
|
||||
exists(ClassValue sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq |
|
||||
not exists(GenericEqMethod eq | eq.getScope() = sup.getScope()) and
|
||||
not exists(IdentityEqMethod eq | eq.getScope() = sup.getScope()) and
|
||||
not base_eq.(FunctionValue).getScope() instanceof IdentityEqMethod and
|
||||
not base_eq = ClassValue::object().declaredAttribute("__eq__")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -36,16 +36,16 @@ predicate should_override_eq(ClassObject cls, Object base_eq) {
|
||||
* Does the non-overridden __eq__ method access the attribute,
|
||||
* which implies that the __eq__ method does not need to be overridden.
|
||||
*/
|
||||
predicate superclassEqExpectsAttribute(ClassObject cls, PyFunctionObject base_eq, string attrname) {
|
||||
predicate superclassEqExpectsAttribute(ClassValue cls, FunctionValue base_eq, string attrname) {
|
||||
not cls.declaresAttribute("__eq__") and
|
||||
exists(ClassObject sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq |
|
||||
exists(ClassValue sup | sup = cls.getABaseType() and sup.declaredAttribute("__eq__") = base_eq |
|
||||
exists(SelfAttributeRead store | store.getName() = attrname |
|
||||
store.getScope() = base_eq.getFunction()
|
||||
store.getScope() = base_eq.getScope()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
from ClassObject cls, SelfAttributeStore store, Object base_eq
|
||||
from ClassValue cls, SelfAttributeStore store, Value base_eq
|
||||
where
|
||||
class_stores_to_attribute(cls, store, _) and
|
||||
should_override_eq(cls, base_eq) and
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
|
||||
import python
|
||||
|
||||
from ClassObject c
|
||||
where not c.isC() and not c.isContextManager() and exists(c.declaredAttribute("__del__"))
|
||||
from ClassValue c
|
||||
where not c.isBuiltin() and not c.isContextManager() and exists(c.declaredAttribute("__del__"))
|
||||
select c,
|
||||
"Class " + c.getName() +
|
||||
" implements __del__ (presumably to release some resource). Consider making it a context manager."
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* the arguments with which it is called, and if it were called, would be likely to cause an error.
|
||||
* @kind problem
|
||||
* @tags maintainability
|
||||
* @problem.severity error
|
||||
* @sub-severity low
|
||||
* @problem.severity recommendation
|
||||
* @sub-severity high
|
||||
* @precision high
|
||||
* @id py/inheritance/incorrect-overridden-signature
|
||||
*/
|
||||
|
||||
@@ -20,7 +20,7 @@ where
|
||||
count(int line |
|
||||
exists(DuplicateBlock d | d.sourceFile() = f |
|
||||
line in [d.sourceStartLine() .. d.sourceEndLine()] and
|
||||
not whitelistedLineForDuplication(f, line)
|
||||
not allowlistedLineForDuplication(f, line)
|
||||
)
|
||||
)
|
||||
select f, n order by n desc
|
||||
|
||||
@@ -20,7 +20,7 @@ where
|
||||
count(int line |
|
||||
exists(SimilarBlock d | d.sourceFile() = f |
|
||||
line in [d.sourceStartLine() .. d.sourceEndLine()] and
|
||||
not whitelistedLineForDuplication(f, line)
|
||||
not allowlistedLineForDuplication(f, line)
|
||||
)
|
||||
)
|
||||
select f, n order by n desc
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
<p>
|
||||
|
||||
The second two examples show safe checks.
|
||||
In <code>safe1</code>, a white-list is used. Although fairly inflexible,
|
||||
In <code>safe1</code>, an allowlist is used. Although fairly inflexible,
|
||||
this is easy to get right and is most likely to be safe.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
@@ -21,16 +21,16 @@ def unsafe2(request):
|
||||
|
||||
|
||||
|
||||
#Simplest and safest approach is to use a white-list
|
||||
#Simplest and safest approach is to use an allowlist
|
||||
|
||||
@app.route('/some/path/good1')
|
||||
def safe1(request):
|
||||
whitelist = [
|
||||
allowlist = [
|
||||
"example.com/home",
|
||||
"example.com/login",
|
||||
]
|
||||
target = request.args.get('target', '')
|
||||
if target in whitelist:
|
||||
if target in allowlist:
|
||||
return redirect(target)
|
||||
|
||||
#More complex example allowing sub-domains.
|
||||
|
||||
@@ -26,7 +26,7 @@ Ideally, follow these rules:
|
||||
<li>Do not allow directory separators such as "/" or "\" (depending on the file system).</li>
|
||||
<li>Do not rely on simply replacing problematic sequences such as "../". For example, after
|
||||
applying this filter to ".../...//", the resulting string would still be "../".</li>
|
||||
<li>Use a whitelist of known good patterns.</li>
|
||||
<li>Use an allowlist of known good patterns.</li>
|
||||
</ul>
|
||||
</recommendation>
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
import python
|
||||
import semmle.python.security.Paths
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
|
||||
/** A TaintKind to represent open tarfile objects. That is, the result of calling `tarfile.open(...)` */
|
||||
|
||||
@@ -25,7 +25,7 @@ safe before using it.</p>
|
||||
|
||||
<p>The following example shows two functions. The first is unsafe as it takes a shell script that can be changed
|
||||
by a user, and passes it straight to <code>subprocess.call()</code> without examining it first.
|
||||
The second is safe as it selects the command from a predefined white-list.</p>
|
||||
The second is safe as it selects the command from a predefined allowlist.</p>
|
||||
|
||||
<sample src="examples/command_injection.py" />
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ class CommandInjectionConfiguration extends TaintTracking::Configuration {
|
||||
|
||||
override predicate isExtension(TaintTracking::Extension extension) {
|
||||
extension instanceof FirstElementFlow
|
||||
or
|
||||
extension instanceof FabricExecuteExtension
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,5 +19,5 @@ def command_execution_unsafe(request):
|
||||
def command_execution_safe(request):
|
||||
if request.method == 'POST':
|
||||
action = request.POST.get('action', '')
|
||||
#GOOD -- Use a whitelist
|
||||
#GOOD -- Use an allowlist
|
||||
subprocess.call(["application", COMMANDS[action]])
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
import python
|
||||
import semmle.python.security.Paths
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.SensitiveData
|
||||
import semmle.python.security.ClearText
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
import python
|
||||
import semmle.python.security.Paths
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.SensitiveData
|
||||
import semmle.python.security.ClearText
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
import python
|
||||
import semmle.python.security.Paths
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.filters.Tests
|
||||
|
||||
class HardcodedValue extends TaintKind {
|
||||
|
||||
@@ -16,7 +16,7 @@ import python
|
||||
import Shadowing
|
||||
import semmle.python.types.Builtins
|
||||
|
||||
predicate white_list(string name) {
|
||||
predicate allow_list(string name) {
|
||||
/* These are rarely used and thus unlikely to be confusing */
|
||||
name = "iter" or
|
||||
name = "next" or
|
||||
@@ -51,7 +51,7 @@ predicate shadows(Name d, string name, Function scope, int line) {
|
||||
) and
|
||||
d.getScope() = scope and
|
||||
d.getLocation().getStartLine() = line and
|
||||
not white_list(name) and
|
||||
not allow_list(name) and
|
||||
not optimizing_parameter(d)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import python
|
||||
import Loop
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
/** Marker for "uninitialized". */
|
||||
class Uninitialized extends TaintKind {
|
||||
|
||||
@@ -33,12 +33,27 @@ predicate mutates_globals(ModuleValue m) {
|
||||
exists(SubscriptNode sub | sub.getObject() = globals and sub.isStore())
|
||||
)
|
||||
or
|
||||
exists(Value enum_convert, ClassValue enum_class |
|
||||
// Enum (added in 3.4) has method `_convert_` that alters globals
|
||||
// This was called `_convert` until 3.8, but that name will be removed in 3.9
|
||||
exists(ClassValue enum_class |
|
||||
enum_class.getASuperType() = Value::named("enum.Enum") and
|
||||
enum_convert = enum_class.attr("_convert") and
|
||||
exists(CallNode call | call.getScope() = m.getScope() |
|
||||
enum_convert.getACall() = call or
|
||||
call.getFunction().pointsTo(enum_convert)
|
||||
(
|
||||
// In Python < 3.8, Enum._convert can be found with points-to
|
||||
exists(Value enum_convert |
|
||||
enum_convert = enum_class.attr("_convert") and
|
||||
exists(CallNode call | call.getScope() = m.getScope() |
|
||||
enum_convert.getACall() = call or
|
||||
call.getFunction().pointsTo(enum_convert)
|
||||
)
|
||||
)
|
||||
or
|
||||
// In Python 3.8, Enum._convert_ is implemented using a metaclass, and our points-to
|
||||
// analysis doesn't handle that well enough. So we need a special case for this
|
||||
not exists(Value enum_convert | enum_convert = enum_class.attr("_convert")) and
|
||||
exists(CallNode call | call.getScope() = m.getScope() |
|
||||
call.getFunction().(AttrNode).getObject(["_convert", "_convert_"]).pointsTo() =
|
||||
enum_class
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -59,7 +74,7 @@ predicate contains_unknown_import_star(ModuleValue m) {
|
||||
from ModuleValue m, StrConst name, string exported_name
|
||||
where
|
||||
declaredInAll(m.getScope(), name) and
|
||||
exported_name = name.strValue() and
|
||||
exported_name = name.getText() and
|
||||
not m.hasAttribute(exported_name) and
|
||||
not is_exported_submodule_name(m, exported_name) and
|
||||
not contains_unknown_import_star(m) and
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @name Sanity check
|
||||
* @description General sanity check to be run on any and all code. Should never produce any results.
|
||||
* @id py/sanity-check
|
||||
* @name Consistency check
|
||||
* @description General consistency check to be run on any and all code. Should never produce any results.
|
||||
* @id py/consistency-check
|
||||
*/
|
||||
|
||||
import python
|
||||
@@ -24,7 +24,7 @@ predicate uniqueness_error(int number, string what, string problem) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate ast_sanity(string clsname, string problem, string what) {
|
||||
predicate ast_consistency(string clsname, string problem, string what) {
|
||||
exists(AstNode a | clsname = a.getAQlClass() |
|
||||
uniqueness_error(count(a.toString()), "toString", problem) and
|
||||
what = "at " + a.getLocation().toString()
|
||||
@@ -39,7 +39,7 @@ predicate ast_sanity(string clsname, string problem, string what) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate location_sanity(string clsname, string problem, string what) {
|
||||
predicate location_consistency(string clsname, string problem, string what) {
|
||||
exists(Location l | clsname = l.getAQlClass() |
|
||||
uniqueness_error(count(l.toString()), "toString", problem) and what = "at " + l.toString()
|
||||
or
|
||||
@@ -65,7 +65,7 @@ predicate location_sanity(string clsname, string problem, string what) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate cfg_sanity(string clsname, string problem, string what) {
|
||||
predicate cfg_consistency(string clsname, string problem, string what) {
|
||||
exists(ControlFlowNode f | clsname = f.getAQlClass() |
|
||||
uniqueness_error(count(f.getNode()), "getNode", problem) and
|
||||
what = "at " + f.getLocation().toString()
|
||||
@@ -80,7 +80,7 @@ predicate cfg_sanity(string clsname, string problem, string what) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate scope_sanity(string clsname, string problem, string what) {
|
||||
predicate scope_consistency(string clsname, string problem, string what) {
|
||||
exists(Scope s | clsname = s.getAQlClass() |
|
||||
uniqueness_error(count(s.getEntryNode()), "getEntryNode", problem) and
|
||||
what = "at " + s.getLocation().toString()
|
||||
@@ -125,7 +125,7 @@ private predicate introspected_builtin_object(Object o) {
|
||||
py_cobject_sources(o, 0)
|
||||
}
|
||||
|
||||
predicate builtin_object_sanity(string clsname, string problem, string what) {
|
||||
predicate builtin_object_consistency(string clsname, string problem, string what) {
|
||||
exists(Object o |
|
||||
clsname = o.getAQlClass() and
|
||||
what = best_description_builtin_object(o) and
|
||||
@@ -146,7 +146,7 @@ predicate builtin_object_sanity(string clsname, string problem, string what) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate source_object_sanity(string clsname, string problem, string what) {
|
||||
predicate source_object_consistency(string clsname, string problem, string what) {
|
||||
exists(Object o | clsname = o.getAQlClass() and not o.isBuiltin() |
|
||||
uniqueness_error(count(o.getOrigin()), "getOrigin", problem) and
|
||||
what = "at " + o.getOrigin().getLocation().toString()
|
||||
@@ -161,7 +161,7 @@ predicate source_object_sanity(string clsname, string problem, string what) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate ssa_sanity(string clsname, string problem, string what) {
|
||||
predicate ssa_consistency(string clsname, string problem, string what) {
|
||||
/* Zero or one definitions of each SSA variable */
|
||||
exists(SsaVariable var | clsname = var.getAQlClass() |
|
||||
uniqueness_error(strictcount(var.getDefinition()), "getDefinition", problem) and
|
||||
@@ -196,7 +196,7 @@ predicate ssa_sanity(string clsname, string problem, string what) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate function_object_sanity(string clsname, string problem, string what) {
|
||||
predicate function_object_consistency(string clsname, string problem, string what) {
|
||||
exists(FunctionObject func | clsname = func.getAQlClass() |
|
||||
what = func.getName() and
|
||||
(
|
||||
@@ -229,7 +229,7 @@ predicate intermediate_origins(ControlFlowNode use, ControlFlowNode inter, Objec
|
||||
)
|
||||
}
|
||||
|
||||
predicate points_to_sanity(string clsname, string problem, string what) {
|
||||
predicate points_to_consistency(string clsname, string problem, string what) {
|
||||
exists(Object obj |
|
||||
multiple_origins_per_object(obj) and
|
||||
clsname = obj.getAQlClass() and
|
||||
@@ -245,7 +245,7 @@ predicate points_to_sanity(string clsname, string problem, string what) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate jump_to_definition_sanity(string clsname, string problem, string what) {
|
||||
predicate jump_to_definition_consistency(string clsname, string problem, string what) {
|
||||
problem = "multiple (jump-to) definitions" and
|
||||
exists(Expr use |
|
||||
strictcount(getUniqueDefinition(use)) > 1 and
|
||||
@@ -254,7 +254,7 @@ predicate jump_to_definition_sanity(string clsname, string problem, string what)
|
||||
)
|
||||
}
|
||||
|
||||
predicate file_sanity(string clsname, string problem, string what) {
|
||||
predicate file_consistency(string clsname, string problem, string what) {
|
||||
exists(File file, Folder folder |
|
||||
clsname = file.getAQlClass() and
|
||||
problem = "has same name as a folder" and
|
||||
@@ -269,7 +269,7 @@ predicate file_sanity(string clsname, string problem, string what) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate class_value_sanity(string clsname, string problem, string what) {
|
||||
predicate class_value_consistency(string clsname, string problem, string what) {
|
||||
exists(ClassValue value, ClassValue sup, string attr |
|
||||
what = value.getName() and
|
||||
sup = value.getASuperType() and
|
||||
@@ -283,16 +283,16 @@ predicate class_value_sanity(string clsname, string problem, string what) {
|
||||
|
||||
from string clsname, string problem, string what
|
||||
where
|
||||
ast_sanity(clsname, problem, what) or
|
||||
location_sanity(clsname, problem, what) or
|
||||
scope_sanity(clsname, problem, what) or
|
||||
cfg_sanity(clsname, problem, what) or
|
||||
ssa_sanity(clsname, problem, what) or
|
||||
builtin_object_sanity(clsname, problem, what) or
|
||||
source_object_sanity(clsname, problem, what) or
|
||||
function_object_sanity(clsname, problem, what) or
|
||||
points_to_sanity(clsname, problem, what) or
|
||||
jump_to_definition_sanity(clsname, problem, what) or
|
||||
file_sanity(clsname, problem, what) or
|
||||
class_value_sanity(clsname, problem, what)
|
||||
ast_consistency(clsname, problem, what) or
|
||||
location_consistency(clsname, problem, what) or
|
||||
scope_consistency(clsname, problem, what) or
|
||||
cfg_consistency(clsname, problem, what) or
|
||||
ssa_consistency(clsname, problem, what) or
|
||||
builtin_object_consistency(clsname, problem, what) or
|
||||
source_object_consistency(clsname, problem, what) or
|
||||
function_object_consistency(clsname, problem, what) or
|
||||
points_to_consistency(clsname, problem, what) or
|
||||
jump_to_definition_consistency(clsname, problem, what) or
|
||||
file_consistency(clsname, problem, what) or
|
||||
class_value_consistency(clsname, problem, what)
|
||||
select clsname + " " + what + " has " + problem
|
||||
@@ -7,7 +7,7 @@ import DefinitionTracking
|
||||
|
||||
predicate want_to_have_definition(Expr e) {
|
||||
/* not builtin object like len, tuple, etc. */
|
||||
not exists(Object cobj | e.refersTo(cobj) and cobj.isC()) and
|
||||
not exists(Value builtin | e.pointsTo(builtin) and builtin.isBuiltin()) and
|
||||
(
|
||||
e instanceof Name and e.(Name).getCtx() instanceof Load
|
||||
or
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
- description: Security-and-quality queries for Python
|
||||
- qlpack: codeql-python
|
||||
- apply: security-and-quality-selectors.yml
|
||||
from: codeql-suite-helpers
|
||||
4
python/ql/src/codeql-suites/python-security-extended.qls
Normal file
4
python/ql/src/codeql-suites/python-security-extended.qls
Normal file
@@ -0,0 +1,4 @@
|
||||
- description: Security-extended queries for Python
|
||||
- qlpack: codeql-python
|
||||
- apply: security-extended-selectors.yml
|
||||
from: codeql-suite-helpers
|
||||
2
python/ql/src/external/CodeDuplication.qll
vendored
2
python/ql/src/external/CodeDuplication.qll
vendored
@@ -268,6 +268,6 @@ predicate similarScopes(Scope s, Scope other, float percent, string message) {
|
||||
* Holds if the line is acceptable as a duplicate.
|
||||
* This is true for blocks of import statements.
|
||||
*/
|
||||
predicate whitelistedLineForDuplication(File f, int line) {
|
||||
predicate allowlistedLineForDuplication(File f, int line) {
|
||||
exists(ImportingStmt i | i.getLocation().getFile() = f and i.getLocation().getStartLine() = line)
|
||||
}
|
||||
|
||||
@@ -597,7 +597,7 @@ class StrConst extends Str_, ImmutableLiteral {
|
||||
this.getEnclosingModule().hasFromFuture("unicode_literals")
|
||||
}
|
||||
|
||||
override string strValue() { result = this.getS() }
|
||||
deprecated override string strValue() { result = this.getS() }
|
||||
|
||||
override Expr getASubExpression() { none() }
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
private import semmle.python.dataflow.Implementation
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
class OpenFile extends TaintKind {
|
||||
OpenFile() { this = "file.open" }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
private import semmle.python.objects.ObjectInternal
|
||||
import semmle.python.dataflow.Implementation
|
||||
|
||||
|
||||
@@ -27,8 +27,10 @@ abstract class CallableObjectInternal extends ObjectInternal {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Gets the `n`th parameter node of this callable. */
|
||||
abstract NameNode getParameter(int n);
|
||||
|
||||
/** Gets the `name`d parameter node of this callable. */
|
||||
abstract NameNode getParameterByName(string name);
|
||||
|
||||
abstract predicate neverReturns();
|
||||
@@ -438,16 +440,30 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
|
||||
PointsTo::pointsTo(result.getFunction(), ctx, this, _)
|
||||
}
|
||||
|
||||
override NameNode getParameter(int n) { result = this.getFunction().getParameter(n + 1) }
|
||||
/** Gets the parameter node that will be used for `self`. */
|
||||
NameNode getSelfParameter() { result = this.getFunction().getParameter(0) }
|
||||
|
||||
override NameNode getParameter(int n) {
|
||||
result = this.getFunction().getParameter(n + 1) and
|
||||
// don't return the parameter for `self` at `n = -1`
|
||||
n >= 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `name`d parameter node of this callable.
|
||||
* Will not return the parameter node for `self`, instead use `getSelfParameter`.
|
||||
*/
|
||||
override NameNode getParameterByName(string name) {
|
||||
result = this.getFunction().getParameterByName(name)
|
||||
result = this.getFunction().getParameterByName(name) and
|
||||
not result = this.getSelfParameter()
|
||||
}
|
||||
|
||||
override predicate neverReturns() { this.getFunction().neverReturns() }
|
||||
|
||||
override predicate functionAndOffset(CallableObjectInternal function, int offset) {
|
||||
function = this.getFunction() and offset = 1
|
||||
or
|
||||
function = this and offset = 0
|
||||
}
|
||||
|
||||
override predicate useOriginAsLegacyObject() { any() }
|
||||
|
||||
@@ -352,7 +352,29 @@ class CallableValue extends Value {
|
||||
result = this.(CallableObjectInternal).getParameterByName(name)
|
||||
}
|
||||
|
||||
/** Gets the argument corresponding to the `n'th parameter node of this callable. */
|
||||
/**
|
||||
* Gets the argument in `call` corresponding to the `n`'th positional parameter of this callable.
|
||||
*
|
||||
* Use this method instead of `call.getArg(n)` to handle the fact that this function might be used as
|
||||
* a bound-method, such that argument `n` of the call corresponds to the `n+1` parameter of the callable.
|
||||
*
|
||||
* This method also gives results when the argument is passed as a keyword argument in `call`, as long
|
||||
* as `this` is not a builtin function or a builtin method.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - if `this` represents the `PythonFunctionValue` for `def func(a, b):`, and `call` represents
|
||||
* `func(10, 20)`, then `getArgumentForCall(call, 0)` will give the `ControlFlowNode` for `10`.
|
||||
*
|
||||
* - with `call` representing `func(b=20, a=10)`, `getArgumentForCall(call, 0)` will give
|
||||
* the `ControlFlowNode` for `10`.
|
||||
*
|
||||
* - if `this` represents the `PythonFunctionValue` for `def func(self, a, b):`, and `call`
|
||||
* represents `foo.func(10, 20)`, then `getArgumentForCall(call, 1)` will give the
|
||||
* `ControlFlowNode` for `10`.
|
||||
* Note: There will also exist a `BoundMethodValue bm` where `bm.getArgumentForCall(call, 0)`
|
||||
* will give the `ControlFlowNode` for `10` (notice the shift in index used).
|
||||
*/
|
||||
cached
|
||||
ControlFlowNode getArgumentForCall(CallNode call, int n) {
|
||||
exists(ObjectInternal called, int offset |
|
||||
@@ -363,7 +385,7 @@ class CallableValue extends Value {
|
||||
or
|
||||
exists(string name |
|
||||
call.getArgByName(name) = result and
|
||||
this.(PythonFunctionObjectInternal).getScope().getArg(n + offset).getName() = name
|
||||
this.getParameter(n).getId() = name
|
||||
)
|
||||
or
|
||||
called instanceof BoundMethodObjectInternal and
|
||||
@@ -373,21 +395,37 @@ class CallableValue extends Value {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the argument corresponding to the `name`d parameter node of this callable. */
|
||||
/**
|
||||
* Gets the argument in `call` corresponding to the `name`d keyword parameter of this callable.
|
||||
*
|
||||
* This method also gives results when the argument is passed as a positional argument in `call`, as long
|
||||
* as `this` is not a builtin function or a builtin method.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - if `this` represents the `PythonFunctionValue` for `def func(a, b):`, and `call` represents
|
||||
* `func(10, 20)`, then `getNamedArgumentForCall(call, "a")` will give the `ControlFlowNode` for `10`.
|
||||
*
|
||||
* - with `call` representing `func(b=20, a=10)`, `getNamedArgumentForCall(call, "a")` will give
|
||||
* the `ControlFlowNode` for `10`.
|
||||
*
|
||||
* - if `this` represents the `PythonFunctionValue` for `def func(self, a, b):`, and `call`
|
||||
* represents `foo.func(10, 20)`, then `getNamedArgumentForCall(call, "a")` will give the
|
||||
* `ControlFlowNode` for `10`.
|
||||
*/
|
||||
cached
|
||||
ControlFlowNode getNamedArgumentForCall(CallNode call, string name) {
|
||||
exists(CallableObjectInternal called, int offset |
|
||||
PointsToInternal::pointsTo(call.getFunction(), _, called, _) and
|
||||
called.functionAndOffset(this, offset)
|
||||
|
|
||||
call.getArgByName(name) = result
|
||||
or
|
||||
exists(int n |
|
||||
call.getArg(n) = result and
|
||||
this.(PythonFunctionObjectInternal).getScope().getArg(n + offset).getName() = name
|
||||
this.getParameter(n + offset).getId() = name
|
||||
)
|
||||
or
|
||||
call.getArgByName(name) = result and
|
||||
exists(this.(PythonFunctionObjectInternal).getScope().getArgByName(name))
|
||||
or
|
||||
called instanceof BoundMethodObjectInternal and
|
||||
offset = 1 and
|
||||
name = "self" and
|
||||
@@ -396,6 +434,29 @@ class CallableValue extends Value {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing bound-methods, such as `o.func`, where `o` is an instance
|
||||
* of a class that has a callable attribute `func`.
|
||||
*/
|
||||
class BoundMethodValue extends CallableValue {
|
||||
BoundMethodValue() { this instanceof BoundMethodObjectInternal }
|
||||
|
||||
/**
|
||||
* Gets the callable that will be used when `this` is called.
|
||||
* The actual callable for `func` in `o.func`.
|
||||
*/
|
||||
CallableValue getFunction() { result = this.(BoundMethodObjectInternal).getFunction() }
|
||||
|
||||
/**
|
||||
* Gets the value that will be used for the `self` parameter when `this` is called.
|
||||
* The value for `o` in `o.func`.
|
||||
*/
|
||||
Value getSelf() { result = this.(BoundMethodObjectInternal).getSelf() }
|
||||
|
||||
/** Gets the parameter node that will be used for `self`. */
|
||||
NameNode getSelfParameter() { result = this.(BoundMethodObjectInternal).getSelfParameter() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Class representing classes in the Python program, both Python and built-in.
|
||||
*/
|
||||
@@ -456,7 +517,14 @@ class ClassValue extends Value {
|
||||
/** Holds if this class is a container(). That is, does it have a __getitem__ method. */
|
||||
predicate isContainer() { exists(this.lookup("__getitem__")) }
|
||||
|
||||
/** Holds if this class is probably a sequence. */
|
||||
/**
|
||||
* Holds if this class is a sequence. Mutually exclusive with `isMapping()`.
|
||||
*
|
||||
* Following the definition from
|
||||
* https://docs.python.org/3/glossary.html#term-sequence.
|
||||
* We don't look at the keys accepted by `__getitem__, but default to treating a class
|
||||
* as a sequence (so might treat some mappings as sequences).
|
||||
*/
|
||||
predicate isSequence() {
|
||||
/*
|
||||
* To determine whether something is a sequence or a mapping is not entirely clear,
|
||||
@@ -477,16 +545,26 @@ class ClassValue extends Value {
|
||||
or
|
||||
major_version() = 3 and this.getASuperType() = Value::named("collections.abc.Sequence")
|
||||
or
|
||||
/* Does it have an index or __reversed__ method? */
|
||||
this.isContainer() and
|
||||
(
|
||||
this.hasAttribute("index") or
|
||||
this.hasAttribute("__reversed__")
|
||||
)
|
||||
this.hasAttribute("__getitem__") and
|
||||
this.hasAttribute("__len__") and
|
||||
not this.getASuperType() = ClassValue::dict() and
|
||||
not this.getASuperType() = Value::named("collections.Mapping") and
|
||||
not this.getASuperType() = Value::named("collections.abc.Mapping")
|
||||
}
|
||||
|
||||
/** Holds if this class is a mapping. */
|
||||
/**
|
||||
* Holds if this class is a mapping. Mutually exclusive with `isSequence()`.
|
||||
*
|
||||
* Although a class will satisfy the requirement by the definition in
|
||||
* https://docs.python.org/3.8/glossary.html#term-mapping, we don't look at the keys
|
||||
* accepted by `__getitem__, but default to treating a class as a sequence (so might
|
||||
* treat some mappings as sequences).
|
||||
*/
|
||||
predicate isMapping() {
|
||||
major_version() = 2 and this.getASuperType() = Value::named("collections.Mapping")
|
||||
or
|
||||
major_version() = 3 and this.getASuperType() = Value::named("collections.abc.Mapping")
|
||||
or
|
||||
this.hasAttribute("__getitem__") and
|
||||
not this.isSequence()
|
||||
}
|
||||
@@ -571,6 +649,10 @@ class ClassValue extends Value {
|
||||
* Note that this does not include other callables such as bound-methods.
|
||||
*/
|
||||
abstract class FunctionValue extends CallableValue {
|
||||
/**
|
||||
* Gets the qualified name for this function.
|
||||
* Should return the same name as the `__qualname__` attribute on functions in Python 3.
|
||||
*/
|
||||
abstract string getQualifiedName();
|
||||
|
||||
/** Gets a longer, more descriptive version of toString() */
|
||||
@@ -663,11 +745,13 @@ class PythonFunctionValue extends FunctionValue {
|
||||
ControlFlowNode getAReturnedNode() { result = this.getScope().getAReturnValueFlowNode() }
|
||||
|
||||
override ClassValue getARaisedType() { scope_raises(result, this.getScope()) }
|
||||
|
||||
|
||||
override ClassValue getAnInferredReturnType() {
|
||||
/* We have to do a special version of this because builtin functions have no
|
||||
/*
|
||||
* We have to do a special version of this because builtin functions have no
|
||||
* explicit return nodes that we can query and get the class of.
|
||||
*/
|
||||
|
||||
result = this.getAReturnedNode().pointsTo().getClass()
|
||||
}
|
||||
}
|
||||
@@ -690,9 +774,11 @@ class BuiltinFunctionValue extends FunctionValue {
|
||||
}
|
||||
|
||||
override ClassValue getAnInferredReturnType() {
|
||||
/* We have to do a special version of this because builtin functions have no
|
||||
/*
|
||||
* We have to do a special version of this because builtin functions have no
|
||||
* explicit return nodes that we can query and get the class of.
|
||||
*/
|
||||
|
||||
result = TBuiltinClassObject(this.(BuiltinFunctionObjectInternal).getReturnType())
|
||||
}
|
||||
}
|
||||
@@ -719,7 +805,7 @@ class BuiltinMethodValue extends FunctionValue {
|
||||
/* Information is unavailable for C code in general */
|
||||
none()
|
||||
}
|
||||
|
||||
|
||||
override ClassValue getAnInferredReturnType() {
|
||||
result = TBuiltinClassObject(this.(BuiltinMethodObjectInternal).getReturnType())
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ predicate used_as_regex(Expr s, string mode) {
|
||||
/* Call to re.xxx(regex, ... [mode]) */
|
||||
exists(CallNode call, string name |
|
||||
call.getArg(0).refersTo(_, _, s.getAFlowNode()) and
|
||||
call.getFunction().pointsTo(Module::named("re").attr(name))
|
||||
call.getFunction().pointsTo(Module::named("re").attr(name)) and
|
||||
not name = "escape"
|
||||
|
|
||||
mode = "None"
|
||||
or
|
||||
@@ -124,16 +125,40 @@ abstract class RegexString extends Expr {
|
||||
)
|
||||
}
|
||||
|
||||
/** Named unicode characters, eg \N{degree sign} */
|
||||
private predicate escapedName(int start, int end) {
|
||||
this.escapingChar(start) and
|
||||
this.getChar(start + 1) = "N" and
|
||||
this.getChar(start + 2) = "{" and
|
||||
this.getChar(end - 1) = "}" and
|
||||
end > start and
|
||||
not exists(int i | start + 2 < i and i < end - 1 |
|
||||
this.getChar(i) = "}"
|
||||
)
|
||||
}
|
||||
|
||||
private predicate escapedCharacter(int start, int end) {
|
||||
this.escapingChar(start) and
|
||||
not exists(this.getText().substring(start + 1, end + 1).toInt()) and
|
||||
(
|
||||
// hex value \xhh
|
||||
this.getChar(start + 1) = "x" and end = start + 4
|
||||
or
|
||||
// octal value \ooo
|
||||
end in [start + 2 .. start + 4] and
|
||||
exists(this.getText().substring(start + 1, end).toInt())
|
||||
or
|
||||
this.getChar(start + 1) != "x" and end = start + 2
|
||||
// 16-bit hex value \uhhhh
|
||||
this.getChar(start + 1) = "u" and end = start + 6
|
||||
or
|
||||
// 32-bit hex value \Uhhhhhhhh
|
||||
this.getChar(start + 1) = "U" and end = start + 10
|
||||
or
|
||||
escapedName(start, end)
|
||||
or
|
||||
// escape not handled above, update when adding a new case
|
||||
not this.getChar(start + 1) in ["x", "u", "U", "N"] and
|
||||
end = start + 2
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.SensitiveData
|
||||
import semmle.python.dataflow.Files
|
||||
import semmle.python.web.Http
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
private import semmle.python.security.SensitiveData
|
||||
private import semmle.crypto.Crypto as CryptoLib
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
|
||||
private Value traceback_function(string name) { result = Module::named("traceback").attr(name) }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
abstract class SqlInjectionSink extends TaintSink { }
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.HttpRequest
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
|
||||
/** Abstract taint sink that is potentially vulnerable to malicious shell commands. */
|
||||
@@ -231,3 +231,41 @@ class FabricV1Commands extends CommandSink {
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
/**
|
||||
* An extension that propagates taint from the arguments of `fabric.api.execute(func, arg0, arg1, ...)`
|
||||
* to the parameters of `func`, since this will call `func(arg0, arg1, ...)`.
|
||||
*/
|
||||
class FabricExecuteExtension extends DataFlowExtension::DataFlowNode {
|
||||
CallNode call;
|
||||
|
||||
FabricExecuteExtension() {
|
||||
call = Value::named("fabric.api.execute").getACall() and
|
||||
(
|
||||
this = call.getArg(any(int i | i > 0))
|
||||
or
|
||||
this = call.getArgByName(any(string s | not s = "task"))
|
||||
)
|
||||
}
|
||||
|
||||
override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) {
|
||||
tokind = fromkind and
|
||||
exists(CallableValue func |
|
||||
(
|
||||
call.getArg(0).pointsTo(func)
|
||||
or
|
||||
call.getArgByName("task").pointsTo(func)
|
||||
) and
|
||||
exists(int i |
|
||||
// execute(func, arg0, arg1) => func(arg0, arg1)
|
||||
this = call.getArg(i) and
|
||||
result = func.getParameter(i - 1)
|
||||
)
|
||||
or
|
||||
exists(string name |
|
||||
this = call.getArgByName(name) and
|
||||
result = func.getParameterByName(name)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
/** `pickle.loads(untrusted)` vulnerability. */
|
||||
abstract class DeserializationSink extends TaintSink {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.injection.Deserialization
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.injection.Deserialization
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.SQL
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.injection.Deserialization
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.injection.Deserialization
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import python
|
||||
private import Common
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
/** An extensible kind of taint representing any kind of string. */
|
||||
abstract class StringKind extends TaintKind {
|
||||
@@ -107,7 +107,11 @@ private predicate os_path_join(ControlFlowNode fromnode, CallNode tonode) {
|
||||
tonode.getAnArg() = fromnode
|
||||
}
|
||||
|
||||
/** A kind of "taint", representing a dictionary mapping str->"taint" */
|
||||
class StringDictKind extends DictKind {
|
||||
/**
|
||||
* A kind of "taint", representing a dictionary mapping str->"taint"
|
||||
*
|
||||
* DEPRECATED: Use `ExternalStringDictKind` instead.
|
||||
*/
|
||||
deprecated class StringDictKind extends DictKind {
|
||||
StringDictKind() { this.getValue() instanceof StringKind }
|
||||
}
|
||||
|
||||
@@ -60,14 +60,14 @@ class ExternalJsonKind extends TaintKind {
|
||||
}
|
||||
}
|
||||
|
||||
/** A kind of "taint", representing a dictionary mapping str->"taint" */
|
||||
/** A kind of "taint", representing a dictionary mapping keys to tainted strings. */
|
||||
class ExternalStringDictKind extends DictKind {
|
||||
ExternalStringDictKind() { this.getValue() instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
/**
|
||||
* A kind of "taint", representing a dictionary mapping strings to sequences of
|
||||
* tainted strings
|
||||
* A kind of "taint", representing a dictionary mapping keys to sequences of
|
||||
* tainted strings.
|
||||
*/
|
||||
class ExternalStringSequenceDictKind extends DictKind {
|
||||
ExternalStringSequenceDictKind() { this.getValue() instanceof ExternalStringSequenceKind }
|
||||
|
||||
@@ -118,7 +118,7 @@ class BuiltinModuleObject extends ModuleObject {
|
||||
|
||||
override predicate hasAttribute(string name) { exists(this.asBuiltin().getMember(name)) }
|
||||
|
||||
override predicate exportsComplete() { any() }
|
||||
deprecated override predicate exportsComplete() { any() }
|
||||
}
|
||||
|
||||
class PythonModuleObject extends ModuleObject {
|
||||
@@ -132,7 +132,7 @@ class PythonModuleObject extends ModuleObject {
|
||||
|
||||
override Container getPath() { result = this.getModule().getFile() }
|
||||
|
||||
override predicate exportsComplete() {
|
||||
deprecated override predicate exportsComplete() {
|
||||
exists(Module m | m = this.getModule() |
|
||||
not exists(Call modify, Attribute attr, GlobalVariable all |
|
||||
modify.getScope() = m and
|
||||
@@ -196,7 +196,7 @@ class PackageObject extends ModuleObject {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate exportsComplete() {
|
||||
deprecated override predicate exportsComplete() {
|
||||
not exists(this.getInitModule())
|
||||
or
|
||||
this.getInitModule().exportsComplete()
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.bottle.General
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.External
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.bottle.General
|
||||
|
||||
@@ -13,7 +13,7 @@ class BottleRequestKind extends TaintKind {
|
||||
result instanceof BottleFormsDict and
|
||||
(name = "cookies" or name = "query" or name = "form")
|
||||
or
|
||||
result instanceof UntrustedStringKind and
|
||||
result instanceof ExternalStringKind and
|
||||
(name = "query_string" or name = "url_args")
|
||||
or
|
||||
result.(DictKind).getValue() instanceof FileUpload and
|
||||
@@ -34,7 +34,7 @@ class BottleFormsDict extends TaintKind {
|
||||
/* Cannot use `getTaintOfAttribute(name)` as it wouldn't bind `name` */
|
||||
exists(string name |
|
||||
fromnode = tonode.(AttrNode).getObject(name) and
|
||||
result instanceof UntrustedStringKind
|
||||
result instanceof ExternalStringKind
|
||||
|
|
||||
name != "get" and name != "getunicode" and name != "getall"
|
||||
)
|
||||
@@ -42,9 +42,9 @@ class BottleFormsDict extends TaintKind {
|
||||
|
||||
override TaintKind getTaintOfMethodResult(string name) {
|
||||
(name = "get" or name = "getunicode") and
|
||||
result instanceof UntrustedStringKind
|
||||
result instanceof ExternalStringKind
|
||||
or
|
||||
name = "getall" and result.(SequenceKind).getItem() instanceof UntrustedStringKind
|
||||
name = "getall" and result.(SequenceKind).getItem() instanceof ExternalStringKind
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,9 +52,9 @@ class FileUpload extends TaintKind {
|
||||
FileUpload() { this = "bottle.FileUpload" }
|
||||
|
||||
override TaintKind getTaintOfAttribute(string name) {
|
||||
name = "filename" and result instanceof UntrustedStringKind
|
||||
name = "filename" and result instanceof ExternalStringKind
|
||||
or
|
||||
name = "raw_filename" and result instanceof UntrustedStringKind
|
||||
name = "raw_filename" and result instanceof ExternalStringKind
|
||||
or
|
||||
name = "file" and result instanceof UntrustedFile
|
||||
}
|
||||
@@ -74,7 +74,7 @@ class BottleRequestParameter extends HttpRequestTaintSource {
|
||||
exists(BottleRoute route | route.getANamedArgument() = this.(ControlFlowNode).getNode())
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof UntrustedStringKind }
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
|
||||
override string toString() { result = "bottle handler function argument" }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.bottle.General
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.cherrypy.General
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.cherrypy.General
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.security.injection.Sql
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
private import semmle.python.web.django.Shared
|
||||
private import semmle.python.web.Http
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.django.General
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
private import semmle.python.web.django.Shared
|
||||
private import semmle.python.web.Http
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.falcon.General
|
||||
import semmle.python.security.strings.External
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.falcon.General
|
||||
import semmle.python.security.strings.External
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.flask.General
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.web.flask.General
|
||||
|
||||
@@ -54,3 +54,35 @@ class FlaskRequestJson extends HttpRequestTaintSource {
|
||||
|
||||
override string toString() { result = "flask.request.json" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A parameter to a flask request handler, that can capture a part of the URL (as specified in
|
||||
* the url-pattern of a route).
|
||||
*
|
||||
* For example, the `name` parameter in:
|
||||
* ```
|
||||
* @app.route('/hello/<name>')
|
||||
* def hello(name):
|
||||
* ```
|
||||
*/
|
||||
class FlaskRoutedParameter extends HttpRequestTaintSource {
|
||||
FlaskRoutedParameter() {
|
||||
exists(string name, Function func, StrConst url_pattern |
|
||||
this.(ControlFlowNode).getNode() = func.getArgByName(name) and
|
||||
flask_routing(url_pattern.getAFlowNode(), func) and
|
||||
exists(string match |
|
||||
match = url_pattern.getS().regexpFind(werkzeug_rule_re(), _, _) and
|
||||
name = match.regexpCapture(werkzeug_rule_re(), 4)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
private string werkzeug_rule_re() {
|
||||
// since flask uses werkzeug internally, we are using its routing rules from
|
||||
// https://github.com/pallets/werkzeug/blob/4dc8d6ab840d4b78cbd5789cef91b01e3bde01d5/src/werkzeug/routing.py#L138-L151
|
||||
result =
|
||||
"(?<static>[^<]*)<(?:(?<converter>[a-zA-Z_][a-zA-Z0-9_]*)(?:\\((?<args>.*?)\\))?\\:)?(?<variable>[a-zA-Z_][a-zA-Z0-9_]*)>"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.flask.General
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
private import semmle.python.web.webob.Request
|
||||
private import semmle.python.web.pyramid.View
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
private import semmle.python.web.pyramid.View
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* (or subclasses) and form parsing using `cgi.FieldStorage`.
|
||||
*/
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
|
||||
/** Source of BaseHTTPRequestHandler instances. */
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
|
||||
private predicate is_wfile(AttrNode wfile) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
import Tornado
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import Tornado
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
private import semmle.python.web.Http
|
||||
import Tornado
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
|
||||
private ClassValue theTornadoRequestHandlerClass() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.strings.Untrusted
|
||||
import semmle.python.security.strings.External
|
||||
import semmle.python.web.Http
|
||||
import TurboGears
|
||||
|
||||
@@ -22,5 +22,5 @@ class UnvalidatedControllerMethodParameter extends HttpRequestTaintSource {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof UntrustedStringKind }
|
||||
override predicate isSourceOf(TaintKind kind) { kind instanceof ExternalStringKind }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.security.strings.Basic
|
||||
import semmle.python.web.Http
|
||||
import TurboGears
|
||||
@@ -27,5 +27,5 @@ class ControllerMethodTemplatedReturnValue extends HttpResponseTaintSink {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate sinks(TaintKind kind) { kind instanceof StringDictKind }
|
||||
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringDictKind }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
private ClassValue theTurboGearsControllerClass() { result = Value::named("tg.TGController") }
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import Twisted
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
import semmle.python.security.strings.Basic
|
||||
import Twisted
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
|
||||
private ClassValue theTwistedHttpRequestClass() {
|
||||
result = Value::named("twisted.web.http.Request")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import python
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.dataflow.TaintTracking
|
||||
import semmle.python.web.Http
|
||||
|
||||
abstract class BaseWebobRequest extends TaintKind {
|
||||
|
||||
@@ -116,7 +116,7 @@ class XMLFile extends XMLParent, File {
|
||||
XMLFile() { xmlEncoding(this, _) }
|
||||
|
||||
/** Gets a printable representation of this XML file. */
|
||||
override string toString() { result = XMLParent.super.toString() }
|
||||
override string toString() { result = getName() }
|
||||
|
||||
/** Gets the name of this XML file. */
|
||||
override string getName() { result = File.super.getAbsolutePath() }
|
||||
@@ -236,7 +236,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }
|
||||
|
||||
/** Gets a printable representation of this XML element. */
|
||||
override string toString() { result = XMLParent.super.toString() }
|
||||
override string toString() { result = getName() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user