Python SDK (codepathfinder v2.1.0) for writing Code Pathfinder rules. This page covers language-agnostic primitives. Pick a language below for the decorator and matcher reference specific to that target.
QueryType classes for 70+ stdlib and framework types. flows() with type-inferred matching.
@go_rule · QueryType · .method() · .attr()Pattern-based matchers for any Python framework. No pre-defined QueryType classes; bring your own FQNs.
@python_rule · calls() · variable() · attribute()Instruction-level analysis for Dockerfiles. No dataflow; matches structural properties of build stages.
@dockerfile_rule · instruction() · missing()Service-level configuration analysis for docker-compose files.
@compose_rule · service_has() · service_missing()flows(..., propagates_through=None) defaults to an empty list, meaning no propagation is applied. Source and sink must already be connected by a primitive you pass explicitly. Use propagates_through=PropagationPresets.standard() unless you know otherwise, or set it globally with set_default_propagation(PropagationPresets.standard()). Confirmed in codepathfinder/config.py:15.The core dataflow analysis primitive. Traces taint from sources to sinks and reports paths that reach a sink without passing through a sanitizer. Works for Go and Python rules. Dockerfile / docker-compose rules do not use flows().
from codepathfinder import flows
from codepathfinder.presets import PropagationPresets
flows(
from_sources, # AnyMatcher | list[AnyMatcher], required
to_sinks, # AnyMatcher | list[AnyMatcher], required
sanitized_by=None, # optional
propagates_through=None, # defaults to [] (see callout above)
scope=None, # "local" | "global" (default: global)
)from_sourcesrequiredAnyMatcher union (dataflow.py:17) covers CallMatcher (calls()), AttributeMatcher (attribute()), MethodMatcher (QueryType.method()), and AttributeMethodMatcher (QueryType.attr()). Logic combinators (And, Or, Not) are also accepted.to_sinksrequiredsanitized_bypropagates_through[], meaning no propagation). Pass PropagationPresets.standard() for typical taint tracking.scope"local" runs intra-procedurally (same function)."global" runs inter-procedurally (across functions). None uses the global default, which is "global". Invalid values raise ValueError.Determines whether the analyzer traces taint across function boundaries.
"local"intra-proceduralSource and sink must be in the same function. Faster, no false positives from cross-function paths, but misses real flows that go through helpers.
"global"defaultTraces taint through function calls, returns, and across files using the project-wide call graph. Recommended for real-world rules.
Pre-bundled lists of propagation primitives. Import from codepathfinder.presets. All presets are static methods that return list[PropagationPrimitive].
from codepathfinder.presets import PropagationPresets
PropagationPresets.minimal() # [assignment, function_args], ~40% coverage
PropagationPresets.standard() # adds function_returns, string_concat, string_format (recommended)
PropagationPresets.comprehensive() # same primitives as standard() today
PropagationPresets.exhaustive() # same primitives as comprehensive() todaycomprehensive() and exhaustive() return the same list as standard(). Defined in codepathfinder/presets.py:82-136.Individual propagation primitives for fine-grained control. Import the propagates namespace directly.
from codepathfinder import propagates
propagates.assignment() # x = tainted; chained assignment; tuple unpacking
propagates.function_args() # func(tainted); *args, **kwargs
propagates.function_returns() # return tainted; conditional returns
propagates.string_concat() # "pre" + tainted + "post"
propagates.string_format() # f"{tainted}"; "{}".format(tainted); "%s" % taintedFive propagation primitives are currently implemented. The PropagationPresets.standard() bundle includes all of them.
Constraint helpers used with .where(), .arg(), or inside match_position / match_name dicts on calls().
from codepathfinder import lt, gt, lte, gte, regex, missing
# Numeric constraints
RSAModule.method("generate_private_key").where("key_size", lt(2048))
FlaskApp.method("run").where("port", gte(1024))
# Regex on string values
calls("connect").where(0, regex(r"^(?!localhost).*"))
# missing(): keyword argument is absent from the call (uses default value)
ResponseModule.method("set_cookie").where("secure", missing())lt(value)gt(value)lte(value)gte(value)regex(pattern)missing()Boolean combinators for matchers. Works on any matcher type (calls, variable, QueryType method, etc.).
from codepathfinder import And, Or, Not
Or(calls("eval"), calls("exec")) # any of
And(calls("open"), variable("user_*")) # both
Not(calls("test_*")) # exclude test functions
# Nested: mix Go QueryType with calls()
Or(GoOSExec.method("Command"), calls("os/exec.Command"))And and Or require ≥2 matchers; Not takes exactly one. Container rules use all_of / any_of / none_of instead (see Dockerfile page).
Override the global defaults for propagation and scope. Useful when every rule in a ruleset needs the same setup.
from codepathfinder import set_default_propagation, set_default_scope, PropagationPresets
# Apply PropagationPresets.standard() to every flows() call that omits propagates_through
set_default_propagation(PropagationPresets.standard())
# Switch the global default to local scope
set_default_scope("local")Everything available via from codepathfinder import ...:
Language-specific decorators and pre-defined types live in submodules: codepathfinder.go_decorators, codepathfinder.python_decorators, codepathfinder.container_decorators, codepathfinder.go_rule, codepathfinder.container_matchers.