Skip to main content

Skill Scanner

License CPython 3.11–3.14 PyPI version CI Discord Cisco AI Defense AI Security Framework Ask DeepWiki

A best-effort security scanner for AI Agent Skills that detects prompt injection, data exfiltration, and malicious code patterns. It combines pattern-based detection (YAML + YARA-X), AST and dataflow analysis, an optional LLM-as-a-judge, and a bounded CEL decision layer over typed detector facts.

Important: This scanner provides best-effort detection, not comprehensive or complete coverage. A scan that returns no findings does not guarantee that a skill is free of all threats. See Scope and Limitations below.

Supports OpenAI Codex Skills and Cursor Agent Skills formats following the Agent Skills specification. With --lenient, also scans non-standard formats such as Claude Code .claude/commands/*.md and flat markdown skill repos.


Highlights

  • Multi-Engine Detection - Static analysis, behavioral dataflow, LLM semantic analysis, and cloud-based scanning for layered, best-effort coverage
  • Typed CEL Decisions - The core scanner uses the official cel-go v0.32.0 runtime to correlate bounded facts after deterministic detection and before optional LLM analysis
  • Finding Review - The optional Meta-analyzer correlates, prioritizes, and can filter findings; paired accuracy validation remains pending
  • CI/CD Ready - SARIF output for GitHub Code Scanning, reusable GitHub Actions workflow, exit codes for build failures
  • Pre-commit Hook - Standard pre-commit framework integration to scan skills before every commit
  • Extensible - Plugin architecture for custom analyzers

Join the Cisco AI Discord to discuss, share feedback, or connect with the team.


Scope and Limitations

Skill Scanner is a detection tool. It identifies known and probable risk patterns, but it does not certify security.

Key limitations:

  • No findings ≠ no risk. A scan that returns "No findings" indicates that no known threat patterns were detected. It does not guarantee that a skill is secure, benign, or free of vulnerabilities.
  • Coverage is inherently incomplete. The scanner combines signature-based detection, LLM-based semantic analysis, behavioral dataflow analysis, optional cloud services, and configurable rule packs. While this approach improves coverage, no automated tool can detect every technique, especially novel or zero-day attacks.
  • False positives and false negatives can occur. Consensus modes and meta-analysis can help review findings, but no configuration eliminates all incorrect classifications. Tune the scan policy to your risk tolerance.
  • Human review remains essential. Automated scanning is one component of a defense-in-depth strategy. High-risk or production deployments should pair scanner results with manual code review and/or threat modeling.

Current modernization evidence

The final core + CEL development benchmark contains 5,256 malicious and 1,338 benign MaliciousSkillBench packages. Compared with origin/main, the current scanner raised F1 from 32.92% to 47.73% and recall from 19.88% to 31.43%, while reducing benign false-positive rate from 3.59% to 1.05%. Precision is 99.16%. Five CEL-shadow runs were exact and deterministic; CEL evaluated 154 candidates without proposing a suppression or falling back.

The locked source-disjoint split is weaker: TP=65, FP=42, TN=503, and FN=774, for 60.75% precision, 7.75% recall, 13.74% F1, and 7.71% FPR. This improves F1 over origin/main (7.40%) but regresses FPR (3.67%), so it does not pass the promotion gate. Every bundled CEL rule therefore remains in shadow; this change does not promote any CEL suppression.

Compatibility and supplemental checks found identical CEL-OFF/CEL-SHADOW findings on 111 official Codex, Claude Code, and Cursor skills (30 MEDIUM+ and 8 HIGH/CRITICAL packages), with five stable runs. The NotInject hard-negative set had 0/339 actionable matches. HarmfulSkillBench had 7/200 actionable and 6/200 HIGH+ packages with one quarantined sample, while OpenSkillRisk had 76/263 actionable packages with two host quarantines. The latter two are positive-only recall diagnostics and cannot measure precision or FPR. Optional ATR results are outside this release scope. See Detection Evaluation and Rollout for methodology, provenance, confidence intervals, and limitations.


Documentation

Guide Description
Quick Start Get started in 5 minutes
Architecture System design and components
CEL Decision Layer Typed facts, safety bounds, rollout modes, and telemetry
Threat Taxonomy Complete AITech threat taxonomy with examples
LLM Analyzer LLM configuration and usage
Meta-Analyzer False positive filtering and prioritization
Behavioral Analyzer Dataflow analysis details
Scan Policy Custom policies, presets, and tuning guide
Policy Quick Reference Compact reference for policy sections and knobs
Rule Authoring How to add signature, YARA, and Python rules
GitHub Actions Reusable workflow for CI/CD integration
API Reference REST API documentation
Development Guide Contributing and development setup

Installation

Prerequisites for this checkout and a release containing these changes: CPython 3.11–3.14 and uv (recommended) or pip

A release containing this branch's CEL changes will include the required helper in its wheels; there is no separate CEL extra. That release is configured for CPython 3.11–3.14, while source installs additionally require Go 1.27.1+ to build the helper. Until it is published, the package currently served by PyPI may have a different compatibility contract. See Installation and Configuration for details.

# Using uv (recommended)
uv pip install cisco-ai-skill-scanner

# Using pip
pip install cisco-ai-skill-scanner
Cloud Provider Extras
# AWS Bedrock support
pip install cisco-ai-skill-scanner[bedrock]

# Google AI Studio / Gemini support
pip install cisco-ai-skill-scanner[google]

# Google Vertex AI support
pip install cisco-ai-skill-scanner[vertex]

# Azure OpenAI support
pip install cisco-ai-skill-scanner[azure]

# All cloud providers
pip install cisco-ai-skill-scanner[all]

Quick Start

Environment Setup (Optional)

# For LLM analyzer and Meta-analyzer
export SKILL_SCANNER_LLM_API_KEY="your_api_key"
export SKILL_SCANNER_LLM_MODEL="claude-3-5-sonnet-20241022"
# Optional: disabled, minimal, low, medium, high, xhigh, or max
export SKILL_SCANNER_LLM_REASONING_EFFORT="low"

# For VirusTotal binary scanning
export VIRUSTOTAL_API_KEY="your_virustotal_api_key"

# For Cisco AI Defense
export AI_DEFENSE_API_KEY="your_aidefense_api_key"

Interactive Wizard

Not sure which flags to use? Run skill-scanner with no arguments to launch the interactive wizard:

skill-scanner

The wizard walks you through selecting a scan target, analyzers, policy, and output format, then shows the assembled command before running it. Great for learning the CLI.

CLI Usage

# Scan a single skill (core analyzers: static + bytecode + pipeline + correlation)
skill-scanner scan /path/to/skill

# Scan with behavioral analyzer (dataflow analysis)
skill-scanner scan /path/to/skill --use-behavioral

# Scan with all engines
skill-scanner scan /path/to/skill --use-behavioral --use-llm --use-aidefense

# Scan with meta-analyzer for false positive filtering
skill-scanner scan /path/to/skill --use-llm --enable-meta

# Scan with trigger analyzer for vague description checks
skill-scanner scan /path/to/skill --use-trigger

# Run LLM analyzer multiple times and keep majority-agreed findings
skill-scanner scan /path/to/skill --use-llm --llm-consensus-runs 3

# Scan multiple skills recursively
skill-scanner scan-all /path/to/skills --recursive --use-behavioral

# Scan multiple skills with cross-skill overlap detection
skill-scanner scan-all /path/to/skills --recursive --check-overlap

# Scan a GitHub repository (owner/repo shorthand or full URL)
skill-scanner scan-repo owner/repo
skill-scanner scan-repo https://github.com/owner/repo --use-llm

# Lenient mode: tolerate malformed skills instead of failing
skill-scanner scan /path/to/skill --lenient
skill-scanner scan-all /path/to/skills --recursive --lenient

# Lenient mode with non-standard skill formats (no SKILL.md required)
skill-scanner scan .claude/commands/deploy --lenient
skill-scanner scan-all .claude/commands --recursive --lenient

# Use a custom metadata filename instead of SKILL.md
skill-scanner scan /path/to/skill --skill-file README.md

# CI/CD: Fail build if threats found
skill-scanner scan-all ./skills --fail-on-severity high --format sarif --output results.sarif

# Generate interactive HTML report with attack correlation groups
skill-scanner scan /path/to/skill --use-llm --enable-meta --format html --output report.html

# Use custom YARA rules
skill-scanner scan /path/to/skill --custom-rules /path/to/my-rules/

# Use custom taxonomy + threat mapping profiles (JSON/YAML)
skill-scanner scan /path/to/skill --taxonomy /path/to/taxonomy.json --threat-mapping /path/to/threat_mapping.json

# VirusTotal hash scan with optional unknown-file uploads
skill-scanner scan /path/to/skill --use-virustotal --vt-upload-files

# Use a scan policy preset (strict, balanced, permissive)
skill-scanner scan /path/to/skill --policy strict

# Inspect CEL decisions without suppressing findings
skill-scanner scan /path/to/skill --cel-mode shadow --format json

# Use a custom org policy file
skill-scanner scan /path/to/skill --policy my_org_policy.yaml

# Generate a policy file to customise
skill-scanner generate-policy -o my_org_policy.yaml

# Interactive policy configurator (TUI)
skill-scanner configure-policy

Consensus mode keeps a finding only when it appears in more than half of the configured runs. When those votes disagree on severity, the highest observed severity wins, independent of response order. Failed runs and successful runs that omit the finding cast no vote but remain in the denominator. This makes severity selection stable for majority-agreed findings. It does not make an individual LLM sample deterministic, and descriptive fields from equal-severity votes, single-run output, and non-majority findings can still vary between scans.

LLM provider note: --llm-provider currently accepts anthropic or openai. For Bedrock, Vertex, Azure, Gemini, and other LiteLLM backends, set provider-specific model strings and environment variables (see LLM Analyzer docs).

Python SDK

from skill_scanner import SkillScanner
from skill_scanner.core.analyzers import BehavioralAnalyzer

# Create scanner with analyzers
scanner = SkillScanner(analyzers=[
    BehavioralAnalyzer(),
])

# Scan a skill
result = scanner.scan_skill("/path/to/skill")

print(f"Findings: {len(result.findings)}")
print(f"Max severity: {result.max_severity}")

# Note: is_safe indicates no HIGH/CRITICAL findings were detected.
# It does not guarantee the skill is free of all risk.
if not result.is_safe:
    print("Issues detected -- review findings before deployment")

Security Analyzers

Analyzer Detection Method Scope Requirements
Static YAML + YARA patterns All files None
Bytecode .pyc integrity verification Python bytecode None
Pipeline Command taint analysis Shell pipelines None
Correlation Bounded structured source/sink correlation Python, JavaScript, TypeScript, and package facts None
Behavioral AST dataflow analysis Python files None
LLM Semantic analysis SKILL.md + scripts API key
Meta False positive filtering All findings API key
VirusTotal Hash-based malware Binary files API key
AI Defense Cloud-based AI Text content API key

CLI Options

Option Description
--policy Scan policy: preset name (strict, balanced, permissive) or path to custom YAML
--use-behavioral Enable behavioral analyzer (dataflow analysis)
--use-llm Enable LLM analyzer (requires API key)
--llm-provider LLM provider for CLI routing: anthropic or openai
--llm-consensus-runs N Run LLM analysis N times, keep majority-agreed findings, and retain their highest observed severity
--llm-max-tokens N Maximum output tokens for LLM responses (default: 8192)
--llm-reasoning-effort LEVEL Optional reasoning depth (disabled, minimal, low, medium, high, xhigh, or max); unset preserves the provider default
--use-virustotal Enable VirusTotal binary scanner
--vt-api-key KEY Provide VirusTotal API key directly (optional)
--vt-upload-files Upload unknown binaries to VirusTotal (optional)
--use-aidefense Enable Cisco AI Defense analyzer
--aidefense-api-url URL Override AI Defense API URL (optional)
--use-trigger Enable trigger specificity analyzer
--enable-meta Enable meta-analyzer for false positive filtering
--verbose Include per-finding policy fingerprints, co-occurrence metadata, and keep meta-analyzer false positives
--format Output: summary, json, markdown, table, sarif, html. The html format produces a self-contained interactive report with collapsible correlation groups, expandable code snippets, and pipeline taint flow diagrams
--detailed Include detailed findings in Markdown output
--compact Compact JSON output
--output PATH Default output file path (overridden by --output-<fmt>)
--fail-on-findings Exit with error if HIGH/CRITICAL found (shorthand for --fail-on-severity high)
--fail-on-severity LEVEL Exit with error if findings at or above LEVEL exist (critical, high, medium, low, info)
--custom-rules PATH Use custom YARA rules from directory
--trusted-rule-pack PATH Load an administrator-trusted schema-v2 signature/YARA/CEL pack (repeatable)
--cel-mode MODE Set the CEL decision layer to off, shadow, or enforce
--taxonomy PATH Load custom taxonomy profile (JSON/YAML) for this run
--threat-mapping PATH Load custom scanner threat mapping profile (JSON) for this run
--lenient Tolerate malformed skills (coerce bad fields, fill defaults) instead of failing. When SKILL.md is absent, falls back to scanning .md files in the directory
--skill-file FILENAME Custom metadata filename to use instead of SKILL.md (e.g. README.md)
--check-overlap (scan-all) Enable cross-skill description overlap checks
Command Description
(no command) Launch interactive scan wizard (when run in a terminal)
interactive Launch interactive scan wizard (explicit)
scan Scan a single skill directory
scan-all Scan multiple skills (with --recursive, --check-overlap)
generate-policy Generate a scan policy YAML for customisation
configure-policy Interactive TUI to build/edit a custom scan policy (--input supported)
list-analyzers Show available analyzers
validate-rules Validate bundled rules plus optional --rules-file signatures and repeatable --trusted-rule-pack v2 packs

Balanced (the default) and strict policies use CEL shadow; permissive uses CEL off. Every bundled CEL rule currently has rollout: shadow, so even a global --cel-mode enforce retains findings until an individual rule is qualified and promoted. The ATR pack remains opt-in through --rule-packs atr and is not part of the current core + CEL release gate.


Example Output

$ skill-scanner scan ./my-skill --use-behavioral

============================================================
Skill: my-skill
============================================================
Status: [OK] No findings
Max Severity: NONE
Total Findings: 0
Scan Duration: 0.15s

Note: "No findings" means the scanner did not detect any known threat patterns -- it is not a guarantee that the skill is free of all risk. See Scope and Limitations.


GitHub Actions

Scan skills automatically on every push or PR using the reusable workflow:

# .github/workflows/scan-skills.yml
name: Scan Skills
on:
  pull_request:
    paths: [".cursor/skills/**"]
jobs:
  scan:
    uses: cisco-ai-defense/skill-scanner/.github/workflows/scan-skills.yml@main
    with:
      skill_path: .cursor/skills
    permissions:
      security-events: write
      contents: read

Results appear as inline annotations in PRs via GitHub Code Scanning. See the full guide for LLM integration, secret configuration, and branch protection setup.


Pre-commit Hook

Scan skills before every commit using the pre-commit framework:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/cisco-ai-defense/skill-scanner
    rev: v1.0.0  # use the latest release tag
    hooks:
      - id: skill-scanner

Or install the built-in hook directly:

skill-scanner-pre-commit --install

The hook maps changed files to their nearest SKILL.md and scans each affected skill once. During a normal commit, it reads the staged diff. In CI, compare two revisions so no staged index is required:

pre-commit run skill-scanner --from-ref "$BASE_SHA" --to-ref "$HEAD_SHA"

Both revisions must exist in the checkout. To scan every configured skill, invoke the hook directly:

skill-scanner-pre-commit --scan-all

Alternatively, configure args: [--scan-all] for the hook in .pre-commit-config.yaml.


Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

License

Apache 2.0 - See LICENSE for details.

Copyright 2026 Cisco Systems, Inc. and its affiliates


GitHubDiscordPyPI

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cisco_ai_skill_scanner-2.1.0.tar.gz (1.1 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-win_amd64.whl (5.1 MB view details)

Uploaded CPython 3.11CPython 3.12CPython 3.13CPython 3.14Windows x86-64

cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-manylinux_2_17_x86_64.whl (5.0 MB view details)

Uploaded CPython 3.11CPython 3.12CPython 3.13CPython 3.14manylinux: glibc 2.17+ x86-64

cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-manylinux_2_17_aarch64.whl (4.6 MB view details)

Uploaded CPython 3.11CPython 3.12CPython 3.13CPython 3.14manylinux: glibc 2.17+ ARM64

cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-macosx_13_0_x86_64.whl (5.1 MB view details)

Uploaded CPython 3.11CPython 3.12CPython 3.13CPython 3.14macOS 13.0+ x86-64

cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-macosx_13_0_arm64.whl (4.8 MB view details)

Uploaded CPython 3.11CPython 3.12CPython 3.13CPython 3.14macOS 13.0+ ARM64

File details

Details for the file cisco_ai_skill_scanner-2.1.0.tar.gz.

File metadata

  • Download URL: cisco_ai_skill_scanner-2.1.0.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for cisco_ai_skill_scanner-2.1.0.tar.gz
Algorithm Hash digest
SHA256 14542712f5966a99ec86b27882ef7c5b1803e43587c1fa69e00eb63ddee1ee2e
MD5 c94041e0de33aa8c4b27bfef1d7a11df
BLAKE2b-256 668793a5e410f33ed5c4c62f8da24bca7d99ec5331cfac9a59db384d23d13cfe

See more details on using hashes here.

Provenance

The following attestation bundles were made for cisco_ai_skill_scanner-2.1.0.tar.gz:

Publisher: release.yml on cisco-ai-defense/skill-scanner

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-win_amd64.whl.

File metadata

File hashes

Hashes for cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-win_amd64.whl
Algorithm Hash digest
SHA256 c29d68a2915c73d38971765a35cb0ccd4640e2acb3a4bf542bdbab676dbec8a4
MD5 0c4474809c03cd3f6dccf88e33f7f784
BLAKE2b-256 b47539bd974ae912a92c466e21af67c7a89e547e602301bf9195fc40b8821231

See more details on using hashes here.

Provenance

The following attestation bundles were made for cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-win_amd64.whl:

Publisher: release.yml on cisco-ai-defense/skill-scanner

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 c84292b720bf0eddc8913fe3017dcdb05bd7e98eb19f6ee61dee2c4eb9fa901e
MD5 4496247ba0822b04c6069033a29aaca6
BLAKE2b-256 ffbe5b468d653ece56ab24497b6bb308e0487cc6b4b1b77bb1ebd4b5eb26a19c

See more details on using hashes here.

Provenance

The following attestation bundles were made for cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-manylinux_2_17_x86_64.whl:

Publisher: release.yml on cisco-ai-defense/skill-scanner

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-manylinux_2_17_aarch64.whl.

File metadata

File hashes

Hashes for cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-manylinux_2_17_aarch64.whl
Algorithm Hash digest
SHA256 f867557d9baa7c6654b21c983717240efaf8b0b2f004ae8881e88957ccf69cfc
MD5 709870e4d5988c5cc06d5dbacbc5bb7f
BLAKE2b-256 f80b9180f9b582cf3a5eb7270d6adf8d35c68d742610179b6e102e72507e7b72

See more details on using hashes here.

Provenance

The following attestation bundles were made for cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-manylinux_2_17_aarch64.whl:

Publisher: release.yml on cisco-ai-defense/skill-scanner

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-macosx_13_0_x86_64.whl.

File metadata

File hashes

Hashes for cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-macosx_13_0_x86_64.whl
Algorithm Hash digest
SHA256 55e79e961bc96cf787bb41bb5b79c4dd4f434abbd54125df2bd9488b5c179412
MD5 a8ec33f8f74f03c2c54b678d79428b85
BLAKE2b-256 95c0f0e1ad8bb6be5e6b0fe0e6a428e863f420c1789d2b56bd411d8dcec16e98

See more details on using hashes here.

Provenance

The following attestation bundles were made for cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-macosx_13_0_x86_64.whl:

Publisher: release.yml on cisco-ai-defense/skill-scanner

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-macosx_13_0_arm64.whl.

File metadata

File hashes

Hashes for cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-macosx_13_0_arm64.whl
Algorithm Hash digest
SHA256 452811a64399a7f5f6656f5fccb5487a5f3a0ca00e8cdfa484761022da852bf6
MD5 725ec9519ad9aff17242a002cfc970a2
BLAKE2b-256 5eb5a16cbb76ef9c7428409f2e74d48b42ad02329d44d9782978bb8c9125b207

See more details on using hashes here.

Provenance

The following attestation bundles were made for cisco_ai_skill_scanner-2.1.0-cp311.cp312.cp313.cp314-none-macosx_13_0_arm64.whl:

Publisher: release.yml on cisco-ai-defense/skill-scanner

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

2.1.0 This release

6 files

2.0.14

2 files

2.0.13

2 files

2.0.12

2 files

2.0.11

2 files

2.0.10

2 files

2.0.9

2 files

2.0.8

2 files

2.0.7

2 files

2.0.6

2 files

2.0.5

2 files

2.0.4

2 files

2.0.3

2 files

2.0.2

2 files

2.0.1

2 files

2.0.0

2 files

1.0.2

2 files

1.0.1

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page