Skip to main content

Security scanner for AI skill files (SKILL.md)

Project description

t2i-skillguard

Security scanner for AI skill files (SKILL.md) and bundled code (scripts/, tools/).

It helps you catch high-risk patterns before publishing or running a skill.

Python Output License

TL;DR

# 1) Install
pip install t2i-skillguard

# 2) Scan default locations
t2i-skillguard scan -v

# 3) JSON report with CVSS + payment aggregation
t2i-skillguard scan --format json --aggregate-payment --output report.json

Example execution output:

t2i-skillguard scan example

Why this project

  • Focused on real AI-skill risks (prompt injection, third-party content abuse, unsafe code execution).
  • Scans both skill metadata and executable code paths.
  • Clear terminal output + machine-readable JSON for CI.
  • Opinionated severity model to support go/no-go decisions.

Features

  • 13 built-in security rules for AI skill ecosystems.
  • Scans both SKILL.md and bundled code in scripts/ + tools/.
  • CVSS metadata per vulnerability in JSON output.
  • Optional aggregation of repetitive payment findings (--aggregate-payment).
  • Severity/category filters for focused triage.
  • CI-friendly exit codes (0 clean, 1 findings).

What it detects

t2i-skillguard currently ships with 13 security rules across CRITICAL/HIGH/MEDIUM/LOW.

Severity Rule Category Typical risk
CRITICAL prompt_injection Injection Override safety instructions / exfiltrate context
CRITICAL command_injection Injection Arbitrary command execution
HIGH secret_exposure Exposure Hardcoded keys, tokens, passwords, private keys
HIGH malicious_patterns Dangerous Patterns eval/exec/unsafe deserialization paths
HIGH supply_chain Supply Chain Downloading/executing untrusted code
HIGH / MEDIUM third_party_exposure Dangerous Patterns External content driving AI behavior
MEDIUM insecure_flags Configuration TLS/cert bypass, unsafe runtime flags
MEDIUM path_traversal Configuration Access outside allowed file roots
MEDIUM credential_exposure Exposure Secrets leaked in logs, errors, output
MEDIUM external_content Exposure Unsafe processing of untrusted web/user content
LOW payment_capability Supply Chain Financial capability signal for extra review
MEDIUM system_alteration Configuration Service/firewall/startup/system modifications
LOW frontmatter Metadata Missing/invalid skill metadata

Full rule docs: docs/rules/README.md

Installation

Option A: install from PyPI (recommended for usage)

pip install t2i-skillguard

Option B: local development (recommended for contributors)

poetry install

Quick start

Scan default skill locations:

t2i-skillguard scan

Scan one skill:

t2i-skillguard scan-skill /path/to/skill

Scan custom paths:

t2i-skillguard scan /path/to/skills-a /path/to/skills-b

CLI usage

Output modes

# Terminal (default)
t2i-skillguard scan --format terminal

# JSON
t2i-skillguard scan --format json

# Terminal + JSON
t2i-skillguard scan --format both

# Compact JSON (single line)
t2i-skillguard scan --format compact

Common filters

# Only HIGH and CRITICAL findings
t2i-skillguard scan --min-severity HIGH

# Only one rule category
t2i-skillguard scan --category prompt_injection

# Ignore a whole category
t2i-skillguard scan --ignore-rule prompt_injection

# Ignore a specific pattern in a category
t2i-skillguard scan --ignore-rule prompt_injection.role_confusion

# Repeat or use comma-separated values
t2i-skillguard scan --ignore-rule insecure_flags.http_url --ignore-rule path_traversal
t2i-skillguard scan --ignore-rule insecure_flags.http_url,path_traversal

# Load scoped ignores from YAML file
t2i-skillguard scan --ignore-file .t2i-skillguard-ignore.yml

# Disable warnings for unmatched ignore entries
t2i-skillguard scan --no-warn-unused-ignores

# Skip scripts/tools analysis
t2i-skillguard scan --no-scripts

Ignore rules

Use --ignore-rule when you need to suppress known/accepted findings for a specific run.

  • Accepted format: category or category.pattern
  • Repeatable: --ignore-rule a --ignore-rule b.c
  • Comma-separated supported: --ignore-rule a,b.c
  • Works with both scan and scan-skill
  • You can combine with --ignore-file for file/line-scoped suppression

Examples:

# Ignore all prompt injection findings
t2i-skillguard scan --ignore-rule prompt_injection

# Keep only prompt_injection category, then ignore one noisy pattern
t2i-skillguard scan --category prompt_injection --ignore-rule prompt_injection.role_confusion

# Single-skill scan with ignores
t2i-skillguard scan-skill /path/to/skill --ignore-rule insecure_flags.http_url

Ignore file (YAML)

The scanner will auto-load ./.t2i-skillguard-ignore.yml if it exists. You can also set a custom path with --ignore-file.

Supported schema (version: 1):

version: 1
ignores:
  - category: prompt_injection
  - category: insecure_flags
    pattern: http_url
  - category: credential_exposure
    file: skills/skill-creator/scripts/aggregate_benchmark.py
  - category: prompt_injection
    pattern: concealment_instruction
    file: skills/skill-creator/SKILL.md
    line: 327
    reason: "Known accepted case"

Fields:

  • category (required)
  • pattern (optional)
  • file (optional)
  • line or lines (optional, requires file)
  • reason (optional)

Note: ignore rules (CLI and YAML) affect the final report and exit code for that run. They do not modify detector logic.

Unused ignore warnings

By default, the CLI warns when an ignore entry does not match any finding in the current run.

  • Default: --warn-unused-ignores
  • Disable warnings: --no-warn-unused-ignores

Example warning output:

Ignored findings: 3

Warning: 2 ignore entries did not match any finding.
  - prompt_injection.role_confusion @ /repo/skills/skill-a/SKILL.md:120
  - external_content

Reporting

# Verbose terminal output
t2i-skillguard scan -v

# Save JSON report
t2i-skillguard scan --output report.json

# Aggregate repetitive payment capability findings in terminal and JSON output
t2i-skillguard scan --format both --aggregate-payment

# Aggregate for a single skill scan
t2i-skillguard scan-skill /path/to/skill --format json --aggregate-payment

# Show default locations that will be scanned
t2i-skillguard list-paths

Exit codes (CI-friendly)

  • 0 -> no vulnerabilities found
  • 1 -> one or more vulnerabilities found

This makes it easy to fail CI pipelines when findings are detected.

CI integration (GitHub Actions)

name: Skill Security Scan

on:
  pull_request:
  push:
    branches: [main]

jobs:
  scan-skills:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install Poetry
        run: pipx install poetry

      - name: Install dependencies
        run: poetry install

      - name: Run scanner
        run: poetry run t2i-skillguard scan --format json --aggregate-payment --output skillguard-report.json

Release and PyPI publish

When a GitHub Release is published, .github/workflows/publish-pypi.yml runs and publishes the package to PyPI.

Important:

  • Release tag must match tool.poetry.version in pyproject.toml.
  • Both 1.0.0 and v1.0.0 tag formats are accepted.
  • Publish job runs lint (poetry run ruff check .) and tests (poetry run pytest) before build/upload.
  • Trusted Publisher must be configured in PyPI for this repository/workflow.

Scoring model

Each skill gets a score on a 0-10 scale:

raw_score = min(10, max_severity + vulnerability_count * 0.5)
score = min(raw_score, severity_cap[max_severity])

severity_cap = {
  CRITICAL: 10,
  HIGH: 9,
  MEDIUM: 7,
  LOW: 4,
  INFO: 0,
}

This cap keeps score bands coherent with max-severity verdicts (for example, many LOW findings cannot become CRITICAL by count alone).

Verdict bands:

  • 0 -> OK
  • 1-4 -> LOW
  • 5-7 -> MEDIUM
  • 8-9 -> HIGH
  • 10 -> CRITICAL

Default scan locations

If no path is provided, scanner checks existing directories in this order.

Project scope:

  • ./.opencode/skills/
  • ./.claude/skills/
  • ./.agents/skills/

Global scope:

  • ~/.config/opencode/skills/
  • ~/.claude/skills/
  • ~/.agents/skills/

Compatibility (when present):

  • ${XDG_CONFIG_HOME}/opencode/skills/
  • ${XDG_CONFIG_HOME}/claude/skills/
  • ${XDG_CONFIG_HOME}/agents/skills/
  • ${APPDATA}/opencode/skills/ (Windows)
  • ${APPDATA}/claude/skills/ (Windows)
  • ${APPDATA}/agents/skills/ (Windows)
  • ~/.config/claude/skills/ (legacy)
  • ~/.config/anthropic/skills/ (legacy)

Tip: run t2i-skillguard list-paths to see exactly which paths were found on your machine.

Supported environments

  • OS: Linux, macOS, Windows (including APPDATA path discovery support).
  • Python: 3.10+ recommended.
  • Execution modes:
    • local development via Poetry,
    • CI pipelines (GitHub Actions example included above).
  • Input layout:
    • project-local skill folders (.opencode, .claude, .agents),
    • global skill folders (~/.config/opencode, ~/.claude, ~/.agents),
    • compatibility paths (XDG_CONFIG_HOME, legacy config paths).

CVSS in JSON output

Each vulnerability in JSON output includes CVSS metadata:

  • cvss_vector
  • cvss_score
  • cvss_severity

CVSS is resolved per category.pattern (with category fallback coverage).

When using --aggregate-payment, output also includes grouped-vs-raw counters:

  • report level: raw_total_vulnerabilities
  • skill level: raw_vulnerability_count, raw_payment_vulnerability_count

Aggregation is presentation-only; detection logic, score, and verdict are unchanged.

Example:

{
  "id": "CMDI-001",
  "severity": "CRITICAL",
  "category": "command_injection",
  "pattern": "subprocess_shell_true",
  "cvss_vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
  "cvss_score": 10.0,
  "cvss_severity": "CRITICAL"
}

Development

# Install dependencies
poetry install

# Run lint
poetry run ruff check .

# Run tests
poetry run pytest

# Run scanner locally
poetry run t2i-skillguard scan -v

Contributing

Contributions are welcome.

  • Open an issue for bugs, false positives, or rule improvements.
  • Submit focused PRs with tests for behavior changes.
  • Keep rule docs in docs/rules/ aligned with detector changes.
  • Pull requests run CI checks (.github/workflows/tests.yml) that execute lint + tests and fail the PR check if either command fails.
  • Run the same checks locally before opening PR:
poetry run ruff check .
poetry run pytest

Recommended contribution scope:

  • one detector fix/improvement per PR,
  • documentation updates in the same PR,
  • include before/after examples when tuning detection patterns.

Security policy

See SECURITY.md for supported versions, private reporting instructions, and disclosure policy.

Documentation

License

MIT

Project details


Download files

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

Source Distribution

t2i_skillguard-0.1.0.tar.gz (45.2 kB view details)

Uploaded Source

Built Distribution

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

t2i_skillguard-0.1.0-py3-none-any.whl (58.5 kB view details)

Uploaded Python 3

File details

Details for the file t2i_skillguard-0.1.0.tar.gz.

File metadata

  • Download URL: t2i_skillguard-0.1.0.tar.gz
  • Upload date:
  • Size: 45.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for t2i_skillguard-0.1.0.tar.gz
Algorithm Hash digest
SHA256 50afbb950175748b92ba251648f7250a874985f1298fdbcb4e7969d0af2f9354
MD5 0bb397cac091530b4d1decf2e11d26f7
BLAKE2b-256 6b1f165aba6d281cc3963b17221b7d6006c6df4d65fdc4b5c4c6e6bd9ef54ab5

See more details on using hashes here.

Provenance

The following attestation bundles were made for t2i_skillguard-0.1.0.tar.gz:

Publisher: publish-pypi.yml on Tech2Insights/t2i-skillguard

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

File details

Details for the file t2i_skillguard-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: t2i_skillguard-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 58.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for t2i_skillguard-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b534198629209a24454c0b7fd09ce6a796ce603c038596323e305d4d62fa7771
MD5 6c6d863150b0e66661d078272fe912ba
BLAKE2b-256 03462ac538a40aa12037924274954e5b4be244245ae6158830097c7e4e3f5e5b

See more details on using hashes here.

Provenance

The following attestation bundles were made for t2i_skillguard-0.1.0-py3-none-any.whl:

Publisher: publish-pypi.yml on Tech2Insights/t2i-skillguard

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

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page