# SkillSpector LangGraph Workflow: Core Nodes and Security Analyzers Explained

> Explore the SkillSpector LangGraph workflow and its core nodes like resolve_input, build_context, meta_analyzer, and report. Understand AI skill security scanning with dynamic analyzers.

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

---

**The SkillSpector LangGraph workflow orchestrates AI skill security scanning through four core pipeline nodes—**`resolve_input`**,** `build_context`**,** `meta_analyzer`**, and** `report`**—that manage the analysis lifecycle, alongside a dynamically registered suite of over 19 specialized analyzer nodes covering static patterns, behavioral analysis, MCP policies, and semantic LLM checks.**

SkillSpector is NVIDIA’s open-source framework for auditing AI agents and skills. According to the NVIDIA/SkillSpector source code, the entire security pipeline is implemented as a **LangGraph** state machine defined in [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py), where nodes are wired together to process input, build context, execute parallel security checks, and generate consolidated reports.

## Core Nodes in the SkillSpector LangGraph Workflow

The four core nodes form the immutable spine of the graph. They are explicitly added in the `create_graph()` function (lines 38‑42 of [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py)) and execute sequentially to manage the analysis lifecycle.

### resolve_input

The **`resolve_input`** node normalizes user-provided paths, URLs, or zip archives into a canonical `input_path`. Implemented in [`src/skillspector/nodes/resolve_input.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/resolve_input.py), this node validates file accessibility and format compliance before the workflow proceeds to context building.

### build_context

The **`build_context`** node scans skill files and constructs a unified in-memory representation of the codebase. Located in [`src/skillspector/nodes/build_context.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/build_context.py), it produces the `SkillspectorState` context object containing file lists, dependency graphs, and executable flags. This context is broadcast to all downstream analyzer nodes.

### meta_analyzer

The **`meta_analyzer`** node performs cross-cutting security analysis after all individual analyzers complete. Found in [`src/skillspector/nodes/meta_analyzer.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/meta_analyzer.py), it checks for policy violations that require holistic visibility, such as permission-declaration inconsistencies across files and aggregated risk scoring.

### report

The **`report`** node assembles final output from accumulated findings. Defined in [`src/skillspector/nodes/report.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/report.py), it supports multiple output formats—terminal, JSON, Markdown, and SARIF—and writes the final risk assessment based on the state accumulated through the graph.

## Analyzer Nodes in the SkillSpector LangGraph Workflow

Analyzer nodes are dynamically registered via the registry in [`src/skillspector/nodes/analyzers/__init__.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/__init__.py). The `ANALYZER_NODE_IDS` list (lines 74‑96) enumerates each node ID, which `create_graph()` loops through to wire into the workflow (lines 43‑50 of [`graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/graph.py)).

### Static Pattern Analyzers

These nodes use regex and signature-based detection for specific vulnerability classes:

- **`static_patterns_prompt_injection`**: Detects prompt-injection directives in [`static_patterns_prompt_injection.py`](https://github.com/NVIDIA/SkillSpector/blob/main/static_patterns_prompt_injection.py)
- **`static_patterns_data_exfiltration`**: Identifies hard-coded URLs, network calls, and environment variable leakage
- **`static_patterns_privilege_escalation`**: Flags `sudo` execution and credential reads
- **`static_patterns_supply_chain`**: Checks for unpinned dependencies and vulnerable packages (SC4)
- **`static_patterns_harmful_content`**: Matches disallowed content patterns
- **`static_patterns_excessive_agency`**: Detects unrestricted tool access
- **`static_patterns_output_handling`**: Validates output injection protections
- **`static_patterns_system_prompt_leakage`**: Finds system prompt extraction attempts
- **`static_patterns_memory_poisoning`**: Detects context injection and window stuffing
- **`static_patterns_tool_misuse`**: Identifies unsafe tool parameters and chaining abuses
- **`static_patterns_rogue_agent`**: Flags self-modifying code and background processes
- **`static_patterns_agent_snooping`**: Detects host environment data harvesting
- **`static_yara`**: Applies YARA signatures for malware and crypto-miner detection

### Behavioral Analysis Nodes

These nodes perform code execution and data-flow analysis:

- **`behavioral_ast`**: Parses abstract syntax trees to flag dangerous calls like `exec`, `eval`, and `subprocess`
- **`behavioral_taint_tracking`**: Tracks data flow from sources (environment variables) to sinks (network requests)

### MCP Security Nodes

Model Context Protocol (MCP) specific checks include:

- **`mcp_least_privilege`**: Validates declared permissions match actual capabilities
- **`mcp_tool_poisoning`**: Detects manipulated tool metadata
- **`mcp_rug_pull`**: Identifies suspicious dependency version-pinning or removal patterns

### Semantic Analysis Nodes

LLM-powered nodes for nuanced security assessment:

- **`semantic_security_discovery`**: Surfaces subtle security intent missed by static checks
- **`semantic_developer_intent`**: Classifies developer intent as benign or malicious
- **`semantic_quality_policy`**: Assesses compliance against quality gates

## How the Nodes Connect

The SkillSpector LangGraph workflow follows a strict execution topology defined in `create_graph()`:

```

START → resolve_input → build_context → [parallel analyzer nodes] → meta_analyzer → report → END

```

Every analyzer node receives the full `SkillspectorState` from `build_context` and routes findings to `meta_analyzer`. This guarantees that **meta-level analysis executes only after all individual security checks complete**, enabling comprehensive cross-file correlation.

## Running the SkillSpector Pipeline

Invoke the compiled LangGraph workflow through the public API:

```python
from skillspector import graph  # Compiled graph from src/skillspector/graph.py

result = graph.invoke({
    "input_path": "./my-skill/",     # Supports local dirs, zips, URLs, or SKILL.md

    "output_format": "json",         # Options: terminal | json | markdown | sarif

    "use_llm": True,                 # Set False for static-only analysis

})

print("Risk score:", result["risk_score"])
print("Severity :", result["risk_severity"])
print("Recommendation:", result["risk_recommendation"])

```

The `SkillspectorState` model in [`src/skillspector/state.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/state.py) defines the schema for data flowing between nodes, ensuring type safety across the graph.

## Summary

- **Four core nodes** (`resolve_input`, `build_context`, `meta_analyzer`, `report`) handle the pipeline backbone in [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py)
- **Over 19 analyzer nodes** provide specialized security checks across static patterns, behavioral analysis, MCP policies, and semantic LLM evaluation
- **Dynamic registration** occurs via `ANALYZER_NODE_IDS` in [`src/skillspector/nodes/analyzers/__init__.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/__init__.py)
- **Execution order** ensures analyzers run in parallel after context building, followed by sequential meta-analysis and reporting
- **State management** uses `SkillspectorState` to pass findings and context through the LangGraph workflow

## Frequently Asked Questions

### What distinguishes core nodes from analyzer nodes in the SkillSpector LangGraph workflow?

Core nodes manage the analysis lifecycle and data flow infrastructure, with hardcoded positions in the graph. Analyzer nodes implement specific security detection logic and are dynamically registered through the `ANALYZER_NODE_IDS` registry, allowing the system to extend coverage without modifying [`graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/graph.py).

### How does the meta_analyzer node consolidate findings?

The `meta_analyzer` receives findings from all analyzer nodes via the shared `SkillspectorState`, enabling it to perform cross-file checks such as permission-declaration consistency and aggregated risk scoring that require holistic visibility of the skill codebase.

### Can I run SkillSpector without LLM-based semantic analyzers?

Yes. Set `"use_llm": False` in the `graph.invoke()` call to disable LLM-dependent nodes like `semantic_security_discovery` and `semantic_developer_intent`, executing only static pattern and behavioral analysis.

### Where are analyzer nodes registered in the SkillSpector codebase?

Analyzer nodes are enumerated in the `ANALYZER_NODE_IDS` list within [`src/skillspector/nodes/analyzers/__init__.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/nodes/analyzers/__init__.py) (lines 74‑96), then automatically wired into the LangGraph workflow by the loop in `create_graph()` at lines 43‑50 of [`src/skillspector/graph.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/graph.py).