mech.app

The mech.app newsletter

Agentic AI, minus the noise.

Get practical field notes on AI agents, automation, developer tools and security delivered to your inbox.

No spam. Unsubscribe anytime.

Dev Tools

SkillSpector: How NVIDIA Built a Security Scanner That Catches Malicious Agent Skills Before Installation

Two-stage static and LLM pipeline scans agent skills for 71 vulnerability patterns, live CVE lookups, and fail-closed resource bounds.

Source: github.com
SkillSpector: How NVIDIA Built a Security Scanner That Catches Malicious Agent Skills Before Installation

Agent skills run with implicit trust. Claude Code, Codex CLI, and MCP tools execute arbitrary Python, shell commands, and API calls with the same privileges as the host process. NVIDIA scanned 31,132 skills and found 26.1% contain vulnerabilities and 5.2% show likely malicious intent. SkillSpector is the security scanner they built to catch these issues before installation.

The tool is part of NVIDIA’s Verified Skills pipeline, which scans, evaluates, and signs agent skills before publication to their catalog. It runs a two-stage analysis: fast static checks followed by optional LLM semantic evaluation. The scanner detects 71 vulnerability patterns across 17 categories, queries live CVE databases, and enforces fail-closed resource bounds to prevent analysis-time attacks.

The Supply Chain Problem

Agent skills are distributed as Git repos, zip bundles, or single files. Developers install them with minimal vetting. The trust model assumes skills are safe because they come from a GitHub repo or a catalog listing. This is the same supply chain risk that hit npm, PyPI, and Docker Hub, but agent skills have broader execution scope.

A malicious skill can:

  • Exfiltrate environment variables, API keys, or file contents
  • Inject prompts that override system instructions
  • Escalate privileges by calling shell commands
  • Poison agent memory to influence future decisions
  • Abuse tool permissions (MCP least privilege violations)
  • Trigger on specific inputs (time bombs, keyword triggers)

SkillSpector scans for these patterns before the skill touches your runtime.

Two-Stage Analysis Pipeline

The scanner runs static analysis first, then optionally invokes an LLM for semantic evaluation. This balances speed against depth.

Stage 1: Static Analysis

Fast checks that run without network calls or LLM inference:

  • AST parsing: Detects dangerous code patterns (eval, exec, subprocess, file writes)
  • YARA signatures: Matches known malicious patterns in code and config files
  • Taint tracking: Follows user input through the skill to identify injection points
  • MCP least privilege: Checks if the skill requests more tool permissions than it uses
  • Supply chain (SC4): Queries OSV.dev for CVEs in dependencies, with automatic offline fallback

The static stage produces findings in under 5 seconds for most skills. If the skill is clean or the findings are low-severity, you can stop here.

Stage 2: LLM Semantic Evaluation

Optional deep analysis that requires an LLM API key:

  • Prompt injection: Detects attempts to override system instructions or leak prompts
  • Data exfiltration: Identifies obfuscated network calls or encoding tricks
  • Excessive agency: Flags skills that request permissions beyond their stated purpose
  • Memory poisoning: Catches attempts to corrupt agent state or conversation history
  • Anti-refusal: Detects jailbreak patterns or refusal suppression
  • Rogue agent: Identifies skills that spawn subagents or delegate tasks without disclosure

The LLM stage adds 10-30 seconds depending on skill size and model latency. It catches semantic issues that static analysis misses, like a skill that claims to “format JSON” but also sends data to a remote endpoint.

Fail-Closed Resource Bounds

SkillSpector enforces hard limits to prevent analysis-time attacks. A malicious skill could try to crash the scanner, exhaust memory, or trigger infinite loops. The bounds are:

ResourceLimitBehavior on Violation
Bundle size100 MBReject before extraction
Parser depth1000 AST nodesTruncate and flag
Nested artifacts10 levelsStop recursion, flag
Finding count500 findingsStop analysis, report overflow
Analysis timeout5 minutesKill process, mark unsafe

These limits are documented in docs/ANALYSIS_RESOURCE_BOUNDS.md. The scanner fails closed: if a skill exceeds any bound, the scan aborts and the skill is marked unsafe. This prevents zip bombs, parser exploits, and resource exhaustion.

Vulnerability Taxonomy: 71 Patterns Across 17 Categories

The scanner checks for 71 specific patterns grouped into 17 categories. Here are the high-impact categories:

Prompt Injection: Detects skills that try to override system instructions, leak the system prompt, or inject hidden instructions into user messages.

Data Exfiltration: Catches network calls to non-declared endpoints, base64 encoding of sensitive data, and file reads followed by external writes.

Privilege Escalation: Flags shell command execution, file system writes outside the skill directory, and environment variable access.

Supply Chain (SC4): Queries OSV.dev for known CVEs in dependencies. If the network is unavailable, it falls back to a local CVE database snapshot.

MCP Least Privilege: Compares the tool permissions a skill requests against the tools it actually calls. A skill that requests file system access but never uses it gets flagged.

MCP Tool Poisoning: Detects skills that redefine or override existing MCP tools to intercept calls or modify behavior.

Memory Poisoning: Identifies attempts to corrupt agent memory, conversation history, or state files.

Dangerous Code (AST): Static analysis of Python AST for eval, exec, compile, import, subprocess, os.system, and other risky calls.

Taint Tracking: Follows user input through the skill to identify injection points. If user input reaches eval or subprocess without sanitization, it gets flagged.

The full list is in the repository under docs/VULNERABILITY_PATTERNS.md.

Live CVE Lookups with Offline Fallback

The SC4 (supply chain) analyzer queries OSV.dev for real-time CVE data. When you scan a skill, SkillSpector extracts dependency declarations (requirements.txt, package.json, go.mod) and sends them to OSV.dev. The response includes CVE IDs, severity scores, and patched versions.

If the network is unavailable or OSV.dev is down, the scanner falls back to a local CVE database snapshot. The snapshot is updated weekly via GitHub Actions and bundled with the release. This ensures the scanner works in air-gapped environments or CI pipelines without internet access.

The fallback is automatic. You do not configure it. The scanner tries OSV.dev first, then switches to local data if the request times out or fails.

Output Formats and Integration Points

SkillSpector produces four output formats:

  • Terminal: Human-readable summary with color-coded severity levels
  • JSON: Machine-readable findings for CI/CD pipelines
  • Markdown: Report suitable for pull request comments or documentation
  • SARIF: Static Analysis Results Interchange Format for GitHub Code Scanning and other SAST tools

The JSON output is the integration point for CI/CD. You can gate skill installation by checking the exit code or parsing the findings array.

import subprocess
import json

result = subprocess.run(
    ["skillspector", "scan", "skill.zip", "--format", "json"],
    capture_output=True,
    text=True
)

findings = json.loads(result.stdout)
critical = [f for f in findings if f["severity"] == "critical"]

if critical:
    print(f"Blocked: {len(critical)} critical findings")
    exit(1)

The SARIF output integrates with GitHub Code Scanning. Upload the SARIF file as a workflow artifact and GitHub will annotate pull requests with findings.

Gating Skill Installation in Production

You have three integration points:

Pre-commit hooks: Scan skills before they enter version control. This catches issues before they reach CI/CD.

CI/CD pipelines: Run SkillSpector as a build step. Fail the build if critical findings are detected.

Runtime interception: Wrap the skill installation command with a scanner check. This is the last line of defense.

NVIDIA uses all three. The Verified Skills pipeline scans every skill submission, signs passing skills with a GPG key, and publishes them to the catalog. Users can verify signatures before installation.

For self-hosted catalogs, you can run SkillSpector as a pre-receive hook in your Git server or as a Lambda function that scans uploaded bundles.

Pi and OpenCode Extensions

SkillSpector ships with extensions for Pi and OpenCode, two agent frameworks. These extensions let you scan skills from inside an agent session.

Pi extension: Install SkillSpector as a Pi tool. The agent can call skillspector.scan(url) to check a skill before installing it.

OpenCode extension: Install SkillSpector as an OpenCode tool. Type /skillspector scan <url> in the chat to trigger a scan.

Both extensions run the full two-stage pipeline and return findings in the chat. This is useful when an agent discovers a new skill and wants to vet it before installation.

The extensions are documented in docs/PI_EXTENSION.md and docs/OPENCODE_EXTENSION.md.

Architecture: Analyzer Registry and Finding Ledger

SkillSpector uses an analyzer registry pattern. Each vulnerability category is implemented as a separate analyzer class. The scanner loads all analyzers at startup and runs them in parallel.

Analyzers produce findings. Each finding has:

  • Pattern ID: Unique identifier for the vulnerability pattern
  • Severity: Critical, high, medium, low, info
  • Location: File path, line number, code snippet
  • Description: Human-readable explanation
  • Remediation: Suggested fix

Findings are stored in a ledger. The ledger enforces the 500-finding limit. If an analyzer produces more than 500 findings, the ledger stops accepting new findings and flags the overflow.

The ledger is thread-safe. Analyzers run in parallel and write findings concurrently. The ledger uses a lock to prevent race conditions.

When to Use SkillSpector

Use it when:

  • You install agent skills from public catalogs or GitHub repos
  • You run agents in production with access to sensitive data or APIs
  • You maintain a catalog of approved skills for your organization
  • You need SARIF output for GitHub Code Scanning or other SAST tools
  • You want to enforce least privilege for MCP tools

Avoid it when:

  • You only run skills you wrote yourself (but still consider it for supply chain checks)
  • You need real-time scanning during skill execution (this is a pre-installation scanner)
  • You require formal verification or proof of correctness (this is heuristic-based detection)

The scanner catches known patterns and common mistakes. It does not prove a skill is safe. It reduces risk by filtering out obvious vulnerabilities and malicious code before installation.

Technical Verdict

SkillSpector is a practical tool for a real supply chain problem. The two-stage pipeline balances speed and depth. The fail-closed resource bounds prevent analysis-time attacks. The 71-pattern taxonomy covers the high-impact vulnerability classes. The live CVE lookups with offline fallback make it usable in air-gapped environments.

The scanner is most useful as a CI/CD gate or pre-commit hook. It catches issues before they reach production. The JSON and SARIF outputs integrate cleanly with existing workflows.

The LLM semantic stage is optional but recommended. It catches obfuscated attacks and semantic issues that static analysis misses. Budget 10-30 seconds per skill for the LLM stage.

If you run agents in production or maintain a skill catalog, add SkillSpector to your pipeline. It will not catch every attack, but it will stop the obvious ones.