Files
codeql/python/ql/lib/semmle/python/security
yoff 6d1a82d0ed Python: switch dataflow library to new (shared) CFG + SSA
Flips the Python dataflow trunk from the legacy CFG (semmle/python/Flow.qll)
and legacy ESSA SSA (semmle/python/essa/*) to the new shared CFG facade
(semmle.python.controlflow.internal.Cfg) and the new SSA adapter
(semmle.python.dataflow.new.internal.SsaImpl), both introduced
additively in the preceding PRs in this stack.

This is the trunk-flip equivalent of the original draft PR #21894 (kept
around as documentation), rebased on top of the four preparatory PRs:

  P1: Remove AstNode.getAFlowNode() and rewrite callers (#21919).
  P2: Qualify Flow.qll's AST references with Py:: prefix (#21920).
  P3: Add new shared-CFG-backed control flow graph (#21921).
  P4: Add new shared-SSA-backed SSA adapter (#21923).

The Python dataflow library (semmle/python/dataflow/new/) now imports
the new CFG facade and SSA adapter. All CFG-typed predicates
(ControlFlowNode, CallNode, BasicBlock, NameNode, AttrNode, ...) are
qualified with the Cfg:: prefix; SSA references switch from
EssaVariable/EssaDefinition to SsaImpl::Definition/SourceVariable.

GuardNode is redesigned to use the new CFG's outcome-node model
(isAfterTrue / isAfterFalse) instead of the legacy ConditionBlock +
flipped indirection. Only BarrierGuard<...> is preserved as public
API.

Framework files (Bottle, FastApi, Django, Tornado, Pyramid, Stdlib,
...) are updated to take CFG nodes from the new facade.

A handful of dataflow consistency tweaks for the new CFG:
- Augmented-assignment targets are treated as both load and store.
- 'from X import *' produces uncertain SSA writes for unknown names.
- CFG nodes are canonicalised so dataflow does not see equivalent
  pre/post-order pairs as distinct nodes.

Two AST tweaks for the new CFG:
- AstNodeImpl: omit PEP 695 type-parameter names from
  FunctionDefExpr / ClassDefExpr children.
- ImportResolution: drop the legacy essa import.

Test churn (~175 files): reblessed library- and query-test .expected
files reflect slightly different CFG granularity, different toString
output, and a handful of true alert deltas in security queries.

Verification: all 367 lib + src + consistency-queries compile clean.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-21 11:32:03 +00:00
..
2024-01-22 09:11:35 +01:00
2022-08-24 16:36:15 +01:00

Python Taint Tracking Library

The taint tracking library can be broken down into three parts.

  1. Specification of sources, sinks and flows.
  2. The high level query API
  3. The implementation.

Specification

There are five parts to the specification of a taint tracking query. These are:

  1. Kinds

    The Python taint tracking library supports arbitrary kinds of taint. This is useful where you want to track something related to "taint", but that is in itself not dangerous. For example, we might want to track the flow of requests objects. Request objects are not in themselves tainted, but they do contain tainted data. For example, the length or timestamp of a request may not pose a risk, but the GET or POST string probably do. So, we would want to track request objects distinctly from the request data in the GET or POST field.

  2. Sources

    Sources of taint can be added by importing a predefined sub-type of TaintSource, or defining new ones.

  3. Sinks (or vulnerabilities)

    Sinks can be add by importing a predefined sub-type of TaintSink or defining new ones.

  4. Data flow extensions

    Additional dataflow edges; node->node, node->var, var->var or var->node can be added by importing predefined extensions or by adding new ones. Additional edges can be specified by overriding DataFlowExtension::DataFlowNode or DataFlowExtension::DataFlowVariable.

  5. Taint tracking extensions

    Taint tracking extensions, where a only a particular kind of taint flows, can be added by overriding any or all of following the methods on TaintKind:

    The two general purpose extensions:

    predicate additionalTaintStep(ControlFlowNode fromnode, ControlFlowNode tonode)

    predicate additionalTaintStepVar(EssaVariable fromvar, EssaVariable var)

    And the two special purpose extensions for tainted methods or attributes. These allow simple taint-tracking extensions, without worrying about the underlying flow graph.

    TaintKind getTaintFromAttribute(string name)

    TaintKind getTaintFromMethod(string name)

The high-level query API

The TaintedNode fully describes the taint flow graph. The full graph can be expressed as:

from TaintedNode n, TaintedNode s
where s = n.getASuccessor()
select n, s

The source -> sink relation can be expressed either using TaintedNode:

from TaintedNode src, TaintedNode sink
where src.isSource() and sink.isSink() and src.getASuccessor*() = sink
select src, sink

or, using the specification API:

from TaintSource src, TaintSink sink
where src.flowsToSink(sink)
select src, sink

The implementation

The data-flow graph used by the taint-tracking library is the one created by the points-to analysis, and consists of the course data-flow graph produced by semmle/python/data-flow/SsaDefinitions.qll enhanced with precise variable flows, call graph and type information. This graph is then enhanced with additional flows specified in part 1 above. Since the call graph and points-to information is context sensitive, the taint graph must also be context sensitive.

The taint graph is a simple directed graph where each node consists of a (CFG node, context, taint) triple although it could be thought of more naturally as a number of distinct graphs, one for each input taint-kind consisting of data flow nodes, (CFG node, context) pairs, labelled with their taint.

The TrackedValue used in the implementation is not the taint kind specified by the user, but describes both the kind of taint and how that taint relates to any object referred to by a data-flow graph node or edge. Currently, only two types of taint are supported: simple taint, where the object is actually tainted; and attribute taint where a named attribute of the referred object is tainted.

Support for tainted members (both specific members of tuples and the like, and generic members for mutable collections) are likely to be added in the near future and others form are possible. The types of taints are hard-wired with no user-visible extension method at the moment.