{"id":47284570,"url":"https://github.com/kurtpayne/skillscan-security","last_synced_at":"2026-04-20T07:03:39.180Z","repository":{"id":337328795,"uuid":"1153118845","full_name":"kurtpayne/skillscan-security","owner":"kurtpayne","description":"Security scanner for AI agent skills and MCP tool bundles — prompt injection, IOC matching, malware detection, ML classifier","archived":false,"fork":false,"pushed_at":"2026-03-31T18:48:45.000Z","size":27052,"stargazers_count":1,"open_issues_count":6,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-31T20:38:48.432Z","etag":null,"topics":["ai-agent","ai-security","llm-security","mcp","prompt-injection","security","skill-scanner","static-analysis"],"latest_commit_sha":null,"homepage":"https://skillscan.sh","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kurtpayne.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-08T23:13:14.000Z","updated_at":"2026-03-31T18:48:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kurtpayne/skillscan-security","commit_stats":null,"previous_names":["kurtpayne/skillscan","kurtpayne/skillscan-security"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/kurtpayne/skillscan-security","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kurtpayne%2Fskillscan-security","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kurtpayne%2Fskillscan-security/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kurtpayne%2Fskillscan-security/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kurtpayne%2Fskillscan-security/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kurtpayne","download_url":"https://codeload.github.com/kurtpayne/skillscan-security/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kurtpayne%2Fskillscan-security/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31307352,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agent","ai-security","llm-security","mcp","prompt-injection","security","skill-scanner","static-analysis"],"created_at":"2026-03-16T05:36:51.612Z","updated_at":"2026-04-20T07:03:39.173Z","avatar_url":"https://github.com/kurtpayne.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n[![CI](https://github.com/kurtpayne/skillscan-security/actions/workflows/ci.yml/badge.svg)](https://github.com/kurtpayne/skillscan-security/actions/workflows/ci.yml)\n[![CodeQL](https://github.com/kurtpayne/skillscan-security/actions/workflows/codeql.yml/badge.svg)](https://github.com/kurtpayne/skillscan-security/actions/workflows/codeql.yml)\n[![PyPI](https://img.shields.io/pypi/v/skillscan-security.svg)](https://pypi.org/project/skillscan-security/)\n[![Docker Hub](https://img.shields.io/docker/v/kurtpayne/skillscan-security?label=docker)](https://hub.docker.com/r/kurtpayne/skillscan-security)\n[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)\n[![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)](pyproject.toml)\n\n**Free. Private. Offline. No API key required.**\n\nSecurity scanner for AI agent skills and MCP tool bundles. Part of the [SkillScan](https://skillscan.sh) project.\n\nSkillScan Security catches the obvious stuff so you don't have to pay Claude to find it. It runs entirely on your machine — no network calls, no telemetry, no tokens spent — and returns deterministic verdicts before you ever send a skill to an online scanner.\n\nUse it as a free pre-filter in your CI pipeline. If it blocks, you know immediately. If it passes, you've already eliminated the easy wins before handing off to a deeper (and more expensive) analysis layer.\n\nVerdicts: `allow` · `warn` · `block`\n\nDefault policy: `strict`.\n\n---\n\n## Why SkillScan First\n\nOnline AI scanners (Invariant, Lakera Guard, and others) are excellent at nuanced intent analysis. They are also billed per token. Running them on every skill in a large repository is expensive.\n\nSkillScan handles the deterministic layer for free:\n\n- Download-and-execute chains\n- Secret exfiltration patterns\n- Credential harvesting instructions\n- Malicious binary artifacts\n- Known-bad IOC domains and IPs\n- Vulnerable dependency versions\n- Prompt injection and instruction override attempts\n- Social engineering credential requests\n\nIf SkillScan blocks it, you don't need to spend tokens on it. If it passes, you have a clean bill of health on the obvious vectors before your paid scanner runs.\n\n---\n\n## Features\n\n1. **Offline-first.** No network calls required. Runs entirely on your machine.\n2. Archive-safe extraction and static analysis.\n3. Binary artifact classification and flagging (executables, libraries, bytecode, blobs).\n4. Malware and instruction-abuse pattern detection (121 static rules + 17 multilang rules, 15 chain rules).\n5. Instruction hardening pipeline (Unicode normalization, zero-width stripping, bounded base64 decode, action-chain checks).\n6. IOC extraction with local intel matching (updated regularly).\n7. Dependency vulnerability checks (23 Python + 4 npm packages via OSV.dev).\n8. Social engineering and credential-harvest instruction detection (SE-001, SE-SEM-001).\n9. Policy profiles (`strict`, `balanced`, `permissive`, `ci`, `enterprise`, `observe`) + custom policies.\n10. Pretty terminal output + JSON / SARIF / JUnit / compact reports.\n11. Auto-refresh managed intel feeds (default checks every scan, 1-hour max age).\n12. Versioned YAML rulepack for flexible detection updates.\n13. Adversarial regression corpus with expected verdicts.\n14. Default-on local semantic prompt-injection classifier (NLTK/classical features, no external API).\n15. Optional offline ML detection (`--ml-detect`) using a fine-tuned Qwen2.5-1.5B model (GGUF Q4_K_M) — no API key, no cloud.\n\n---\n\n## Distribution Status\n\n- PyPI: `pip install skillscan-security`\n- Docker: `docker pull kurtpayne/skillscan-security`\n- Pre-commit hook: `skillscan-security\u003e=0.8.0`\n\nRelease process: `docs/RELEASE_CHECKLIST.md`.\n\nSBOMs: Python CycloneDX (`sbom-python.cdx.json`) and Docker SPDX (`sbom-docker.spdx.json`) are included in release artifacts.\n\nDocker default behavior: the image includes ClamAV and enables it by default (`SKILLSCAN_CLAMAV=true`). Override with `--no-clamav`.\n\n---\n\n## Install\n\n### Option A: convenience installer\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/kurtpayne/skillscan/main/scripts/install.sh | bash\n```\n\n### Option B: pip\n\n```bash\npip install skillscan-security\n```\n\n**Base install is ~25 MB.** No torch, no transformers, no heavy ML stack. The `--ml-detect` flag requires an optional extra:\n\n```bash\n# llama-cpp-python backend (~935 MB model download) — recommended\npip install 'skillscan-security[ml]'\n```\n\n### Option C: local/dev install\n\n```bash\npython3 -m venv .venv\nsource .venv/bin/activate\npip install -e '.[dev]'\n```\n\n---\n\n## Quick Start\n\n```bash\nskillscan scan ./examples/suspicious_skill\n```\n\nScan directly from URL (including GitHub blob URLs):\n\n```bash\nskillscan scan \"https://github.com/blader/humanizer/blob/main/SKILL.md?plain=1\"\n```\n\nSave reports:\n\n```bash\n# JSON\nskillscan scan ./target --format json --out report.json --fail-on never\n# SARIF (GitHub code scanning)\nskillscan scan ./target --format sarif --out skillscan.sarif --fail-on never\n# JUnit XML (CI test report ingestion)\nskillscan scan ./target --format junit --out skillscan-junit.xml --fail-on never\n# Compact (terse CI logs)\nskillscan scan ./target --format compact --fail-on never\n```\n\nRender a saved report:\n\n```bash\nskillscan explain ./report.json\n```\n\nOptional offline ML detection (requires `[ml]` extra):\n\n```bash\nskillscan scan ./target --ml-detect\n```\n\nThe ML detector uses a fine-tuned Qwen2.5-1.5B model (GGUF Q4_K_M, ~935 MB). It runs entirely on your machine — no API calls, no tokens, no cloud. It is the right tool for subtle semantic attacks that the static rules don't catch. For nuanced intent analysis that requires reasoning about context, see the [integration bridges](#integration-bridges) below.\n\n---\n\n## Highlighted Examples\n\n### 1. Scan a suspicious skill\n\n```console\n$ skillscan scan examples/suspicious_skill --fail-on never\n```\n\n### 2. Scan a benign skill\n\n```console\n$ skillscan scan examples/benign_skill --fail-on never\n```\n\nEvery static rule includes an inline `test_input` field in `default.yaml` that\ndocuments which text triggers the rule. Run all rule tests with:\n\n```console\nSKILLSCAN_NO_USER_RULES=1 pytest tests/test_rule_inputs.py -q\n```\n\n---\n\n## Command Summary\n\n- `skillscan scan \u003cpath\u003e`\n- `skillscan explain \u003creport.json\u003e`\n- `skillscan delta \u003cold_path\u003e \u003cnew_path\u003e`\n- `skillscan alert --baseline-report FILE --current-report FILE`\n- `skillscan watch \u003cpath\u003e`\n- `skillscan badge combine`\n- `skillscan online-trace \u003cskill\u003e`\n- `skillscan feedback [fp|fn|bug|feature]`\n- `skillscan policy list|show|show-default|validate`\n- `skillscan intel status|list|add|remove|enable|disable|lookup`\n- `skillscan rule list|status|show|test|validate`\n- `skillscan model install|status`\n- `skillscan suppress check`\n- `skillscan uninstall [--keep-data]`\n- `skillscan version`\n\nSee full command docs: `docs/COMMANDS.md`.\n\n---\n\n## Policies\n\nBuilt-in profiles:\n\n1. `strict` (default) — maximum coverage, blocks on score \u003e= 70\n2. `balanced` — blocks on score \u003e= 50, HIGH+ severity\n3. `permissive` — trusted environments, blocks on score \u003e= 90, CRITICAL only\n4. `ci` — PR gates, blocks on CRITICAL + HIGH only\n5. `enterprise` — formal security gate, ML required\n6. `observe` — day-one adoption, exit 0 always\n\nUse a built-in profile:\n\n```bash\nskillscan scan ./target --profile balanced\n```\n\nUse a custom policy file:\n\n```bash\nskillscan scan ./target --policy ./examples/policies/strict_custom.yaml\n```\n\n---\n\n## Intel Management\n\nAdd a local IOC source:\n\n```bash\nskillscan intel add --url https://example.com/feeds/iocs.json --type ioc --name team-iocs\n```\n\nView sources:\n\n```bash\nskillscan intel status\nskillscan intel list\n```\n\nManaged intel auto-refresh runs by default on `scan`. You can tune or disable it:\n\n```bash\nskillscan scan ./target --intel-max-age-minutes 60\nskillscan scan ./target --no-auto-intel\n```\n\n---\n\n## Integration Bridges\n\nSkillScan is designed to be the **free pre-filter** in a layered scanning pipeline. It handles deterministic checks locally so you don't spend tokens on the obvious cases. For nuanced intent analysis, pair it with an online scanner.\n\n### Use SkillScan as a pre-filter for Invariant\n\n[Invariant Analyzer](https://github.com/invariantlabs-ai/invariant) provides deep semantic analysis of agent traces and skill files. Run SkillScan first to eliminate clear-cut cases:\n\n```bash\n# Only send to Invariant if SkillScan doesn't block\nskillscan scan ./skill --format json --out pre-filter.json --fail-on never\nif [ \"$(jq -r '.verdict' pre-filter.json)\" != \"block\" ]; then\n  invariant analyze ./skill\nfi\n```\n\nOr in CI:\n\n```yaml\n- name: SkillScan pre-filter\n  run: skillscan scan ./skills --format sarif --out skillscan.sarif\n  continue-on-error: true\n\n- name: Upload SkillScan results\n  uses: github/codeql-action/upload-sarif@v3\n  with:\n    sarif_file: skillscan.sarif\n\n- name: Deep scan (only if SkillScan passes)\n  if: steps.skillscan.outcome == 'success'\n  run: invariant analyze ./skills\n```\n\n### Use SkillScan as a pre-filter for Lakera Guard\n\n[Lakera Guard](https://www.lakera.ai/) provides real-time prompt injection detection via API. SkillScan catches the static patterns for free before you hit the API:\n\n```python\nimport subprocess, json, requests\n\nresult = subprocess.run(\n    [\"skillscan\", \"scan\", skill_path, \"--format\", \"json\", \"--fail-on\", \"never\"],\n    capture_output=True, text=True\n)\nreport = json.loads(result.stdout)\n\nif report[\"verdict\"] == \"block\":\n    # SkillScan caught it — no API call needed\n    raise ValueError(f\"Skill blocked by SkillScan: {report['top_findings']}\")\n\n# SkillScan passed — send to Lakera for semantic analysis\nresponse = requests.post(\n    \"https://api.lakera.ai/v1/prompt_injection\",\n    headers={\"Authorization\": f\"Bearer {LAKERA_API_KEY}\"},\n    json={\"input\": skill_content}\n)\n```\n\n### Pre-commit hook\n\n```yaml\n# .pre-commit-config.yaml\nrepos:\n  - repo: https://github.com/kurtpayne/skillscan-security\n    rev: v0.8.0\n    hooks:\n      - id: skillscan\n        args: [--fail-on, warn]\n```\n\n---\n\n## Example Fixtures\n\n1. Benign sample: `examples/benign_skill`\n2. Suspicious sample: `examples/suspicious_skill`\n3. OpenAI-style sample: `examples/openai_style_tool`\n4. Claude-style sample: `examples/claude_style_skill`\n5. Rule test inputs: inline `test_input` fields in `src/skillscan/data/rules/default.yaml`\n7. OpenClaw-compromised-style sample: `tests/fixtures/malicious/openclaw_compromised_like`\n\n---\n\n## Cross-Platform Skill Bundles\n\nStarter bundles for OpenClaw/ClawHub, Claude-style skills, and OpenAI Actions are in:\n\n- `integrations/openclaw/`\n- `integrations/claude/`\n- `integrations/openai/`\n\nEach `integrations/` directory has a README describing the starter bundle and how to adopt it.\n\n---\n\n## Testing\n\n```bash\n./scripts/run_tests.sh test\n./scripts/run_tests.sh lint\n./scripts/run_tests.sh type\n./scripts/run_tests.sh check\n```\n\nOr via Makefile:\n\n```bash\nmake check\n```\n\n---\n\n## CI/CD Integration\n\nSkillScan provides a reusable GitHub Actions workflow for scanning skill artifacts in CI pipelines with native SARIF upload to the GitHub Security tab.\n\n```yaml\njobs:\n  skillscan:\n    uses: kurtpayne/skillscan-security/.github/workflows/skillscan-scan.yml@main\n    with:\n      scan-path: ./skills\n```\n\nSee `docs/GITHUB_ACTIONS.md` for full documentation and examples.\n\n---\n\n## Extend SkillScan\n\nEvery detection layer except the ML classifier is configurable. The ML model is a frozen GGUF artifact — a tamper-resistant trust anchor that cannot be overridden by local configuration.\n\n### Add custom rules\n\nWrite a YAML file using the same schema as the built-in rules and place it in `~/.skillscan/rules/`. Custom rules are additive — they run alongside the built-in set.\n\n```yaml\n# my-rules.yaml\nstatic_rules:\n  - id: CUSTOM-001\n    name: Internal API Key Exposure\n    description: Detects hardcoded internal API key patterns\n    severity: critical\n    pattern: \"sk-internal-[a-zA-Z0-9]{32}\"\n    tags: [secrets, custom]\n\n  - id: CUSTOM-002\n    name: Internal Domain Reference\n    description: Flags references to internal infrastructure domains\n    severity: high\n    pattern: \"\\\\.internal\\\\.example\\\\.com\"\n    tags: [infra, custom]\n```\n\n```bash\n# Test a rule against a fixture file (positional args)\nskillscan rule test my-rules.yaml test.md\n```\n\nSee [`docs/custom-rules-format.md`](docs/custom-rules-format.md) for the full schema including chain rules, multilang rules, and AST flow rules.\n\n### Suppress false positives\n\nInline — suppress a specific rule on a specific line:\n\n```yaml\n# skillscan-suppress: MAL-001\nexport ADMIN_TOKEN=\"placeholder-replaced-at-runtime\"\n```\n\nProject-level — suppress rules across a whole project via `.skillscan-suppressions.yaml` at the repo root:\n\n```yaml\n# .skillscan-suppressions.yaml\nsuppressions:\n  - id: MAL-001\n    evidence_path: skills/legacy-tool.md\n    reason: Known false positive — token is a placeholder\n    expires: \"2026-12-31\"\n  - id: EXF-003\n    evidence_path: skills/analytics.md\n    reason: Intentional telemetry, reviewed 2026-03-01\n    expires: \"2026-12-31\"\n```\n\nSee [`docs/suppression-format.md`](docs/suppression-format.md) for the full schema.\n\n### Policy profiles\n\nSix built-in profiles cover the most common deployment contexts:\n\n| Profile | Fails on | Use case |\n|---|---|---|\n| `strict` (default) | score \u003e= 70 | Local dev, high-assurance pipelines |\n| `balanced` | score \u003e= 50, HIGH+ | Developer and team use |\n| `permissive` | score \u003e= 90, CRITICAL only | Trusted internal registries |\n| `ci` | CRITICAL + HIGH only | PR gates, CI/CD pipelines |\n| `enterprise` | score \u003e= 70, ML required | Formal security gate |\n| `observe` | never (exit 0 always) | Day-one adoption, reporting only |\n\n```bash\nskillscan scan ./skills/ --profile ci\n```\n\n### Contribute a rule\n\nCommunity-submitted patterns are reviewed and, if accepted, added to the static rule layer — not the model. Submit via the [corpus-submission issue template](https://github.com/kurtpayne/skillscan-security/issues/new?template=corpus-submission.md).\n\nFor the full customization reference, see [skillscan.sh/docs#customization](https://skillscan.sh/docs#customization).\n\n---\n\n## Uninstall\n\n```bash\nskillscan uninstall\n# Keep local data (intel/reports/config):\nskillscan uninstall --keep-data\n```\n\nShell script uninstall: `scripts/uninstall.sh`.\n\n---\n\n## Documentation\n\n- Command reference: `docs/COMMANDS.md`\n- Detection model: `docs/DETECTION_MODEL.md`\n- Scan overview: `docs/SCAN_OVERVIEW.md`\n- Architecture: `docs/ARCHITECTURE.md`\n- Policy guide: `docs/POLICY.md`\n- Intel guide: `docs/INTEL.md`\n- Testing guide: `docs/TESTING.md`\n- Rules and scoring: `docs/RULES.md`\n- Rule catalogue: `docs/EXAMPLES.md`\n- GitHub Actions integration: `docs/GITHUB_ACTIONS.md`\n- Custom rule format: `docs/custom-rules-format.md`\n- Custom policy format: `docs/custom-policy-format.md`\n- Custom intel format: `docs/custom-intel-format.md`\n- Suppression format: `docs/suppression-format.md`\n- ML model metrics: `docs/MODEL_METRICS.md`\n- Release checklist: `docs/RELEASE_CHECKLIST.md`\n- Pattern update changelog: `PATTERN_UPDATES.md`\n\n---\n\n## Related\n\n- **[skillscan-lint](https://github.com/kurtpayne/skillscan-lint)** — Quality linter for AI agent skills: readability, clarity, graph integrity\n- **[Invariant Analyzer](https://github.com/invariantlabs-ai/invariant)** — Deep semantic analysis of agent traces; use SkillScan as a free pre-filter\n- **[Lakera Guard](https://www.lakera.ai/)** — Real-time prompt injection detection API; use SkillScan to eliminate static cases before hitting the API\n- **[skills.sh](https://skills.sh)** — Community registry of AI agent skills\n- **[ClawHub](https://clawhub.ai)** — MCP skill marketplace\n- **[Docker Hub](https://hub.docker.com/r/kurtpayne/skillscan-security)** — `docker pull kurtpayne/skillscan-security`\n- **[PyPI](https://pypi.org/project/skillscan-security/)** — `pip install skillscan-security`\n\n---\n\n## License\n\nLicensed under Apache-2.0. See `LICENSE`.\n\n## Security Note\n\nSkillScan performs static analysis by default and does not execute scanned artifacts. For untrusted inputs, run in a trusted isolated environment.\n\nFor URL scans, unreadable linked sources are reported as low-severity `SRC-READ-ERR` findings. They are flagged for review but are not treated as malicious by default.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkurtpayne%2Fskillscan-security","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkurtpayne%2Fskillscan-security","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkurtpayne%2Fskillscan-security/lists"}