Signals Reference

pydepgate emits 30 signals across five analyzer namespaces. Each signal represents a specific detection pattern.

How severity is assigned

The rules engine evaluates each signal against the active rule set. When one or more rules match, the most-specific rule from the highest-priority source wins (user > system > default; within a source, more match conditions wins; within a tie, load order wins). The winning rule’s SET_SEVERITY effect determines the finding’s severity.

When no rule matches, the rules engine falls back to a mechanical mapping from the analyzer’s Confidence value to a Severity value. The mapping is defined in confidence_to_severity_v01() in src/pydepgate/engines/base.py:

Analyzer confidence Resulting severity
DEFINITE (90) HIGH
HIGH (70) MEDIUM
MEDIUM (50) LOW
LOW (30) INFO
AMBIGUOUS (10) INFO

A signal with no matching rule still produces a finding; it just does so at the conservative confidence-based severity.

The tables in each entry below list explicit default rules first, then a “Fallback (no rule)” row where applicable, showing the severity the signal would carry from the mechanical mapping based on the analyzer’s confidence for that signal.

Use pydepgate explain <SIGNAL_ID> at the command line to see all rules (default and user) that apply to a signal.


ENC: Encoding Abuse

Emitted by the encoding_abuse analyzer.

ENC001

Decode-then-execute pattern. Encoded content (base64, hex, compressed bytes) is decoded and immediately passed to exec, eval, compile, or __import__.

The analyzer emits ENC001 at DEFINITE confidence when the inner argument is a literal-looking payload string, and at HIGH confidence otherwise.

This is the most common pattern in Python supply-chain malware. The LiteLLM 1.82.8 attack used exactly this pattern in a .pth file.

Common evasions: aliasing the exec primitive (e = exec; e(b64decode(...))), chaining multiple decoders (zlib + base64), splitting the payload across multiple variables.

File kind Severity
pth CRITICAL
setup_py CRITICAL
sitecustomize CRITICAL
init_py HIGH
Fallback (no rule, e.g. usercustomize, library_py) HIGH (literal) or MEDIUM

ENC002

Deeply-nested encoded payload. A string literal that required 2 or more transformations to decode (or exhausted the --peek-depth limit with more layers still possible). Emitted by the payload-peek enricher; requires --peek.

The enricher emits ENC002 at AMBIGUOUS confidence at depth 2, MEDIUM confidence at depth 3, and HIGH confidence on depth exhaustion.

Condition Severity
pth CRITICAL
sitecustomize CRITICAL
usercustomize CRITICAL
setup_py with unwrap_status == "exhausted_depth" CRITICAL
setup_py (baseline) HIGH
init_py with final_kind == "python_source" CRITICAL
init_py with unwrap_status == "exhausted_depth" HIGH
init_py (baseline) MEDIUM
Any file kind with unwrap_status == "exhausted_depth" HIGH
Fallback (no rule, e.g. library_py with non-exhausted chain) INFO to MEDIUM (depends on depth)

The setup_py exhausted-depth rule has higher specificity than the setup_py baseline rule and wins when its predicate matches. Same for the init_py python-source and exhausted-depth variants.


DYN: Dynamic Execution

Emitted by the dynamic_execution analyzer.

DYN001

exec/eval/compile at module scope with a literal argument. The argument is a statically-visible string constant.

Analyzer emits at MEDIUM confidence. No default rule exists, so DYN001 findings always come through the mechanical-mapping fallback.

Condition Severity
Fallback (no rule, any file kind) LOW

DYN002

exec/eval/compile at module scope with a non-literal argument. The argument is computed at runtime; the executed code is not visible in the source.

Analyzer emits at HIGH confidence.

File kind Severity
pth CRITICAL
setup_py HIGH
Fallback (no rule, other file kinds) MEDIUM

DYN003

exec/eval/compile inside a function or class body with a non-literal argument. Lower priority than module-scope because function bodies often have legitimate reasons to use exec.

Analyzer emits at MEDIUM confidence. No default rule.

Condition Severity
Fallback (no rule, any file kind) LOW

DYN004

__import__ or importlib.import_module with a non-literal module name. Computed module names defeat static dependency analysis.

Analyzer emits at HIGH confidence. No default rule.

Condition Severity
Fallback (no rule, any file kind) MEDIUM

DYN005

Reaching into builtins via getattr, globals(), locals(), or vars() to access an exec primitive by string lookup. For example: getattr(__builtins__, 'eval') or globals()['exec'].

There is no legitimate reason to access exec, eval, or compile via string lookup. This pattern exists specifically to evade scanners that match on the names of dangerous builtins.

File kind Severity
All file kinds (anywhere rule) HIGH

DYN006

Compile-then-exec pattern. A compile() result is stored in a variable and later passed to exec or eval somewhere else in the file.

File kind Severity
All file kinds (anywhere rule) HIGH

DYN006_PRECURSOR

compile() called with mode='exec'. Creates a code object intended for execution even without a following exec.

Analyzer emits at MEDIUM confidence. No default rule.

Condition Severity
Fallback (no rule, any file kind) LOW

DYN007

Aliased exec shape. A call to an unresolvable name whose first argument is itself a decode call, for example e(base64.b64decode(...)) where e cannot be resolved.

Analyzer emits at HIGH confidence.

File kind Severity
setup_py HIGH
Fallback (no rule, other file kinds) MEDIUM

STR: String Obfuscation

Emitted by the string_ops analyzer. Uses a safe partial evaluator to statically compute what obfuscated string expressions would produce.

STR001

Standalone obfuscated expression that resolves to a sensitive name. Not seen passed to a dangerous function at this point, but the obfuscation is worth noting.

Analyzer emits at MEDIUM confidence. No default rule.

Condition Severity
Fallback (no rule, any file kind) LOW

STR002

Obfuscated expression resolves to a sensitive name and is passed directly to a dangerous function.

Analyzer emits at DEFINITE confidence when the obfuscation score is 2 or more, and at HIGH confidence at score 1.

Common evasions: chr() concatenation, string reversal ('lave'[::-1]), bytes from list (bytes([101, 118, 97, 108]).decode()).

File kind Severity
setup_py CRITICAL
All other file kinds (anywhere rule) HIGH

STR003

Variable assigned an obfuscated sensitive name is later used as the argument to a dangerous function. Two-step obfuscation that defeats single-expression analyzers.

File kind Severity
All file kinds (anywhere rule) HIGH

STR004

Heavily obfuscated expression that pydepgate could not fully resolve, but that used many obfuscation operations. The obfuscation effort itself is the signal.

Analyzer emits at HIGH confidence when a func_name is known, otherwise at MEDIUM confidence.

File kind Severity
setup_py HIGH
Fallback (no rule, other file kinds, with func_name) MEDIUM
Fallback (no rule, other file kinds, without func_name) LOW

STDLIB: Suspicious Standard Library

Emitted by the suspicious_stdlib analyzer. All three STDLIB signals fire at HIGH confidence.

Note: aliased imports are a documented gap. from subprocess import Popen as P followed by P(['ls']) does not currently fire because the qualified name resolves to P, not subprocess.Popen.

STDLIB001

Call to a stdlib function that spawns a subprocess or executes a shell command. Covered functions include the full subprocess.*, os.system, os.popen, os.spawn*, os.exec*, os.fork, os.forkpty, pty.spawn, pty.fork, and platform.popen families.

File kind Severity
pth CRITICAL
setup_py CRITICAL
sitecustomize CRITICAL
init_py (module scope only) HIGH
Fallback (no rule, e.g. init_py function scope, usercustomize, library_py) MEDIUM

STDLIB002

Call to a stdlib function that initiates network communication. Covered functions include urllib.request.urlopen, urllib.request.urlretrieve, urllib.request.Request, socket.socket, socket.create_connection, http.client.HTTPConnection, http.client.HTTPSConnection, ftplib.FTP, ftplib.FTP_TLS, smtplib.SMTP, smtplib.SMTP_SSL, imaplib.IMAP4, imaplib.IMAP4_SSL, and others.

File kind Severity
pth CRITICAL
setup_py HIGH
init_py (module scope only) HIGH
Fallback (no rule, e.g. init_py function scope, sitecustomize, usercustomize, library_py) MEDIUM

STDLIB003

Call to a stdlib function that loads native code via ctypes. Covered functions include ctypes.CDLL, ctypes.WinDLL, ctypes.OleDLL, ctypes.PyDLL, and all LoadLibrary variants.

Native code loaded via ctypes runs outside Python’s execution model. Legitimate packages that wrap native libraries do so via compiled extension modules, not runtime ctypes loads.

File kind Severity
pth CRITICAL
setup_py CRITICAL
All other file kinds (anywhere rule) HIGH

DENS: Code Density

Emitted by the code_density analyzer. Covers statistical and structural fingerprints of intentionally obfuscated code. This is the only analyzer that runs on ordinary library .py files in --deep mode.

None of these signals are individually conclusive. Context, particularly file kind, is what makes them meaningful. Every DENS signal has an *_anywhere default rule, so the mechanical-mapping fallback never applies to DENS signals.

DENS001

Single-line token compression. A physical line contains an anomalously high number of tokens, indicating minification or deliberate packing. Fires at MEDIUM at 50+ tokens, HIGH at 100+ tokens.

File kind Severity
pth HIGH
setup_py HIGH
sitecustomize HIGH
library_py (deep mode) LOW
All other file kinds (anywhere rule) LOW

DENS002

Semicolon statement chaining. Multiple statements joined by semicolons on one physical line. Fires at MEDIUM at 2+ semicolons, HIGH at 4+ semicolons.

File kind Severity
pth HIGH
setup_py HIGH
library_py (deep mode) LOW
All other file kinds (anywhere rule) LOW

DENS010

High-entropy string literal. A string constant whose Shannon entropy and length together suggest encoded content. Calibrated to catch base64-encoded Python source at approximately 5.2-5.4 bits/char (the entropy of the LiteLLM 1.82.8 attack payload).

File kind / condition Severity
pth CRITICAL
sitecustomize CRITICAL
Any file, length >= 10240 bytes CRITICAL
setup_py HIGH
init_py MEDIUM
library_py (deep mode) MEDIUM
All other file kinds (anywhere rule) LOW

DENS011

Base64-alphabet string constant. A long string whose character set is restricted to the base64 alphabet (A-Za-z0-9+/=), indicating a likely encoded payload even without an accompanying decode call. Complements DENS010 by firing on alphabet membership without requiring high entropy.

File kind / condition Severity
pth CRITICAL
Any file, length >= 10240 bytes CRITICAL
setup_py HIGH
Length >= 1024 bytes HIGH
library_py (deep mode) MEDIUM
All other file kinds (anywhere rule) LOW

DENS020

Low-vowel-ratio identifier. An identifier whose consonant-heavy composition suggests machine-generated or deliberately mangled naming.

Produces false positives on legitimate generated code and scientific Python abbreviations.

File kind Severity
library_py (deep mode) INFO
All other file kinds (anywhere rule) LOW

DENS021

Confusable single-character identifier. Use of l, O, or I as a variable name. Universally INFO; a PEP 8 issue by itself.

File kind Severity
All file kinds (anywhere rule) INFO

DENS030

Invisible Unicode character. A zero-width space, zero-width joiner, byte-order mark, right-to-left override, or other invisible Unicode codepoint found anywhere in the source. This is the Trojan Source attack class (CVE-2021-42574).

File kind Severity
pth CRITICAL
setup_py CRITICAL
sitecustomize CRITICAL
library_py (deep mode) HIGH
All other file kinds (anywhere rule) HIGH

DENS031

Unicode homoglyph in identifier. A non-ASCII character visually identical to an ASCII letter (Cyrillic or Greek lookalikes) used in an identifier. Enables steganographic evasion of string-match scanners.

File kind Severity
pth CRITICAL
setup_py CRITICAL
library_py (deep mode) HIGH
All other file kinds (anywhere rule) HIGH

DENS040

Disproportionate AST depth. The AST is unusually deep relative to the file’s line count, indicating expression compression.

Produces false positives on Cython output and parser-generator tables.

File kind Severity
pth HIGH
setup_py HIGH
library_py (deep mode) INFO
All other file kinds (anywhere rule) LOW

DENS041

Deeply nested lambdas or comprehensions. Lambdas or comprehensions nested beyond a configurable depth threshold.

File kind Severity
pth HIGH
setup_py HIGH
library_py (deep mode) INFO
All other file kinds (anywhere rule) LOW

DENS042

Large byte-range integer array. A list or tuple whose elements are predominantly integers in the range [0, 255], suggesting shellcode or payload staging.

Cryptographic constants and lookup tables are the main false-positive class.

File kind Severity
pth CRITICAL
setup_py HIGH
library_py (deep mode) LOW
All other file kinds (anywhere rule) LOW

DENS050

High-entropy docstring. A string in docstring position with high Shannon entropy and length suggesting encoded content disguised as documentation. The complete attack pattern pairs DENS050 (smuggling the payload) with DENS051 (executing it).

File kind / condition Severity
pth CRITICAL
setup_py CRITICAL
Any file, length >= 10240 bytes CRITICAL
Length >= 1024 bytes HIGH
library_py (deep mode) HIGH
All other file kinds (anywhere rule) MEDIUM

DENS051

Dynamic __doc__ reference passed to a callable. __doc__ is read and passed as an argument to a function call. This is the execution half of the docstring-payload pattern.

Some introspection tools legitimately read __doc__; those cases can be suppressed via a user rule.

File kind Severity
pth CRITICAL
setup_py CRITICAL
library_py (deep mode) HIGH
All other file kinds (anywhere rule) HIGH

This site uses Just the Docs, a documentation theme for Jekyll.