Matchers

Matchers identify specific patterns in your code. Learn how to use calls() andvariable() to find function calls and variable references.

calls() Matcher

The calls() matcher finds function and method calls in your code. It's the most commonly used matcher for security rules.

Match a Single Function

Find all calls to a specific function:

from codepathfinder import rule, calls

@rule(id="detect-eval", severity="critical")
def detect_eval():
    """Find dangerous eval() calls"""
    return calls("eval")

This matches:

eval("some code")  # Matched!
exec("other code")  # Not matched

Match Multiple Functions

Pass multiple function names to match any of them:

@rule(id="code-exec", severity="critical")
def detect_code_execution():
    """Find code execution functions"""
    return calls("eval", "exec", "compile")

This matches:

eval("x = 1")       # Matched!
exec("print('hi')")  # Matched!
compile("code", "", "exec")  # Matched!

Match Methods

Use dot notation to match methods on specific classes:

@rule(id="subprocess-shell", severity="high")
def detect_subprocess_shell():
    """Find subprocess.Popen with shell=True"""
    return calls("subprocess.Popen", match_name={"shell": True})

This matches:

subprocess.Popen("ls", shell=True)  # Matched!
subprocess.Popen("ls", shell=False) # Not matched

Wildcard Patterns

Use * wildcards to match multiple variations of function names. This is incredibly powerful for catching entire families of functions.

Module Wildcards

Match any method on a module:

@rule(id="requests-calls", severity="info")
def detect_http_requests():
    """Find all HTTP requests"""
    return calls("requests.*")

This matches:

requests.get("https://example.com")    # Matched!
requests.post("https://api.com/data")   # Matched!
requests.put("https://api.com/update")  # Matched!
requests.delete("https://api.com/del")  # Matched!

Any Module Pattern

Match a method on any class or module:

@rule(id="sql-execute", severity="critical")
def detect_sql_execution():
    """Find SQL execute calls on any database connection"""
    return calls("*.execute", "*.executemany")

This matches:

cursor.execute("SELECT * FROM users")      # Matched!
connection.execute("INSERT INTO logs")     # Matched!
db.execute("UPDATE settings")              # Matched!
session.executemany("DELETE FROM old")     # Matched!

Complete Wildcards

Match any function (use sparingly, can be slow):

@rule(id="any-password", severity="medium")
def detect_password_params():
    """Find any function call with a password parameter"""
    return calls("*", match_name={"password": "*"})

Performance Tip: Complete wildcards (*) check every function call in your codebase. Use them only when combined with argument matching or other constraints.

variable() Matcher

The variable() matcher finds variable references in your code. Useful for detecting usage of specific variable names.

Match Variable Names

from codepathfinder import rule, variable

@rule(id="debug-mode", severity="medium")
def detect_debug_variables():
    """Find DEBUG variable usage"""
    return variable("DEBUG")

This matches:

DEBUG = True          # Matched!
if DEBUG:             # Matched!
    print(DEBUG)      # Matched!

Variable Wildcards

Use wildcards to match variable name patterns:

@rule(id="sensitive-vars", severity="high")
def detect_sensitive_variables():
    """Find variables with sensitive names"""
    return variable("*PASSWORD*", "*SECRET*", "*API_KEY*")

This matches:

DB_PASSWORD = "secret"        # Matched!
SECRET_KEY = "xyz"            # Matched!
API_KEY_PRODUCTION = "abc"    # Matched!

Combining Matchers

Use And, Or, and Not to create complex patterns.

Or - Match Any Pattern

from codepathfinder import rule, calls, Or

@rule(id="deserialization", severity="critical")
def detect_insecure_deserialization():
    """Find insecure deserialization"""
    return Or(
        calls("pickle.loads"),
        calls("pickle.load"),
        calls("yaml.unsafe_load"),
        calls("yaml.load")
    )

And - All Must Match

from codepathfinder import rule, calls, variable, And

@rule(id="eval-with-input", severity="critical")
def detect_eval_with_user_input():
    """Find eval() called with user input variable"""
    return And(
        calls("eval"),
        variable("user_input")
    )

Not - Exclude Patterns

from codepathfinder import rule, calls, Not

@rule(id="production-debug", severity="high")
def detect_debug_outside_tests():
    """Find debug calls outside test files"""
    return And(
        calls("print", "pprint"),
        Not(calls("test_*"))
    )

Real-World Example:

@rule(id="comprehensive-sqli", severity="critical")
def detect_sql_injection_patterns():
    """Comprehensive SQL injection detection"""
    return Or(
        # Direct SQL execution
        calls("*.execute", "*.executemany"),

        # ORM raw queries
        calls("*.raw"),

        # String formatting into SQL
        And(
            calls("*.format"),
            variable("*SQL*", "*QUERY*")
        )
    )