Merge branch 'master' into python-cwe-312

This commit is contained in:
Mark Shannon
2019-08-30 10:30:51 +01:00
135 changed files with 12128 additions and 2591 deletions

View File

@@ -187,6 +187,18 @@ class TarSlipConfiguration extends TaintTracking::Configuration {
sanitizer instanceof ExcludeTarFilePy
}
override predicate isBarrier(DataFlow::Node node) {
// Avoid flow into the tarfile module
exists(ParameterDefinition def |
node.asVariable().getDefinition() = def
or
node.asCfgNode() = def.getDefiningNode()
|
def.getScope() = Value::named("tarfile.open").(CallableValue).getScope()
or
def.isSelf() and def.getScope().getEnclosingModule().getName() = "tarfile"
)
}
}

View File

@@ -32,6 +32,18 @@ class SQLInjectionConfiguration extends TaintTracking::Configuration {
}
/* Additional configuration to support tracking of DB objects. Connections, cursors, etc. */
class DbConfiguration extends TaintTracking::Configuration {
DbConfiguration() { this = "DB configuration" }
override predicate isSource(TaintTracking::Source source) {
source instanceof DjangoModelObjects or
source instanceof DbConnectionSource
}
}
from SQLInjectionConfiguration config, TaintedPathSource src, TaintedPathSink sink
where config.hasFlowPath(src, sink)
select sink.getSink(), src, sink, "This SQL query depends on $@.", src.getSource(), "a user-provided value"

View File

@@ -38,4 +38,4 @@ class CleartextLoggingConfiguration extends TaintTracking::Configuration {
from CleartextLoggingConfiguration config, TaintedPathSource source, TaintedPathSink sink
where config.hasFlowPath(source, sink)
select sink.getSink(), source, sink, "Sensitive data returned by $@ is logged here.",
source.getSource(), source.getNode().(SensitiveData::Source).repr()
source.getSource(), source.getCfgNode().(SensitiveData::Source).repr()

View File

@@ -37,4 +37,4 @@ class CleartextStorageConfiguration extends TaintTracking::Configuration {
from CleartextStorageConfiguration config, TaintedPathSource source, TaintedPathSink sink
where config.hasFlowPath(source, sink)
select sink.getSink(), source, sink, "Sensitive data from $@ is stored here.",
source.getSource(), source.getNode().(SensitiveData::Source).repr()
source.getSource(), source.getCfgNode().(SensitiveData::Source).repr()

View File

@@ -9,44 +9,6 @@ class Uninitialized extends TaintKind {
}
/** A source of an uninitialized variable.
* Either the start of the scope or a deletion.
*/
class UninitializedSource extends TaintedDefinition {
UninitializedSource() {
exists(FastLocalVariable var |
this.getSourceVariable() = var and
not var.escapes() |
this instanceof ScopeEntryDefinition
or
this instanceof DeletionDefinition
)
}
override predicate isSourceOf(TaintKind kind) {
kind instanceof Uninitialized
}
}
/** A loop where we are guaranteed (or is at least likely) to execute the body at least once.
*/
class AtLeastOnceLoop extends DataFlowExtension::DataFlowVariable {
AtLeastOnceLoop() {
loop_entry_variables(this, _)
}
/* If we are guaranteed to iterate over a loop at least once, then we can prune any edges that
* don't pass through the body.
*/
override predicate prunedSuccessor(EssaVariable succ) {
loop_entry_variables(this, succ)
}
}
private predicate loop_entry_variables(EssaVariable pred, EssaVariable succ) {
exists(PhiFunction phi, BasicBlock pb |
loop_entry_edge(pb, phi.getBasicBlock()) and
@@ -64,43 +26,6 @@ private predicate loop_entry_edge(BasicBlock pred, BasicBlock loop) {
)
}
class UnitializedSanitizer extends Sanitizer {
UnitializedSanitizer() { this = "use of variable" }
override
predicate sanitizingDefinition(TaintKind taint, EssaDefinition def) {
// An assignment cannot leave a variable uninitialized
taint instanceof Uninitialized and
(
def instanceof AssignmentDefinition
or
def instanceof ExceptionCapture
or
def instanceof ParameterDefinition
or
/* A use is a "sanitizer" of "uninitialized", as any use of an undefined
* variable will raise, making the subsequent code unreacahable.
*/
exists(def.(EssaNodeRefinement).getInput().getASourceUse())
or
exists(def.(PhiFunction).getAnInput().getASourceUse())
or
exists(def.(EssaEdgeRefinement).getInput().getASourceUse())
)
}
override
predicate sanitizingNode(TaintKind taint, ControlFlowNode node) {
taint instanceof Uninitialized and
exists(EssaVariable v |
v.getASourceUse() = node and
not first_use(node, v)
)
}
}
/** Since any use of a local will raise if it is uninitialized, then
* any use dominated by another use of the same variable must be defined, or is unreachable.
*/
@@ -124,15 +49,75 @@ private predicate maybe_call_to_exiting_function(CallNode call) {
)
}
/** Prune edges where the predecessor block looks like it might contain a call to an exit function. */
class ExitFunctionGuardedEdge extends DataFlowExtension::DataFlowVariable {
override predicate prunedSuccessor(EssaVariable succ) {
exists(CallNode exit_call |
succ.(PhiFunction).getInput(exit_call.getBasicBlock()) = this and
maybe_call_to_exiting_function(exit_call)
predicate exitFunctionGuardedEdge(EssaVariable pred, EssaVariable succ) {
exists(CallNode exit_call |
succ.(PhiFunction).getInput(exit_call.getBasicBlock()) = pred and
maybe_call_to_exiting_function(exit_call)
)
}
class UninitializedConfig extends TaintTracking::Configuration {
UninitializedConfig() {
this = "Unitialized local config"
}
override predicate isSource(DataFlow::Node source, TaintKind kind) {
kind instanceof Uninitialized and
exists(EssaVariable var |
source.asVariable() = var and
var.getSourceVariable() instanceof FastLocalVariable and
not var.getSourceVariable().(Variable).escapes() |
var instanceof ScopeEntryDefinition
or
var instanceof DeletionDefinition
)
}
override predicate isBarrier(DataFlow::Node node, TaintKind kind) {
kind instanceof Uninitialized and
(
definition(node.asVariable())
or
use(node.asVariable())
or
sanitizingNode(node.asCfgNode())
)
}
private predicate definition(EssaDefinition def) {
def instanceof AssignmentDefinition
or
def instanceof ExceptionCapture
or
def instanceof ParameterDefinition
}
private predicate use(EssaDefinition def) {
exists(def.(EssaNodeRefinement).getInput().getASourceUse())
or
exists(def.(PhiFunction).getAnInput().getASourceUse())
or
exists(def.(EssaEdgeRefinement).getInput().getASourceUse())
}
private predicate sanitizingNode(ControlFlowNode node) {
exists(EssaVariable v |
v.getASourceUse() = node and
not first_use(node, v)
)
}
override predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest) {
/* If we are guaranteed to iterate over a loop at least once, then we can prune any edges that
* don't pass through the body.
*/
loop_entry_variables(src.asVariable(), dest.asVariable())
or
exitFunctionGuardedEdge(src.asVariable(), dest.asVariable())
}
}

View File

@@ -0,0 +1,145 @@
import python
import semmle.python.security.TaintTracking
private import semmle.python.objects.ObjectInternal
private import semmle.python.dataflow.Implementation
module TaintTracking {
class Source = TaintSource;
class Sink = TaintSink;
class Extension = DataFlowExtension::DataFlowNode;
class PathSource = TaintTrackingNode;
class PathSink = TaintTrackingNode;
abstract class Configuration extends string {
/* Required to prevent compiler warning */
bindingset[this]
Configuration() { this = this }
/* Old implementation API */
predicate isSource(Source source) { none() }
predicate isSink(Sink sink) { none() }
predicate isSanitizer(Sanitizer sanitizer) { none() }
predicate isExtension(Extension extension) { none() }
/* New implementation API */
/**
* Holds if `source` is a source of taint of `kind` that is relevant
* for this configuration.
*/
predicate isSource(DataFlow::Node node, TaintKind kind) {
exists(TaintSource source |
this.isSource(source) and
node.asCfgNode() = source and
source.isSourceOf(kind)
)
}
/**
* Holds if `sink` is a sink of taint of `kind` that is relevant
* for this configuration.
*/
predicate isSink(DataFlow::Node node, TaintKind kind) {
exists(TaintSink sink |
node.asCfgNode() = sink and
sink.sinks(kind)
)
}
/**
* Holds if `src -> dest` should be considered as a flow edge
* in addition to standard data flow edges.
*/
predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest) { none() }
/**
* Holds if `src -> dest` is a flow edge converting taint from `srckind` to `destkind`.
*/
predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind) {
none()
}
/**
* Holds if `node` should be considered as a barrier to flow of any kind.
*/
predicate isBarrier(DataFlow::Node node) { none() }
/**
* Holds if `node` should be considered as a barrier to flow of `kind`.
*/
predicate isBarrier(DataFlow::Node node, TaintKind kind) {
exists(Sanitizer sanitizer |
this.isSanitizer(sanitizer)
|
sanitizer.sanitizingNode(kind, node.asCfgNode())
or
sanitizer.sanitizingEdge(kind, node.asVariable())
or
sanitizer.sanitizingSingleEdge(kind, node.asVariable())
or
sanitizer.sanitizingDefinition(kind, node.asVariable())
or
exists(MethodCallsiteRefinement call, FunctionObject callee |
call = node.asVariable().getDefinition() and
callee.getACall() = call.getCall() and
sanitizer.sanitizingCall(kind, callee)
)
)
}
/**
* Holds if flow from `src` to `dest` is prohibited.
*/
predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest) { none() }
/**
* Holds if control flow from `test` along the `isTrue` edge is prohibited.
*/
predicate isBarrierTest(ControlFlowNode test, boolean isTrue) { none() }
/**
* Holds if flow from `src` to `dest` is prohibited when the incoming taint is `srckind` and the outgoing taint is `destkind`.
* Note that `srckind` and `destkind` can be the same.
*/
predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind) { none() }
/* Common query API */
predicate hasFlowPath(PathSource source, PathSink sink) {
this.(TaintTrackingImplementation).hasFlowPath(source, sink)
}
/* Old query API */
/* deprecated */
predicate hasFlow(Source source, Sink sink) {
exists(PathSource psource, PathSink psink |
this.hasFlowPath(psource, psink) and
source = psource.getNode().asCfgNode() and
sink = psink.getNode().asCfgNode()
)
}
/* New query API */
predicate hasSimpleFlow(DataFlow::Node source, DataFlow::Node sink) {
exists(PathSource psource, PathSink psink |
this.hasFlowPath(psource, psink) and
source = psource.getNode() and
sink = psink.getNode()
)
}
}
}

View File

@@ -0,0 +1,852 @@
import python
import semmle.python.security.TaintTracking
private import semmle.python.objects.ObjectInternal
private import semmle.python.pointsto.Filters as Filters
import semmle.python.dataflow.Legacy
/* See tests/library-tests/taint/examples
* For examples of taint sources, sinks and flow,
* including attribute paths, contexts and edges.
*/
newtype TTaintTrackingContext =
TNoParam()
or
TParamContext(TaintKind param, AttributePath path, int n) {
any(TaintTrackingImplementation impl).callWithTaintedArgument(_, _, _, _, n, path, param)
}
/** The context for taint-tracking.
* There are two types of contexts:
* * No context; the context at a source.
* * Tainted parameter; tracks the taint and attribute-path for a parameter
* Used to track taint through calls accurately and reasonably efficiently.
*/
class TaintTrackingContext extends TTaintTrackingContext {
string toString() {
this = TNoParam() and result = ""
or
exists(TaintKind param, AttributePath path, int n |
this = TParamContext(param, path, n) and
result = "p" + n.toString() + path.extension() + " = " + param
)
}
TaintKind getParameterTaint(int n) {
this = TParamContext(result, _, n)
}
AttributePath getAttributePath() {
this = TParamContext(_, result, _)
}
TaintTrackingContext getCaller() {
result = this.getCaller(_)
}
TaintTrackingContext getCaller(CallNode call) {
exists(TaintKind param, AttributePath path, int n |
this = TParamContext(param, path, n) and
exists(TaintTrackingImplementation impl |
impl.callWithTaintedArgument(_, call, result, _, n, path, param)
)
)
}
predicate isTop() {
this = TNoParam()
}
}
private newtype TAttributePath =
TNoAttribute()
or
TAttribute(string name) {
exists(Attribute a | a.getName() = name)
}
/* It might make sense to add another level, attribute of attribute.
* But some experimentation would be needed.
*/
/** The attribute of the tracked value holding the taint.
* This is usually "no attribute".
* Used for tracking tainted attributes of objects.
*/
abstract class AttributePath extends TAttributePath {
abstract string toString();
abstract string extension();
abstract AttributePath fromAttribute(string name);
AttributePath getAttribute(string name) {
this = result.fromAttribute(name)
}
predicate noAttribute() {
this = TNoAttribute()
}
}
/** AttributePath for no attribute. */
class NoAttribute extends TNoAttribute, AttributePath {
override string toString() { result = "no attribute" }
override string extension() { result = "" }
override AttributePath fromAttribute(string name) {
none()
}
}
/** AttributePath for an attribute. */
class NamedAttributePath extends TAttribute, AttributePath {
override string toString() {
exists(string attr |
this = TAttribute(attr) and
result = "attribute " + attr
)
}
override string extension() {
exists(string attr |
this = TAttribute(attr) and
result = "." + attr
)
}
override AttributePath fromAttribute(string name) {
this = TAttribute(name) and result = TNoAttribute()
}
}
/** Type representing the (node, context, path, kind) tuple.
* Construction of this type is mutually recursive with `TaintTrackingImplementation.flowStep(...)`
*/
newtype TTaintTrackingNode =
TTaintTrackingNode_(DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, TaintTracking::Configuration config) {
config.(TaintTrackingImplementation).flowSource(node, context, path, kind)
or
config.(TaintTrackingImplementation).flowStep(_, node, context, path, kind, _)
}
/** Class representing the (node, context, path, kind) tuple.
* Used for context-sensitive path-aware taint-tracking.
*/
class TaintTrackingNode extends TTaintTrackingNode {
string toString() {
if this.getPath() instanceof NoAttribute then (
result = this.getTaintKind().repr()
) else (
result = this.getPath().extension() + " = " + this.getTaintKind().repr()
)
}
/** Gets the data flow node for this taint-tracking node */
DataFlow::Node getNode() {
this = TTaintTrackingNode_(result, _, _, _, _)
}
/** Gets the taint kind for this taint-tracking node */
TaintKind getTaintKind() {
this = TTaintTrackingNode_(_, _, _, result, _)
}
/** Gets the taint-tracking context for this taint-tracking node */
TaintTrackingContext getContext() {
this = TTaintTrackingNode_(_, result, _, _, _)
}
/** Gets the attribute path context for this taint-tracking node */
AttributePath getPath() {
this = TTaintTrackingNode_(_, _, result, _, _)
}
TaintTracking::Configuration getConfiguration() {
this = TTaintTrackingNode_(_, _, _, _, result)
}
Location getLocation() {
result = this.getNode().getLocation()
}
predicate isSource() {
this.getConfiguration().(TaintTrackingImplementation).isPathSource(this)
}
predicate isSink() {
this.getConfiguration().(TaintTrackingImplementation).isPathSink(this)
}
ControlFlowNode getCfgNode() {
result = this.getNode().asCfgNode()
}
/** Get the AST node for this node. */
AstNode getAstNode() {
result = this.getCfgNode().getNode()
}
TaintTrackingNode getASuccessor(string edgeLabel) {
this.isVisible() and
result = this.unlabeledSuccessor*().labeledSuccessor(edgeLabel)
}
TaintTrackingNode getASuccessor() {
result = this.getASuccessor(_)
or
this.isVisible() and
result = this.unlabeledSuccessor+() and
result.isSink()
}
private TaintTrackingNode unlabeledSuccessor() {
this.getConfiguration().(TaintTrackingImplementation).flowStep(this, result, "")
}
private TaintTrackingNode labeledSuccessor(string label) {
not label = "" and
this.getConfiguration().(TaintTrackingImplementation).flowStep(this, result, label)
}
private predicate isVisible() {
any(TaintTrackingNode pred).labeledSuccessor(_) = this
or
this.isSource()
}
predicate flowsTo(TaintTrackingNode other) {
this.getASuccessor*() = other
}
}
/** The implementation of taint-tracking
* Each `TaintTrackingImplementation` is also a `TaintTracking::Configuration`
* It is implemented as a separate class for clarity and to keep the code
* in `TaintTracking::Configuration` simpler.
*/
class TaintTrackingImplementation extends string {
TaintTrackingImplementation() {
this instanceof TaintTracking::Configuration
}
/** Hold if there is a flow from `source`, which is a taint source, to
* `sink`, which is a taint sink, with this configuration.
*/
predicate hasFlowPath(TaintTrackingNode source, TaintTrackingNode sink) {
this.isPathSource(source) and
this.isPathSink(sink) and
source.flowsTo(sink)
}
/** Hold if `node` is a source of taint `kind` with context `context` and attribute path `path`.
*/
predicate flowSource(DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
context = TNoParam() and path = TNoAttribute() and
this.(TaintTracking::Configuration).isSource(node, kind)
}
/** Hold if `source` is a source of taint. */
predicate isPathSource(TaintTrackingNode source) {
exists(DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind |
source = TTaintTrackingNode_(node, context, path, kind, this) and
this.flowSource(node, context, path, kind)
)
}
/** Hold if `sink` is a taint sink. */
predicate isPathSink(TaintTrackingNode sink) {
exists(DataFlow::Node node, AttributePath path, TaintKind kind |
sink = TTaintTrackingNode_(node, _, path, kind, this) and
path = TNoAttribute() and
this.(TaintTracking::Configuration).isSink(node, kind)
)
}
/** Hold if taint flows to `src` to `dest` in a single step, labeled with `edgeLabel`
* `edgeLabel` is purely informative.
*/
predicate flowStep(TaintTrackingNode src, TaintTrackingNode dest, string edgeLabel) {
exists(DataFlow::Node node, TaintTrackingContext ctx, AttributePath path, TaintKind kind |
dest = TTaintTrackingNode_(node, ctx, path, kind, this) and
this.flowStep(src, node, ctx, path, kind, edgeLabel)
)
}
/** Hold if taint flows to `src` to `(node, context, path, kind)` in a single step, labelled with `egdeLabel` with this configuration.
* `edgeLabel` is purely informative.
*/
predicate flowStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
this.unprunedStep(src, node, context, path, kind, edgeLabel) and
node.getBasicBlock().likelyReachable() and
not this.(TaintTracking::Configuration).isBarrier(node) and
(
not path = TNoAttribute()
or
not this.(TaintTracking::Configuration).isBarrier(node, kind) and
exists(DataFlow::Node srcnode, TaintKind srckind |
src = TTaintTrackingNode_(srcnode, _, _, srckind, this) and
not this.prunedEdge(srcnode, node, srckind, kind)
)
)
}
private predicate prunedEdge(DataFlow::Node srcnode, DataFlow::Node destnode, TaintKind srckind, TaintKind destkind) {
this.(TaintTracking::Configuration).isBarrierEdge(srcnode, destnode, srckind, destkind)
or
srckind = destkind and this.(TaintTracking::Configuration).isBarrierEdge(srcnode, destnode)
}
private predicate unprunedStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
this.importStep(src, node, context, path, kind, edgeLabel)
or
this.fromImportStep(src, node, context, path, kind, edgeLabel)
or
this.attributeLoadStep(src, node, context, path, kind, edgeLabel)
or
this.getattrStep(src, node, context, path, kind, edgeLabel)
or
this.useStep(src, node, context, path, kind, edgeLabel)
or
this.callTaintStep(src, node, context, path, kind, edgeLabel)
or
this.returnFlowStep(src, node, context, path, kind, edgeLabel)
or
this.callFlowStep(src, node, context, path, kind, edgeLabel)
or
this.iterationStep(src, node, context, path, kind, edgeLabel)
or
this.yieldStep(src, node, context, path, kind, edgeLabel)
or
this.parameterStep(src, node, context, path, kind, edgeLabel)
or
this.ifExpStep(src, node, context, path, kind, edgeLabel)
or
this.essaFlowStep(src, node, context, path, kind, edgeLabel)
or
this.instantiationStep(src, node, context, path, kind, edgeLabel)
or
this.legacyExtensionStep(src, node, context, path, kind, edgeLabel)
or
exists(DataFlow::Node srcnode, TaintKind srckind |
this.(TaintTracking::Configuration).isAdditionalFlowStep(srcnode, node, srckind, kind) and
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
path.noAttribute() and edgeLabel = "additional with kind"
)
or
exists(DataFlow::Node srcnode |
this.(TaintTracking::Configuration).isAdditionalFlowStep(srcnode, node) and
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
path.noAttribute() and edgeLabel = "additional"
)
or
exists(DataFlow::Node srcnode, TaintKind srckind |
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
path.noAttribute()
|
kind = srckind.getTaintForFlowStep(srcnode.asCfgNode(), node.asCfgNode(), edgeLabel)
or
kind = srckind.(CollectionKind).getMember() and
srckind.(CollectionKind).flowToMember(srcnode, node) and
edgeLabel = "to member"
or
srckind = kind.(CollectionKind).getMember() and
kind.(CollectionKind).flowFromMember(srcnode, node) and
edgeLabel = "from member"
or
kind = srckind and srckind.flowStep(srcnode, node, edgeLabel)
or
kind = srckind and srckind instanceof DictKind and DictKind::flowStep(srcnode.asCfgNode(), node.asCfgNode(), edgeLabel)
or
kind = srckind and srckind instanceof SequenceKind and SequenceKind::flowStep(srcnode.asCfgNode(), node.asCfgNode(), edgeLabel)
)
}
pragma [noinline]
predicate importStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
edgeLabel = "import" and
exists(ModuleValue m, string name, AttributePath srcpath |
src = TTaintTrackingNode_(_, context, srcpath, kind, this) and
this.moduleAttributeTainted(m, name, src) and
node.asCfgNode().pointsTo(m) and
path = srcpath.getAttribute(name)
)
}
pragma [noinline]
predicate fromImportStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
edgeLabel = "from import" and
exists(ModuleValue m, string name |
src = TTaintTrackingNode_(_, context, path, kind, this) and
this.moduleAttributeTainted(m, name, src) and
node.asCfgNode().(ImportMemberNode).getModule(name).pointsTo(m)
)
}
pragma [noinline]
predicate attributeLoadStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
exists(DataFlow::Node srcnode, AttributePath srcpath, string attrname |
src = TTaintTrackingNode_(srcnode, context, srcpath, kind, this) and
srcnode.asCfgNode() = node.asCfgNode().(AttrNode).getObject(attrname) and
path = srcpath.fromAttribute(attrname) and edgeLabel = "from path attribute"
)
or
exists(DataFlow::Node srcnode, TaintKind srckind, string attrname |
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
srcnode.asCfgNode() = node.asCfgNode().(AttrNode).getObject(attrname) and
kind = srckind.getTaintOfAttribute(attrname) and edgeLabel = "from taint attribute" and
path instanceof NoAttribute
)
}
pragma [noinline]
predicate getattrStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
exists(DataFlow::Node srcnode, AttributePath srcpath, TaintKind srckind, string attrname |
src = TTaintTrackingNode_(srcnode, context, srcpath, srckind, this) and
exists(CallNode call, ControlFlowNode arg |
call = node.asCfgNode() and
call.getFunction().pointsTo(ObjectInternal::builtin("getattr")) and
arg = call.getArg(0) and
attrname = call.getArg(1).getNode().(StrConst).getText() and
arg = srcnode.asCfgNode()
|
path = srcpath.fromAttribute(attrname) and
kind = srckind
or
path = srcpath and
kind = srckind.getTaintOfAttribute(attrname)
)
) and edgeLabel = "getattr"
}
pragma [noinline]
predicate useStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
node.asCfgNode() = srcnode.asVariable().getASourceUse()
) and edgeLabel = "use"
}
/* If the return value is tainted without context, then it always flows back to the caller */
pragma [noinline]
predicate returnFlowStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
exists(CallNode call, PythonFunctionObjectInternal pyfunc, DataFlow::Node retval |
pyfunc.getACall() = call and
context = TNoParam() and
src = TTaintTrackingNode_(retval, TNoParam(), path, kind, this) and
node.asCfgNode() = call and
retval.asCfgNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode()
) and
edgeLabel = "return"
}
/* Avoid taint flow from return value to caller as it can produce imprecise flow graphs
* Step directly from tainted argument to call result.
*/
pragma [noinline]
predicate callFlowStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
exists(CallNode call, PythonFunctionObjectInternal pyfunc, TaintTrackingContext callee, DataFlow::Node retval, TaintTrackingNode retnode |
this.callContexts(call, src, pyfunc, context, callee) and
retnode = TTaintTrackingNode_(retval, callee, path, kind, this) and
node.asCfgNode() = call and
retval.asCfgNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode()
) and
edgeLabel = "call"
}
pragma [noinline]
predicate callContexts(CallNode call, TaintTrackingNode argnode, PythonFunctionObjectInternal pyfunc, TaintTrackingContext caller, TaintTrackingContext callee) {
exists(int arg, TaintKind callerKind, AttributePath callerPath |
this.callWithTaintedArgument(argnode, call, caller, pyfunc, arg, callerPath, callerKind) and
callee = TParamContext(callerKind, callerPath, arg)
)
}
predicate callWithTaintedArgument(TaintTrackingNode src, CallNode call, TaintTrackingContext caller, CallableValue pyfunc, int arg, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, caller, path, kind, this) and
srcnode.asCfgNode() = pyfunc.getArgumentForCall(call, arg)
)
}
predicate instantiationStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
exists(PythonFunctionValue init, EssaVariable self, TaintTrackingContext callee |
instantiationCall(node.asCfgNode(), src, init, context, callee) and
this.(EssaTaintTracking).taintedDefinition(_, self.getDefinition(), callee, path, kind) and
self.getSourceVariable().(Variable).isSelf() and
BaseFlow::reaches_exit(self) and
self.getScope() = init.getScope()
) and
edgeLabel = "instantiation"
}
predicate instantiationCall(CallNode call, TaintTrackingNode argnode, PythonFunctionObjectInternal init, TaintTrackingContext caller, TaintTrackingContext callee) {
exists(ClassValue cls |
call.getFunction().pointsTo(cls) and
cls.lookup("__init__") = init
|
exists(int arg, TaintKind callerKind, AttributePath callerPath, DataFlow::Node argument |
argnode = TTaintTrackingNode_(argument, caller, callerPath, callerKind, this) and
call.getArg(arg-1) = argument.asCfgNode() and
callee = TParamContext(callerKind, callerPath, arg)
)
)
}
pragma [noinline]
predicate callTaintStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
exists(DataFlow::Node srcnode, CallNode call, TaintKind srckind, string name |
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
call.getFunction().(AttrNode).getObject(name) = src.getNode().asCfgNode() and
kind = srckind.getTaintOfMethodResult(name) and
node.asCfgNode() = call
) and edgeLabel = "call"
}
pragma [noinline]
predicate iterationStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
exists(ForNode for, DataFlow::Node sequence, TaintKind seqkind |
src = TTaintTrackingNode_(sequence, context, path, seqkind, this) and
for.iterates(_, sequence.asCfgNode()) and
node.asCfgNode() = for and
path.noAttribute() and
kind = seqkind.getTaintForIteration()
) and edgeLabel = "iteration"
}
pragma [noinline]
predicate parameterStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
exists(CallNode call, PythonFunctionObjectInternal pyfunc, int arg |
this.callWithTaintedArgument(src, call, _, pyfunc, arg, path, kind) and
node.asCfgNode() = pyfunc.getParameter(arg) and
context = TParamContext(kind, path, arg)
) and edgeLabel = "parameter"
}
pragma [noinline]
predicate yieldStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
exists(DataFlow::Node srcnode, TaintKind itemkind |
src = TTaintTrackingNode_(srcnode, context, path, itemkind, this) and
itemkind = kind.getTaintForIteration() and
exists(PyFunctionObject func |
func.getFunction().isGenerator() and
func.getACall() = node.asCfgNode() and
exists(Yield yield |
yield.getScope() = func.getFunction() and
yield.getValue() = srcnode.asCfgNode().getNode()
)
)
) and edgeLabel = "yield"
}
pragma [noinline]
predicate ifExpStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asCfgNode() = node.asCfgNode().(IfExprNode).getAnOperand()
) and edgeLabel = "if exp"
}
pragma [noinline]
predicate essaFlowStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
this.(EssaTaintTracking).taintedDefinition(src, node.asVariable().getDefinition(), context, path, kind) and edgeLabel = ""
}
pragma [noinline]
predicate legacyExtensionStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
exists(TaintTracking::Extension extension, DataFlow::Node srcnode, TaintKind srckind |
this.(TaintTracking::Configuration).isExtension(extension) and
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
srcnode.asCfgNode() = extension
|
extension.getASuccessorNode() = node.asCfgNode() and kind = srckind
or
extension.getASuccessorNode(srckind, kind) = node.asCfgNode()
or
extension.getASuccessorVariable() = node.asVariable() and kind = srckind
) and edgeLabel = "legacy extension"
}
predicate moduleAttributeTainted(ModuleValue m, string name, TaintTrackingNode taint) {
exists(DataFlow::Node srcnode, EssaVariable var |
taint = TTaintTrackingNode_(srcnode, TNoParam(), _, _, this) and
var = srcnode.asVariable() and
var.getName() = name and
BaseFlow::reaches_exit(var) and
var.getScope() = m.getScope()
)
}
}
/** Another taint-tracking class to help partition the code for clarity
* This class handle tracking of ESSA variables. */
private class EssaTaintTracking extends string {
EssaTaintTracking() {
this instanceof TaintTracking::Configuration
}
pragma [noinline]
predicate taintedDefinition(TaintTrackingNode src, EssaDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
this.taintedPhi(src, defn, context, path, kind)
or
this.taintedAssignment(src, defn, context, path, kind)
or
this.taintedAttributeAssignment(src, defn, context, path, kind)
or
this.taintedParameterDefinition(src, defn, context, path, kind)
or
this.taintedCallsite(src, defn, context, path, kind)
or
this.taintedMethodCallsite(src, defn, context, path, kind)
or
this.taintedUniEdge(src, defn, context, path, kind)
or
this.taintedPiNode(src, defn, context, path, kind)
or
this.taintedArgument(src, defn, context, path, kind)
or
this.taintedExceptionCapture(src, defn, context, path, kind)
or
this.taintedScopeEntryDefinition(src, defn, context, path, kind)
or
this.taintedWith(src, defn, context, path, kind)
}
pragma [noinline]
private predicate taintedPhi(TaintTrackingNode src, PhiFunction defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode, BasicBlock pred, EssaVariable predvar, DataFlow::Node phi |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
defn = phi.asVariable().getDefinition() and
predvar = defn.getInput(pred) and
not pred.unlikelySuccessor(defn.getBasicBlock()) and
not this.(TaintTracking::Configuration).isBarrierEdge(srcnode, phi) and
srcnode.asVariable() = predvar
)
}
pragma [noinline]
private predicate taintedAssignment(TaintTrackingNode src, AssignmentDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
defn.getValue() = srcnode.asCfgNode()
)
}
pragma [noinline]
private predicate taintedAttributeAssignment(TaintTrackingNode src, AttributeAssignment defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode, AttributePath srcpath, string attrname |
src = TTaintTrackingNode_(srcnode, context, srcpath, kind, this) and
defn.getValue() = srcnode.asCfgNode() and
defn.getName() = attrname and
path = srcpath.getAttribute(attrname)
)
}
pragma [noinline]
private predicate taintedParameterDefinition(TaintTrackingNode src, ParameterDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asCfgNode() = defn.getDefiningNode()
)
}
pragma [noinline]
private predicate taintedCallsite(TaintTrackingNode src, CallsiteRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
/* In the interest of simplicity and performance we assume that tainted escaping variables remain tainted across calls.
* In the cases were this assumption is false, it is easy enough to add an additional barrier.
*/
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asVariable() = defn.getInput()
)
}
pragma [noinline]
private predicate taintedMethodCallsite(TaintTrackingNode src, MethodCallsiteRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asVariable() = defn.getInput()
)
}
pragma [noinline]
private predicate taintedUniEdge(TaintTrackingNode src, SingleSuccessorGuard defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asVariable() = defn.getInput() and
not this.(TaintTracking::Configuration).isBarrierTest(defn.getTest(), defn.getSense())
)
}
private predicate taintedPiNode(TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
taintedPiNodeOneway(src, defn, context, path, kind)
or
taintedPiNodeBothways(src, defn, context, path, kind)
}
pragma [noinline]
private predicate taintedPiNodeOneway(TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode, ControlFlowNode use |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
not this.(TaintTracking::Configuration).isBarrierTest(defn.getTest(), defn.getSense()) and
defn.getSense() = testEvaluates(defn, defn.getTest(), use, src)
)
}
pragma [noinline]
private predicate taintedPiNodeBothways(TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode, ControlFlowNode test, ControlFlowNode use |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
piNodeTestAndUse(defn, test, use) and
srcnode.asVariable() = defn.getInput() and
not this.(TaintTracking::Configuration).isBarrierTest(test, defn.getSense()) and
testEvaluatesMaybe(test, use)
)
}
pragma [noinline]
private predicate taintedArgument(TaintTrackingNode src, ArgumentRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
defn.getInput() = srcnode.asVariable()
)
}
pragma [noinline]
private predicate taintedExceptionCapture(TaintTrackingNode src, ExceptionCapture defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asCfgNode() = defn.getDefiningNode()
)
}
pragma [noinline]
private predicate taintedScopeEntryDefinition(TaintTrackingNode src, ScopeEntryDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(EssaVariable var |
BaseFlow::scope_entry_value_transfer_from_earlier(var, _, defn, _) and
this.taintedDefinition(src, var.getDefinition(), context, path, kind)
)
}
pragma [noinline]
private predicate taintedWith(TaintTrackingNode src, WithDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
with_flow(_, srcnode.asCfgNode(), defn.getDefiningNode())
)
}
/** Gets the boolean value that `test` evaluates to when `use` is tainted with `kind`
* and `test` and `use` are part of a test in a branch.
*/
private boolean testEvaluates(PyEdgeRefinement defn, ControlFlowNode test, ControlFlowNode use, TaintTrackingNode src) {
defn.getTest().getAChild*() = use and
exists(DataFlow::Node srcnode, TaintKind kind |
srcnode.asVariable() = defn.getInput() and
srcnode.asVariable().getASourceUse() = use and
src = TTaintTrackingNode_(srcnode, _, TNoAttribute(), kind, this)
|
test = use and result = kind.booleanValue()
or
exists(ControlFlowNode const |
Filters::equality_test(test, use, result.booleanNot(), const) and
const.getNode() instanceof ImmutableLiteral
)
or
exists(ControlFlowNode c, ClassValue cls |
Filters::isinstance(test, c, use) and
c.pointsTo(cls)
|
exists(ClassValue scls |
scls = kind.getType() |
scls.getASuperType() = cls and result = true
or
not scls.getASuperType() = cls and result = false
)
or
not exists(kind.getType()) and result = maybe()
)
)
or
result = testEvaluates(defn, not_operand(test), use, src).booleanNot()
}
/** Holds if `test` is the test in a branch and `use` is that test
* with all the `not` prefixes removed.
*/
private predicate boolean_filter(ControlFlowNode test, ControlFlowNode use) {
any(PyEdgeRefinement ref).getTest() = test and
(
use = test
or
exists(ControlFlowNode notuse |
boolean_filter(test, notuse) and
use = not_operand(notuse)
)
)
}
}
private predicate testEvaluatesMaybe(ControlFlowNode test, ControlFlowNode use) {
any(PyEdgeRefinement ref).getTest().getAChild*() = test and
test.getAChild*() = use and
not test.(UnaryExprNode).getNode().getOp() instanceof Not and
not Filters::equality_test(test, use, _, _) and
not Filters::isinstance(test, _, use) and
not test = use
or
testEvaluatesMaybe(not_operand(test), use)
}
/** Gets the operand of a unary `not` expression. */
private ControlFlowNode not_operand(ControlFlowNode expr) {
expr.(UnaryExprNode).getNode().getOp() instanceof Not and
result = expr.(UnaryExprNode).getOperand()
}
/* Helper predicate for tainted_with */
private predicate with_flow(With with, ControlFlowNode contextManager, ControlFlowNode var) {
with.getContextExpr() = contextManager.getNode() and
with.getOptionalVars() = var.getNode() and
contextManager.strictlyDominates(var)
}
/* Helper predicate for taintedPiNode */
pragma [noinline]
private predicate piNodeTestAndUse(PyEdgeRefinement defn, ControlFlowNode test, ControlFlowNode use) {
test = defn.getTest() and use = defn.getInput().getASourceUse() and test.getAChild*() = use
}
module Implementation {
/* A call that returns a copy (or similar) of the argument */
predicate copyCall(ControlFlowNode fromnode, CallNode tonode) {
tonode.getFunction().(AttrNode).getObject("copy") = fromnode
or
exists(ModuleObject copy, string name |
name = "copy" or name = "deepcopy" |
copy.attr(name).(FunctionObject).getACall() = tonode and
tonode.getArg(0) = fromnode
)
or
tonode.getFunction().pointsTo(ObjectInternal::builtin("reversed")) and
tonode.getArg(0) = fromnode
}
}

View File

@@ -0,0 +1,94 @@
import semmle.python.security.TaintTracking
private import semmle.python.objects.ObjectInternal
import semmle.python.dataflow.Implementation
/* For backwards compatibility -- Use `TaintTrackingContext` instead. */
deprecated
class CallContext extends TaintTrackingContext {
TaintTrackingContext getCallee(CallNode call) {
result.getCaller(call) = this
}
predicate appliesToScope(Scope s) {
exists(PythonFunctionObjectInternal func, TaintKind param, AttributePath path, int n |
this = TParamContext(param, path, n) and
exists(TaintTrackingImplementation impl |
impl.callWithTaintedArgument(_, _, _, func, n, path, param) and
s = func.getScope()
)
)
or
this.isTop()
}
}
/* Backwards compatibility with config-less taint-tracking */
private class LegacyConfiguration extends TaintTracking::Configuration {
LegacyConfiguration() {
/* A name that won't be accidentally chosen by users */
this = "Semmle: Internal legacy configuration"
}
override predicate isSource(TaintSource src) {
isValid() and
src = src
}
override predicate isSink(TaintSink sink) {
isValid() and
sink = sink
}
override predicate isSanitizer(Sanitizer sanitizer) {
isValid() and
sanitizer = sanitizer
}
private predicate isValid() {
not exists(TaintTracking::Configuration config | config != this)
}
override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest) {
isValid() and
exists(DataFlowExtension::DataFlowNode legacyExtension |
src.asCfgNode() = legacyExtension
|
dest.asCfgNode() = legacyExtension.getASuccessorNode()
or
dest.asVariable() = legacyExtension.getASuccessorVariable()
or
dest.asCfgNode() = legacyExtension.getAReturnSuccessorNode(_)
or
dest.asCfgNode() = legacyExtension.getACalleeSuccessorNode(_)
)
}
override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind) {
isValid() and
exists(DataFlowExtension::DataFlowNode legacyExtension |
src.asCfgNode() = legacyExtension
|
dest.asCfgNode() = legacyExtension.getASuccessorNode(srckind, destkind)
)
}
override predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest) {
isValid() and
(
exists(DataFlowExtension::DataFlowVariable legacyExtension |
src.asVariable() = legacyExtension and
legacyExtension.prunedSuccessor(dest.asVariable())
)
or
exists(DataFlowExtension::DataFlowNode legacyExtension |
src.asCfgNode() = legacyExtension and
legacyExtension.prunedSuccessor(dest.asCfgNode())
)
)
}
}

View File

@@ -170,6 +170,8 @@ abstract class EssaDefinition extends TEssaDefinition {
result.getDefinition() = this
}
abstract BasicBlock getBasicBlock();
}
/** An ESSA definition corresponding to an edge refinement of the underlying variable.
@@ -233,6 +235,10 @@ class EssaEdgeRefinement extends EssaDefinition, TEssaEdgeDefinition {
result = this.getPredecessor().getScope()
}
override BasicBlock getBasicBlock(){
result = this.getSuccessor()
}
}
/** A Phi-function as specified in classic SSA form. */
@@ -295,7 +301,7 @@ class PhiFunction extends EssaDefinition, TPhiFunction {
}
/** Gets the basic block that succeeds this phi node. */
BasicBlock getBasicBlock() {
override BasicBlock getBasicBlock() {
this = TPhiFunction(_, result)
}
@@ -446,6 +452,10 @@ class EssaNodeDefinition extends EssaDefinition, TEssaNodeDefinition {
)
}
override BasicBlock getBasicBlock(){
result = this.getDefiningNode().getBasicBlock()
}
}
/** A definition of an ESSA variable that takes another ESSA variable as an input.
@@ -512,6 +522,10 @@ class EssaNodeRefinement extends EssaDefinition, TEssaNodeRefinement {
)
}
override BasicBlock getBasicBlock(){
result = this.getDefiningNode().getBasicBlock()
}
}
pragma[noopt]

View File

@@ -192,4 +192,16 @@ module Cryptography {
}
private class CipherConfig extends TaintTracking::Configuration {
CipherConfig() { this = "Crypto cipher config" }
override predicate isSource(TaintTracking::Source source) {
source instanceof Pycrypto::CipherInstanceSource
or
source instanceof Cryptography::CipherSource
}
}

View File

@@ -1,9 +1,20 @@
import python
import semmle.python.dataflow.Implementation
import semmle.python.security.TaintTracking
module TaintTrackingPaths {
predicate edge(TaintTrackingNode src, TaintTrackingNode dest, string label) {
exists(TaintTrackingNode source, TaintTrackingNode sink |
source.getConfiguration().hasFlowPath(source, sink) and
source.getASuccessor*() = src and
src.getASuccessor(label) = dest and
dest.getASuccessor*() = sink
)
}
query predicate edges(TaintedNode fromnode, TaintedNode tonode) {
fromnode.getASuccessor() = tonode and
/* Don't record flow past sinks */
not fromnode.isSink()
}
query predicate edges(TaintTrackingNode fromnode, TaintTrackingNode tonode) {
TaintTrackingPaths::edge(fromnode, tonode, _)
}

View File

@@ -4,4 +4,4 @@
import python
import TaintTracking::TaintFlowImplementation as TaintFlowTest
import semmle.python.dataflow.Implementation as TaintFlowTest

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
import python
import semmle.python.security.TaintTracking
import semmle.python.dataflow.Implementation
import semmle.python.security.strings.External
import HttpConstants
@@ -16,7 +16,7 @@ class WsgiEnvironment extends TaintKind {
WsgiEnvironment() { this = "wsgi.environment" }
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
result = this and TaintFlowImplementation::copyCall(fromnode, tonode)
result = this and Implementation::copyCall(fromnode, tonode)
or
result = this and
tonode.(CallNode).getFunction().refersTo(theDictType()) and