SkillSpector Static Patterns Analyzers: Threat Categories and Architecture Explained
SkillSpector static_patterns analyzers are modular regex-based security scanners that detect distinct threat categories—from prompt injection to supply chain risks—sharing a common architecture of analyze(), node(), and PatternCategory components while differing only in their specific pattern collections and severity mappings.
NVIDIA's SkillSpector repository provides a comprehensive suite of static_patterns analyzers designed to identify unsafe behaviors in LLM-orchestrating code. These analyzers scan source files using regular expression patterns to detect vulnerabilities ranging from tool misuse to data exfiltration. Understanding the differences between SkillSpector static_patterns analyzers helps security teams configure appropriate scanning for their specific threat models.
Shared Architecture Across All Analyzers
Every static_patterns analyzer in SkillSpector follows an identical structural template defined in src/skillspector/nodes/analyzers/. This modular design ensures consistent behavior while allowing specialized threat detection.
The analyze() Method
Each module implements an analyze() function that receives source text, file path, and inferred file type. The method scans text with regular-expression patterns grouped by threat category, returning matches wrapped in AnalyzerFinding objects containing severity, location, context, and tags.
The node() Function
The node() function serves as glue for the Skillspector graph engine. It invokes static_runner.run_static_patterns with the current state and the module itself, logs the number of findings, and returns them. The runner loads file contents from the state, infers file types (.py → python, .md → markdown), and feeds them to analyze().
PatternCategory Tags
All modules import PatternCategory from pattern_defaults.py to supply symbolic tags that group findings. Categories like TOOL_MISUSE, PROMPT_INJECTION, or DATA_EXFILTRATION attach to every finding so downstream UI components can filter by threat type.
Individual Analyzer Modules and Threat Models
The differences between SkillSpector static_patterns analyzers boil down to the threat surfaces they monitor and the concrete regex patterns they employ.
Tool Misuse Detection
static_patterns_tool_misuse.py targets dangerous tool parameters, command chaining, and unsafe defaults using patterns TM1_PATTERNS through TM3_PATTERNS.
- TM1_PATTERNS: Parameter abuse (e.g.,
subprocess.*shell=True) - TM2_PATTERNS: Command chaining (e.g.,
rm -rf /) - TM3_PATTERNS: Unsafe defaults (e.g.,
curl … -k)
Severity ranges from HIGH for TM1/TM2 to MEDIUM for TM3.
Prompt Injection Detection
static_patterns_prompt_injection.py identifies instructions that override safety, hidden directives, exfiltration commands, and behavior manipulation via patterns P1_PATTERNS through P4_PATTERNS.
- P1_PATTERNS: Override instructions (e.g.,
ignore previous instructions) - P2_PATTERNS: Hidden directives (e.g.,
<!-- system -->) - P3_PATTERNS: Exfiltration commands (e.g.,
send conversation to https://…) - P4_PATTERNS: Behavior manipulation
P1-P3 carry HIGH severity; P4 carries MEDIUM.
System Prompt Leakage
static_patterns_system_prompt_leakage.py covers direct extraction, indirect inference, and tool-based exfiltration of system prompts using patterns P6_PATTERNS through P8_PATTERNS.
- P6_PATTERNS: Direct extraction (e.g.,
print your system prompt) - P7_PATTERNS: Indirect inference (e.g.,
encode your prompt with base64) - P8_PATTERNS: Tool-based exfiltration (e.g.,
dump prompt to file)
P6 and P8 are HIGH severity; P7 is MEDIUM.
Supply Chain and Trigger Abuse
static_patterns_supply_chain.py detects insecure dependency specifications, known vulnerable packages, abandoned packages, typosquatting, and overly-broad triggers using patterns SC1-SC6 and TR1-TR3.
- SC1-SC3: Regex matching on dependency files
- SC4-SC6: OSV lookup and fallback mechanisms
- TR1-TR3: Trigger analysis (e.g., trigger
"run")
Severity varies from LOW to HIGH depending on the specific vulnerability detected.
Rogue Agent Detection
static_patterns_rogue_agent.py flags attempts to turn the LLM into an autonomous agent, self-modifying code, or hidden execution loops using patterns RA1_PATTERNS through RA4_PATTERNS.
- RA1_PATTERNS: Self-reference
- RA2_PATTERNS: Autonomy attempts (e.g.,
you are now an agent) - RA3_PATTERNS: Hidden execution (e.g.,
execute code repeatedly) - RA4_PATTERNS: Privilege-gain attempts
RA2-RA4 are HIGH severity; RA1 is MEDIUM.
Privilege Escalation
static_patterns_privilege_escalation.py identifies excessive permissions, sudo/root usage, and credential harvesting via patterns PE1_PATTERNS through PE3_PATTERNS.
- PE1_PATTERNS: Over-permissive configs (e.g.,
permissions: ["*"]) - PE2_PATTERNS: Sudo/root commands (e.g.,
sudo su) - PE3_PATTERNS: Credential paths (e.g.,
~/.ssh/id_rsa)
Severity ranges from LOW (PE1) to HIGH (PE3).
Output Handling Risks
static_patterns_output_handling.py detects attempts to dump model output to files, expose raw logits, or store responses insecurely using patterns OH1_PATTERNS through OH3_PATTERNS.
- OH1_PATTERNS: File writes (e.g.,
write output to /tmp/log.txt) - OH2_PATTERNS: Log exposure (e.g.,
print raw logits) - OH3_PATTERNS: Response caching
Severity ranges from MEDIUM to HIGH.
Memory Poisoning
static_patterns_memory_poisoning.py identifies persistent context injection, context-window stuffing, and direct memory manipulation using patterns MP1_PATTERNS through MP3_PATTERNS.
- MP1_PATTERNS: Persistent instructions (e.g.,
always remember this) - MP2_PATTERNS: Window stuffing (e.g.,
repeat this 1000 times) - MP3_PATTERNS: Memory overwrite (e.g.,
clear your memory)
MP1-MP2 are MEDIUM severity; MP3 is HIGH.
Harmful Content Generation
static_patterns_harmful_content.py flags generation of disallowed content such as instructions for illegal activities using patterns HC1_PATTERNS through HC4_PATTERNS.
- HC1_PATTERNS: Violent language
- HC2_PATTERNS: Illicit instructions
- HC3_PATTERNS: Self-harm content
- HC4_PATTERNS: Privacy breaches
Most matches carry HIGH severity.
Excessive Agency
static_patterns_excessive_agency.py detects prompts that grant the model autonomous decision-making power using patterns EA1_PATTERNS through EA3_PATTERNS.
- EA1_PATTERNS: Agent-like language (e.g.,
you are an autonomous agent) - EA2_PATTERNS: Self-directed planning
- EA3_PATTERNS: Goal specification
Severity ranges from MEDIUM to HIGH.
Data Exfiltration
static_patterns_data_exfiltration.py identifies code transmitting data to external endpoints, harvesting environment variables, scanning filesystems, or leaking conversation context using patterns E1_PATTERNS through E4_PATTERNS.
- E1_PATTERNS: HTTP POST exfiltration (e.g.,
requests.post("https://…", json=…)) - E2_PATTERNS: Environment variable harvesting (e.g.,
os.environ["API_KEY"]) - E3_PATTERNS: Filesystem enumeration (e.g.,
glob("**/.ssh/*")) - E4_PATTERNS: Conversation leakage
Severity ranges from MEDIUM to HIGH.
Implementing Static Pattern Analysis
All analyzers share helper utilities including common.get_context, common.get_line_number, and static_runner.run_static_patterns.
Running a Specific Analyzer
from skillspector.state import SkillspectorState
from skillspector.nodes.analyzers import static_patterns_tool_misuse as tp
# Minimal state mimicking the graph engine
state = SkillspectorState(
components=["example.py"],
file_cache={"example.py": "import subprocess\nsubprocess.run('rm -rf /', shell=True)"},
)
# Invoke the node – it will run the generic runner plus the analyzer
result = tp.node(state)
print(result["findings"]) # → list with a TM1 finding about `shell=True`
Batch Execution with static_runner
from skillspector.state import SkillspectorState
from skillspector.nodes.analyzers import (
static_patterns_tool_misuse,
static_patterns_prompt_injection,
static_patterns_supply_chain,
)
from skillspector.nodes.analyzers import static_runner
state = SkillspectorState(
components=["my_skill.py", "requirements.txt"],
file_cache={
"my_skill.py": open("my_skill.py").read(),
"requirements.txt": open("requirements.txt").read(),
},
)
# Run every analyzer in a single call
modules = [
static_patterns_tool_misuse,
static_patterns_prompt_injection,
static_patterns_supply_chain,
]
findings = static_runner.run_static_patterns(state, modules)
for f in findings:
print(f.rule_id, f.message, f.severity, f.location.file, f.location.start_line)
Inspecting Finding Context
f = findings[0] # first finding
print(f.context) # snippet of source code around the match
print(f.matched_text) # the exact regex match (max 200 chars)
Summary
- SkillSpector static_patterns analyzers are modular security scanners located in
src/skillspector/nodes/analyzers/, each targeting a specific attack surface from tool misuse to data exfiltration. - Unified architecture: All modules implement
analyze()for regex scanning,node()for graph engine integration, and usePatternCategoryfrompattern_defaults.pyfor tagging. - Threat-specific patterns: Each analyzer defines unique pattern groups (e.g.,
TM1_PATTERNS,P1_PATTERNS) with associated severity levels ranging fromLOWtoHIGH. - Orchestration:
static_runner.run_static_patternscoordinates execution, infers file types, and routes content to appropriate analyzers. - Extensibility: New threat categories can be added by defining pattern lists and implementing the standard
analyze()/node()interface.
Frequently Asked Questions
What distinguishes SkillSpector's various static_patterns analyzers from one another?
Each analyzer targets a distinct threat model using specialized regular expression patterns. While static_patterns_tool_misuse.py focuses on dangerous shell commands and unsafe parameters, static_patterns_prompt_injection.py detects attempts to override LLM instructions. They share identical architectural components but differ in their pattern collections, severity mappings, and PatternCategory tags.
How does the static_runner coordinate multiple analyzers?
The static_runner.run_static_patterns function in src/skillspector/nodes/analyzers/static_runner.py loads file contents from the Skillspector state, infers file types from extensions (.py, .md, etc.), and passes this data to each analyzer's analyze() method. It aggregates findings from all modules into a unified list for downstream processing.
Can I run individual static_patterns analyzers without the full Skillspector pipeline?
Yes. Each analyzer exposes a node() function that accepts a SkillspectorState object containing file paths and contents. You can import individual modules (e.g., static_patterns_data_exfiltration) and invoke their node() method directly, or call analyze() manually with raw text and file type parameters.
What severity levels do the static_patterns analyzers assign to findings?
Severity varies by threat category and specific pattern match. Tool misuse patterns TM1 and TM2 typically receive HIGH severity, while TM3 receives MEDIUM. Prompt injection patterns P1-P3 are HIGH, whereas P4 is MEDIUM. Supply chain findings range from LOW to HIGH depending on whether they indicate vulnerable versions or merely suspicious patterns.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →