Security scanner for detecting and remediating malicous AI agent skills and instruction artifacts
Project description
skill-scanner
skill-scanner reviews AI skill and instruction artifacts for security risk using:
- OpenAI analysis
- VirusTotal analysis
Architecture flow
Requirements
- Python 3.11+
uv- OpenAI and/or VirusTotal API key (at least one)
Install (from PyPI)
uv pip install skill-scanner
Base install includes both OpenAI and VirusTotal support.
Install (from source)
uv sync --group dev
Run with:
uv run skill-scanner --help
Alias:
uv run skillscan --help
What gets scanned
By default, discover and scan detect markdown-based skill/instruction artifacts (for example SKILL.md, AGENTS.md, CLAUDE.md, *.instructions.md, *.prompt.md, *.agent.md, .mdc).
Validated skill locations also include:
- Windsurf:
.windsurf/skills/*/SKILL.md,~/.codeium/windsurf/skills/*/SKILL.md - Gemini CLI:
.gemini/skills/*/SKILL.md,~/.gemini/skills/*/SKILL.md(.agents/skills/*/SKILL.mdwhen--platform gemini) - Cline:
.cline/skills/*/SKILL.md,.clinerules/skills/*/SKILL.md,~/.cline/skills/*/SKILL.md,~/.clinerules/skills/*/SKILL.md - OpenCode:
.opencode/skills/*/SKILL.md,~/.config/opencode/skills/*/SKILL.md(.agents/skills/*/SKILL.mdand.claude/skills/*/SKILL.mdwhen--platform opencode) - Claude marketplace/user variants:
.claude/skills/SKILL.md,.claude/skills/*/SKILL.md, and.claude/plugins/marketplaces/*/{plugins,external_plugins}/*/skills/*/SKILL.md - Documented agent profile locations:
.claude/agents/*.md,.gemini/agents/*.md,.gemini/extensions/*/agents/*.md,.opencode/agents/*.md,~/.config/opencode/agents/*.md,.github/agents/**/*.agent.md, andagents/*.agent.md - Skill discovery supports both flat and nested layouts:
skills/SKILL.mdandskills/<name>/SKILL.md
Use --path to target a specific file or folder.
--path discovery is deterministic and only emits files that match known discovery roots/patterns
(plus a direct SKILL.md at the provided path root). It does not treat arbitrary *.md files as targets.
Default discover behavior:
discoverattempts all scopes (repo,user,system,extension).reposcope is only active when your current directory is inside a git repository.- Filesystem traversal errors are non-fatal; discovery returns partial results. Use
--verboseto inspect warnings.
Quick start
# See targets
uv run skill-scanner discover --format json
# Discover only user scope
uv run skill-scanner discover --scope user
# Show detailed discovery warnings
uv run skill-scanner discover --verbose
# Verify key/model configuration
uv run skill-scanner doctor
# Run live API checks (fails non-zero if checks fail)
uv run skill-scanner doctor --check
# Run a combined scan (if both keys are configured)
uv run skill-scanner scan --format summary
Key configuration and analyzer selection
scan requires at least one analyzer enabled.
- If only
OPENAI_API_KEYis available, AI runs and VT is disabled. - If only
VT_API_KEYis available, VT runs and AI is disabled. - If both keys are available, VT findings are included and VT context is passed into AI analysis.
- You can disable either analyzer with
--no-aior--no-vt. - If no model is configured,
gpt-5.2is used as a fallback model.
Use doctor --check to verify the provider/key/model connectivity.
API key safety
Use 1Password secret references instead of plaintext secrets:
OPENAI_API_KEY=op://Developer/OpenAI/api_key
VT_API_KEY=op://Developer/VirusTotal/api_key
Run the scanner through 1Password CLI so references are resolved at runtime:
op run --env-file=.env -- uv run skill-scanner scan --format summary
Security best practice:
- Prefer a 1Password Service Account scoped to only the vault/items required for scanning (least privilege).
Reference:
Output formats
scan --format supports:
table(default)summaryjsonsarif
You can write output to a file with --output <path>.
Useful commands
# List providers
uv run skill-scanner providers
# Scan one path only
uv run skill-scanner scan --path ./some/skill/folder --format summary
# Increase scan concurrency (default: 8)
uv run skill-scanner scan --jobs 16 --format summary
# Enable verbose logs for troubleshooting
uv run skill-scanner scan --verbose --format summary
# List discovered targets without running analyzers
uv run skill-scanner scan --list-targets
# Discover targets from user scope only
uv run skill-scanner discover --scope user --format table
# Discover with detailed traversal diagnostics
uv run skill-scanner discover --verbose --format table
# Scan only selected discovered targets (repeat --target)
uv run skill-scanner scan --target /absolute/path/to/SKILL.md --target /absolute/path/to/AGENTS.md --format summary
# Filter to medium+
uv run skill-scanner scan --min-severity medium --format summary
# Non-zero exit if high+ findings exist
uv run skill-scanner scan --fail-on high --format summary
# Verbose doctor checks
uv run skill-scanner doctor --check --verbose
--list-targets can be used without API keys because it only runs discovery and exits.
Discovery troubleshooting (macOS/Windows)
# macOS/Windows: default discover should complete without crashing
uv run skill-scanner discover --format table
# Scoped check: verify user skill paths only
uv run skill-scanner discover --scope user --format table
Windows known-path sanity check:
- create
%USERPROFILE%\\.clinerules\\skills\\demo\\SKILL.md - run
uv run skill-scanner discover --platform cline --scope user --format table - confirm the demo skill appears in output
Exit behavior
0: scan completed and fail threshold not hit1:--fail-onthreshold matched2: no analyzers enabled (for example missing keys combined with flags), or--targetdid not match any discovered target
doctor --check exit behavior:
0: all executed checks passed1: one or more checks failed
Notes and truncation visibility
scan now surfaces per-target notes in table and summary output, including:
- analyzer failures (OpenAI or VirusTotal)
- payload truncation when files are skipped due to the 400k-character AI payload limit
- unreadable files excluded from payload construction
Contributing
See CONTRIBUTING.md for setup, testing, and PR guidelines.
Roadmap (in progress)
- Improve system prompt hardening to uncover more threat patterns
- Support multiple providers (Gemini, Claude, others)
- Baseline / suppression / false-positive management
- Ollama / local LLM provider support
- Configurable risk scoring
- GitHub Actions template for automated scans
- Improve fixtures to include realistic malicious skills
Version bump workflow
Use uv version so version updates stay command-driven and lock state remains consistent.
# Patch bump (e.g., 0.1.2 -> 0.1.3)
uv version --bump patch
# Or set an explicit version
uv version 0.3.0
Notes:
pyproject.tomlis the canonical version source.uv.lockis generated by uv and should not be edited manually.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file skill_scanner-0.2.3.tar.gz.
File metadata
- Download URL: skill_scanner-0.2.3.tar.gz
- Upload date:
- Size: 287.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
59886aa443d2d0bdee5b3cf7088b4407083e957948a8d65e2a6e5244edd941ee
|
|
| MD5 |
22b2a454688ef88e5dd3a227d89bc6ae
|
|
| BLAKE2b-256 |
69f0bbcf417e150c8ddeffcee2f84a9a83faff6723d7b397215ba31419953a2a
|
Provenance
The following attestation bundles were made for skill_scanner-0.2.3.tar.gz:
Publisher:
release.yml on thedevappsecguy/skill-scanner
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
skill_scanner-0.2.3.tar.gz -
Subject digest:
59886aa443d2d0bdee5b3cf7088b4407083e957948a8d65e2a6e5244edd941ee - Sigstore transparency entry: 1056739547
- Sigstore integration time:
-
Permalink:
thedevappsecguy/skill-scanner@5fd0234d82dca4d4bbb7028107b41f5cc7971abf -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/thedevappsecguy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5fd0234d82dca4d4bbb7028107b41f5cc7971abf -
Trigger Event:
release
-
Statement type:
File details
Details for the file skill_scanner-0.2.3-py3-none-any.whl.
File metadata
- Download URL: skill_scanner-0.2.3-py3-none-any.whl
- Upload date:
- Size: 36.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a47f5dd83c55c96a8198160b8f5941c03617bdf70475f6f26fe4d37202a671d9
|
|
| MD5 |
d07bb619fb17b2ac86f9f2282448bb5f
|
|
| BLAKE2b-256 |
d534e058fa545f85623ed17a7fb219c455edbdbb8f39120d9b862dedf5b141e8
|
Provenance
The following attestation bundles were made for skill_scanner-0.2.3-py3-none-any.whl:
Publisher:
release.yml on thedevappsecguy/skill-scanner
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
skill_scanner-0.2.3-py3-none-any.whl -
Subject digest:
a47f5dd83c55c96a8198160b8f5941c03617bdf70475f6f26fe4d37202a671d9 - Sigstore transparency entry: 1056739574
- Sigstore integration time:
-
Permalink:
thedevappsecguy/skill-scanner@5fd0234d82dca4d4bbb7028107b41f5cc7971abf -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/thedevappsecguy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5fd0234d82dca4d4bbb7028107b41f5cc7971abf -
Trigger Event:
release
-
Statement type: