# Cisco AI Defense Skill Scanner

> Source: <https://github.com/cisco-ai-defense/skill-scanner>
> Published: 2026-06-24 06:44:16+00:00

A best-effort security scanner for AI Agent Skills that detects prompt injection, data exfiltration, and malicious code patterns. Combines **pattern-based detection** (YAML + YARA), **LLM-as-a-judge**, and **behavioral dataflow analysis** to maximize detection coverage of probable threats while minimizing false positives.

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](https://openai.github.io/codex/) and [Cursor Agent Skills](https://docs.cursor.com/context/rules) formats following the [Agent Skills specification](https://agentskills.io). With `--lenient`

, also scans non-standard formats such as Claude Code `.claude/commands/*.md`

and flat markdown skill repos.

**Multi-Engine Detection**- Static analysis, behavioral dataflow, LLM semantic analysis, and cloud-based scanning for layered, best-effort coverage**False Positive Filtering**- Meta-analyzer significantly reduces noise while preserving detection capability** CI/CD Ready**- SARIF output for GitHub Code Scanning,[reusable GitHub Actions workflow](/cisco-ai-defense/skill-scanner/blob/main/docs/github-actions.md), exit codes for build failures**Pre-commit Hook**-[Standard pre-commit framework](https://pre-commit.com/)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.

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 improve 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 reduce noise, but no configuration eliminates all incorrect classifications. Tune the[scan policy](/cisco-ai-defense/skill-scanner/blob/main/docs/user-guide/custom-policy-configuration.md)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.

| Guide | Description |
|---|---|
|

[Architecture](/cisco-ai-defense/skill-scanner/blob/main/docs/architecture/index.md)[Threat Taxonomy](/cisco-ai-defense/skill-scanner/blob/main/docs/architecture/threat-taxonomy.md)[LLM Analyzer](/cisco-ai-defense/skill-scanner/blob/main/docs/architecture/analyzers/llm-analyzer.md)[Meta-Analyzer](/cisco-ai-defense/skill-scanner/blob/main/docs/architecture/analyzers/meta-analyzer.md)[Behavioral Analyzer](/cisco-ai-defense/skill-scanner/blob/main/docs/architecture/analyzers/behavioral-analyzer.md)[Scan Policy](/cisco-ai-defense/skill-scanner/blob/main/docs/user-guide/custom-policy-configuration.md)[Policy Quick Reference](/cisco-ai-defense/skill-scanner/blob/main/docs/reference/policy-quick-reference.md)[Rule Authoring](/cisco-ai-defense/skill-scanner/blob/main/docs/architecture/analyzers/writing-custom-rules.md)[GitHub Actions](/cisco-ai-defense/skill-scanner/blob/main/docs/github-actions.md)[API Reference](/cisco-ai-defense/skill-scanner/blob/main/docs/user-guide/api-server.md)[Development Guide](/cisco-ai-defense/skill-scanner/blob/main/docs/development/setup-and-testing.md)**Prerequisites:** Python 3.10+ and [uv](https://docs.astral.sh/uv/) (recommended) or pip

```
# 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]
# 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"

# 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"
```

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.

```
# Scan a single skill (core analyzers: static + bytecode + pipeline)
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

# 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

# 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
```

**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](/cisco-ai-defense/skill-scanner/blob/main/docs/architecture/analyzers/llm-analyzer.md)).

``` python
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")
```

| 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 |
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 |

| 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 and keep majority-agreed findings |
`--llm-max-tokens N` |
Maximum output tokens for LLM responses (default: 8192) |
`--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 |
`--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 rule signatures (`--rules-file` supported) |

``` bash
$ 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].

Scan skills automatically on every push or PR using the [reusable workflow](/cisco-ai-defense/skill-scanner/blob/main/docs/github-actions.md):

```
# .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](/cisco-ai-defense/skill-scanner/blob/main/docs/github-actions.md) for LLM integration, secret configuration, and branch protection setup.

Scan skills before every commit using the [pre-commit](https://pre-commit.com/) 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 automatically detects which skill directories have staged changes and only scans those, keeping commit times fast. Use `--all`

to scan everything.

We welcome contributions! Please see [CONTRIBUTING.md](/cisco-ai-defense/skill-scanner/blob/main/CONTRIBUTING.md) for guidelines.

Apache 2.0 - See [LICENSE](/cisco-ai-defense/skill-scanner/blob/main/LICENSE) for details.

Copyright 2026 Cisco Systems, Inc. and its affiliates
