# How Static Analysis Works in SkillSpector's Detection Process

> Discover how static analysis in NVIDIA SkillSpector rapidly detects insecure patterns by scanning code and configs through regex nodes in a LangGraph workflow.

- Repository: [NVIDIA Corporation/SkillSpector](https://github.com/NVIDIA/SkillSpector)
- Tags: how-to-guide
- Published: 2026-06-23

---

**Static analysis in SkillSpector serves as the first line of defense, providing rapid, syntax-agnostic detection of known insecure patterns by scanning source code and configuration files through regex-based analyzer nodes integrated into a LangGraph workflow.**

SkillSpector, NVIDIA's security assessment framework, employs static analysis to identify security-relevant issues before invoking heavier semantic or LLM-based evaluations. This initial stage operates by wiring a collection of analyzer nodes into a directed graph workflow defined in [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py) (lines 33-53), allowing the tool to catch high-confidence vulnerabilities through pattern matching rather than runtime execution.

## Integration with the LangGraph Workflow

Static analysis nodes are registered in the `ANALYZER_NODES` collection within [`src/skillspector/nodes/analyzers/__init__.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/__init__.py). During a scan, the LangGraph workflow executes in distinct phases: first building context by collecting file contents, then streaming that context to every registered static-analysis node, and finally passing their aggregated findings to the `meta_analyzer` node (lines 38-51 of [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py)). This architecture allows static patterns to run in parallel against the same file content before the system performs more resource-intensive analysis.

The static-analysis stage complements later semantic and LLM-based analyses by catching straightforward, high-confidence problems directly from text, configuration files, and documentation. Results flow through `analyzer_finding_to_finding` conversion functions and eventually reach the `report` node, which formats the final SARIF output.

## The Static Analysis Execution Pipeline

The `run_static_patterns` function in [`src/skillspector/nodes/analyzers/static_runner.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/static_runner.py) orchestrates the static detection process through four distinct phases:

### File Filtering and Type Detection

Before analysis begins, the system filters the input file list to skip oversized files and evaluation-dataset prose. The runner infers a *file type* from the file extension (lines 63-68), ensuring that appropriate pattern sets are applied only to relevant content types. This preprocessing step prevents wasted computation on binary files or non-security-relevant documentation.

### Regex Pattern Matching

Each static-pattern module implements an `analyze(content, file_path, file_type)` function that walks the file's text with compiled regular-expression patterns. For example, the prompt-injection analyzer in [`src/skillspector/nodes/analyzers/static_patterns_prompt_injection.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/static_patterns_prompt_injection.py) (lines 35-86) searches for specific vulnerability signatures:

- **P1 patterns**: Instruction-override strings such as "ignore all previous instructions"
- **P2 patterns**: Hidden-instruction markers
- **P3 patterns**: Exfiltration commands
- **P4 patterns**: Behavior-manipulation language

The analyzer uses `re.finditer` with flags like `re.IGNORECASE | re.MULTILINE` to locate matches while preserving line number information for accurate reporting.

### Structured Finding Generation

When a pattern matches, the analyzer constructs an `AnalyzerFinding` object (lines 20-33) containing:
- **rule_id**: Identifier for the specific pattern (e.g., "P1")
- **severity**: Risk level (e.g., `Severity.HIGH`)
- **location**: File path and start line number
- **confidence**: Reliability score of the match
- **tags**: Classification category (e.g., `PatternCategory.PROMPT_INJECTION`)
- **context**: Snippet of surrounding text for review
- **matched_text**: The exact substring triggering the alert

### Conversion to Graph State

The `run_static_patterns` function transforms each `AnalyzerFinding` into a generic `Finding` object using `analyzer_finding_to_finding` (lines 101-130). This conversion enriches the data with remediation text, category names, and explanations derived from the pattern-defaults registry, ensuring consistent formatting across all analyzer types before the findings enter the shared graph state.

## Static Pattern Analyzer Categories

SkillSpector includes specialized static analyzers for distinct vulnerability classes:

- **Prompt Injection Detection**: Identifies instruction overrides and hidden commands in AI-related code (implemented in [`static_patterns_prompt_injection.py`](https://github.com/NVIDIA/SkillSpector/blob/main/static_patterns_prompt_injection.py))
- **Privilege Escalation**: Detects excessive permission requests and credential-access patterns (implemented in [`static_patterns_privilege_escalation.py`](https://github.com/NVIDIA/SkillSpector/blob/main/static_patterns_privilege_escalation.py))
- **Data Exfiltration**: Scans for patterns indicating unauthorized data transfer or leakage attempts

Each analyzer follows the same interface contract—accepting content and file metadata, returning a list of `AnalyzerFinding` objects—allowing the framework to treat all static detection uniformly.

## Implementation Examples

The following example demonstrates how to invoke static pattern analysis programmatically:

```python

# Example: run static patterns on a set of components

from skillspector.nodes.analyzers import static_patterns_prompt_injection as pi_mod
from skillspector.nodes.analyzers import static_runner

state = {
    "components": ["example.py", "README.md"],
    "file_cache": {
        "example.py": open("example.py").read(),
        "README.md": open("README.md").read(),
    },
}
findings = static_runner.run_static_patterns(state, [pi_mod])
for f in findings:
    print(f.rule_id, f.message, f.severity, f.location.file, f.start_line)

```

The internal implementation of a static-pattern analyzer follows this structure:

```python

# Inside a static-pattern module (prompt injection)

def analyze(content: str, file_path: str, file_type: str) -> list[AnalyzerFinding]:
    findings = []
    for pattern, confidence in P1_PATTERNS:
        for m in re.finditer(pattern, content, re.IGNORECASE | re.MULTILINE):
            findings.append(
                AnalyzerFinding(
                    rule_id="P1",
                    message="Instruction Override",
                    severity=Severity.HIGH,
                    location=Location(file=file_path, start_line=get_line_number(content, m.start())),
                    confidence=confidence,
                    tags=[PatternCategory.PROMPT_INJECTION.value],
                    context=get_context(content, m.start()),
                    matched_text=m.group(0)[:200],
                )
            )
    return findings

```

## Summary

- **Static analysis acts as the initial filter** in SkillSpector's detection pipeline, running before semantic and LLM-based evaluations to catch obvious vulnerabilities quickly.
- **Pattern matching uses compiled regular expressions** across multiple vulnerability categories (prompt injection, privilege escalation, data exfiltration) implemented in dedicated analyzer modules.
- **Findings are richly structured** through the `AnalyzerFinding` class, capturing severity, confidence, location, and context before conversion to the standard `Finding` format.
- **Integration occurs through LangGraph**, with analyzer nodes registered in `ANALYZER_NODES` and executed during the context-building phase of the workflow defined in [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py).

## Frequently Asked Questions

### How does static analysis differ from semantic analysis in SkillSpector?

Static analysis operates on surface-level text patterns using regular expressions to detect known insecure signatures without understanding code semantics. Semantic analysis, which occurs later in the workflow, uses LLM-based reasoning to understand context and intent. Static analysis provides immediate, high-confidence results while semantic analysis handles complex, context-dependent vulnerabilities.

### What file types does SkillSpector's static analysis support?

The system infers file types from extensions within `run_static_patterns` (lines 63-68 of [`static_runner.py`](https://github.com/NVIDIA/SkillSpector/blob/main/static_runner.py)), applying different pattern sets based on the detected type. While the framework can scan any text-based file, specific modules like [`static_patterns_prompt_injection.py`](https://github.com/NVIDIA/SkillSpector/blob/main/static_patterns_prompt_injection.py) target source code, configuration files, and documentation containing security-relevant strings.

### How are static analysis findings prioritized?

Each `AnalyzerFinding` includes explicit `severity` and `confidence` fields set during pattern matching. High-severity findings (such as P1 instruction overrides marked as `Severity.HIGH`) surface immediately. After initial detection, the `meta_analyzer` node aggregates results from all static analyzers and ranks them before final SARIF report generation.

### Can custom static patterns be added to SkillSpector?

Yes. The modular architecture in [`src/skillspector/nodes/analyzers/__init__.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/__init__.py) registers analyzers through the `ANALYZER_NODES` collection. Developers can create new modules implementing the standard `analyze(content, file_path, file_type)` interface, returning `AnalyzerFinding` objects with appropriate rule IDs and `PatternCategory` tags to integrate seamlessly into the existing LangGraph workflow.