/** * @name Modification of parameter with default * @description Modifying the default value of a parameter can lead to unexpected * results. * @kind path-problem * @tags reliability * maintainability * @problem.severity error * @sub-severity low * @precision high * @id py/modification-of-default-value */ import python import semmle.python.security.Paths predicate safe_method(string name) { name = "count" or name = "index" or name = "copy" or name = "get" or name = "has_key" or name = "items" or name = "keys" or name = "values" or name = "iteritems" or name = "iterkeys" or name = "itervalues" } /** Gets the truthiness (non emptyness) of the default of `p` if that value is mutable */ private boolean mutableDefaultValue(Parameter p) { exists(Dict d | p.getDefault() = d | exists(d.getAKey()) and result = true or not exists(d.getAKey()) and result = false ) or exists(List l | p.getDefault() = l | exists(l.getAnElt()) and result = true or not exists(l.getAnElt()) and result = false ) } class NonEmptyMutableValue extends TaintKind { NonEmptyMutableValue() { this = "non-empty mutable value" } } class EmptyMutableValue extends TaintKind { EmptyMutableValue() { this = "empty mutable value" } override boolean booleanValue() { result = false } } class MutableDefaultValue extends TaintSource { boolean nonEmpty; MutableDefaultValue() { nonEmpty = mutableDefaultValue(this.(NameNode).getNode()) } override string toString() { result = "mutable default value" } override predicate isSourceOf(TaintKind kind) { nonEmpty = false and kind instanceof EmptyMutableValue or nonEmpty = true and kind instanceof NonEmptyMutableValue } } class Mutation extends TaintSink { Mutation() { exists(AugAssign a | a.getTarget().getAFlowNode() = this) or exists(Call c, Attribute a | c.getFunc() = a | a.getObject().getAFlowNode() = this and not safe_method(a.getName()) ) } override predicate sinks(TaintKind kind) { kind instanceof EmptyMutableValue or kind instanceof NonEmptyMutableValue } } from TaintedPathSource src, TaintedPathSink sink where src.flowsTo(sink) select sink.getSink(), src, sink, "$@ flows to here and is mutated.", src.getSource(), "Default value"