{
  "markdown": "<!-- mcp-name: ai.skilltotal/skilltotal -->\n\n# SkillTotal\n\n[![PyPI](https://img.shields.io/pypi/v/skilltotal)](https://pypi.org/project/skilltotal/)\n[![Python](https://img.shields.io/pypi/pyversions/skilltotal)](https://pypi.org/project/skilltotal/)\n[![License](https://img.shields.io/pypi/l/skilltotal)](LICENSE)\n[![CI](https://github.com/pezhik/skilltotal/actions/workflows/ci.yml/badge.svg)](https://github.com/pezhik/skilltotal/actions/workflows/ci.yml)\n[![GitHub Marketplace](https://img.shields.io/badge/Marketplace-SkillTotal-2ea44f?logo=githubactions&logoColor=white)](https://github.com/marketplace/actions/skilltotal-ai-component-security-scan)\n[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/pezhik/skilltotal/badge)](https://scorecard.dev/viewer/?uri=github.com/pezhik/skilltotal)\n\n**AI Component Security Platform — open-source CLI engine.**\n\nSkillTotal statically analyzes AI-related components — agent skills/plugins, MCP servers, npm /\nPython packages, repositories, and **AI-generated projects you upload as an archive or file** — to\nsurface supply-chain risks, dangerous capabilities, prompt-injection surfaces, and data-exfiltration\npaths **before** the component is installed or trusted. Point it at a path, a git URL, an\n`npm:` / `pypi:` package, or a project archive (`.zip` / `.tar.gz`) / single file.\n\n**Try it online (no install, no account):** [www.skilltotal.ai](https://www.skilltotal.ai) —\nthe website runs this same engine. Prefer the CLI? `pipx install skilltotal` (below).\n\nIt analyzes **only the component itself** — never your user, company, environment,\ndeployment, or runtime context. Every score and finding is derived exclusively from the\nfiles inside the component.\n\n> Core principle: **every confirmed finding carries evidence** (file, line range, code\n> snippet). Anything that cannot be evidenced is placed in `needs_review`, never in\n> `findings`, and never affects the score.\n\n## Why SkillTotal\n\n- **100% local & offline** — the component's code **never leaves your machine**. No account,\n  no API token, no cloud upload (unlike cloud scanners that send your components to a backend).\n- **Safe to point at untrusted components** — the engine analyzes without ever running them on\n  your machine. (Optional dynamic analysis is a separate paid service that runs only in our\n  isolated sandbox, with your consent.)\n- **Zero runtime dependencies**, pure Python stdlib — auditable and easy to vendor/air-gap.\n- **Deterministic** — regex + AST, no LLM in the static engine; the same input always yields\n  the same report.\n- **Evidence-anchored & low false-positive** — every finding points at an exact file:line.\n- **Standards-aligned** — every component gets a behavioral **trait fingerprint** mapped to the\n  **Cloud Security Alliance (CSA)** agentic threat model, **MAESTRO** threat-model layers, and\n  **MITRE ATLAS** tactics — including a three-way *execution-context* read (embedded static\n  credential → delegated OAuth/OIDC → least-privilege scoped identity) that shows the blast radius\n  of a compromise, not just that a secret exists.\n- **Free and open source** (Apache-2.0) — the full static report is free, forever.\n\n## Measured, not asserted\n\nDetection claims are cheap, so the numbers behind them are published with the data and the code\nthat produced them.\n\n- **[The whole MCP registry, scanned](docs/mcp-registry-survey.md)** — every distinct component in\n  the official registry, 17,535 of them, in one deterministic run.\n  81.5% expose tools to an agent, 65.2% can reach the network, 29.3% can execute shell commands —\n  and the risk distribution underneath is far flatter, because a capability scores zero here.\n  [Raw JSON](docs/mcp-registry-survey.json) · [the harness](tests/manual_eval/survey_registry.py).\n- **[Detection efficacy](docs/efficacy-report.md)** — recall and precision on a labelled corpus,\n  regenerated every release and enforced by CI as a floor.\n- **[Corpus report](docs/corpus-report.md)** — full findings across real published AI components.\n\nEvery one of these reproduces: same input, same engine, same output. Nothing is executed and no\nLLM is involved.\n\n## Install\n\nRequires **Python 3.10+**. Zero runtime dependencies. `git` is required only for scanning\nremote URLs.\n\nRecommended for the CLI — [pipx](https://pipx.pypa.io) (isolated install; also works on\nDebian/Ubuntu where bare `pip install` is blocked by PEP 668):\n\n```bash\npipx install skilltotal\n```\n\nOr into a virtual environment / as a library:\n\n```bash\npip install skilltotal\n```\n\nFrom source (development):\n\n```bash\npip install -e \".[dev]\"\n```\n\n## Usage\n\n```bash\n# Human-readable report\nskilltotal scan ./path/to/component\n\n# Scan a remote repository (shallow git clone)\nskilltotal scan https://github.com/owner/repo\n\n# Scan a project archive or a single file (e.g. an AI-generated project downloaded as a ZIP)\nskilltotal scan ./my-project.zip\nskilltotal scan ./app.tar.gz\nskilltotal scan ./suspicious.py\n\n# Scan a package from a registry (latest, or a pinned version)\nskilltotal scan npm:left-pad\nskilltotal scan npm:left-pad@1.3.0\nskilltotal scan pypi:requests\nskilltotal scan pypi:requests==2.31.0\n\n# JSON to stdout\nskilltotal scan ./component --json\n\n# SARIF 2.1.0 (GitHub Code Scanning / IDE)\nskilltotal scan ./component --sarif --output report.sarif\n\n# Write the report to a file (SARIF if --sarif, else JSON)\nskilltotal scan ./component --output report.json\n\n# CI gate: exit code 2 by severity level or by risk score\nskilltotal scan ./component --fail-on-high             # alias for --fail-on high\nskilltotal scan ./component --fail-on medium\nskilltotal scan ./component --fail-on-score 50\n\n# Skip paths (repeatable; combined with the config file's `exclude`)\nskilltotal scan ./component --exclude \"vendor/*\" --exclude \"*.min.js\"\n\n# Opt-in provenance for npm:/pypi: sources (registry metadata -> needs_review, never scored)\nskilltotal scan npm:some-lib --provenance\n\n# Baseline: snapshot current findings, then suppress them on later scans\nskilltotal scan ./component --write-baseline .skilltotal-baseline.json\nskilltotal scan ./component --baseline .skilltotal-baseline.json --fail-on-high\n\n# Diff two versions of a component: what changed between them?\n# Each side is any scannable source (path/archive/git/npm:/pypi:) or a saved --json report.\nskilltotal diff npm:some-lib@1.2.3 npm:some-lib@1.2.4\nskilltotal diff ./old-checkout ./new-checkout --json\nskilltotal diff old-report.json new-report.json\n# CI gate: fail (exit 2) if the new version INTRODUCES a high/critical finding\nskilltotal diff npm:some-lib@1.2.3 npm:some-lib@1.2.4 --fail-on-new high\n\n# Pre-install guard: allow/block decision (exit 2 on block) you can chain before installing\nskilltotal guard npm:some-mcp-server && claude mcp add some-mcp-server -- npx some-mcp-server\nskilltotal guard --installed            # check every AI component already on this machine\nskilltotal guard npm:x --block-on malicious   # block only on malicious indicators\n\n# Inventory: discover AI components already installed on this machine and scan them\n# (reads agent configs for Claude Desktop/Code, Cursor, Windsurf, VS Code, Gemini, and\n#  local skills; derives an npm:/pypi:/local source per MCP server and runs the engine)\nskilltotal inventory\nskilltotal inventory --json\nskilltotal inventory --no-scan          # list only, do not scan\nskilltotal inventory --project .        # also include this project's agent configs\nskilltotal inventory --sbom             # AI-BOM: CycloneDX 1.6 JSON of your agent stack,\n                                        # scan verdicts attached as component properties\n\n# List every detection rule\nskilltotal rules list\nskilltotal rules list --json\n```\n\n**Baseline** suppresses findings by a stable fingerprint of\n`(rule id, file, code snippet)` — independent of line numbers, so it survives edits.\nSuppressed findings are removed before scoring and do not affect the risk score.\n\n**Diff** reports new / resolved / changed findings, evidence-level additions and removals\n(matched by the same line-independent fingerprint as the baseline, so pure line shifts are\nnot noise), capability changes, and the risk-score delta. `--fail-on-new LEVEL` gates only\non risk the new version *introduces* — existing accepted findings never trip it, so it fits\nupgrade reviews (\"is 1.2.4 riskier than the 1.2.3 we already vetted?\") without a baseline\nfile.\n\n**Guard** is the install-time answer to \"should I trust this component right now?\".\nMalicious indicators always block; scored risk at/above `--block-on` blocks;\n**capabilities alone never block** — a legitimate MCP server with shell/network access\npasses, so the guard stays quiet enough to leave enabled everywhere (unlike a raw\n`--fail-on high` gate, which would trip on most of the ecosystem's honest capability\nfindings).\n\n**Provenance** (`--provenance`, opt-in) adds registry-metadata signals for `npm:` /\n`pypi:` sources: *recently published*, *deprecated / yanked*, *no recent releases*, *no\nrepository link*. Metadata is context about a component, not component content — so these\nsignals go to `needs_review` and **never** affect the score or verdict, and the default\nscan stays 100% component-only and offline.\n\n**Project config** (optional) — commit a `.skilltotal.toml` instead of repeating flags\n(CLI flags override it):\n\n```toml\nfail_on = \"high\"           # low | medium | high | critical\nfail_on_score = 50         # or gate on the 0-100 risk score\nexclude = [\"vendor/*\", \"*.min.js\"]\nignore = [\"ST-NET-PY\"]     # rule ids to drop\nbaseline = \".skilltotal-baseline.json\"\n\n# Per-rule policy: reviewable gate decisions that live in the repo, not in a dashboard.\n[policy]\n\"ST-SHELL-PIPE-EXEC\" = \"block\"   # gate trips (exit 2) whenever this rule fires,\n                                 # even with no fail_on configured\n\"ST-DYN-PY\" = \"warn\"             # explicit accept-but-show: reported, still counts toward\n                                 # the risk score, but exempt from the fail_on severity gate\n\"ST-SENS-WORD\" = \"ignore\"        # suppressed entirely (same effect as `ignore`)\n```\n\nSuppress a single finding inline with a `# skilltotal:ignore` (or `# skilltotal:ignore[ST-ID]`)\ncomment on its line.\n\n`python -m skilltotal ...` works identically to the `skilltotal` console script.\n\n### Exit codes\n\n| Code | Meaning |\n|------|---------|\n| 0 | Success |\n| 1 | Usage / collection error (e.g. path missing, clone failed) |\n| 2 | A configured gate tripped (`--fail-on`/`--fail-on-high` severity, `--fail-on-score`, or `diff --fail-on-new`) |\n\n> **Gate semantics:** `--fail-on`/`--fail-on-high` trip on the **severity of any single finding**,\n> not the aggregate `risk_score`. A component can report `risk_level: low` (score 0) and still fail\n> the gate if it has a high-severity finding — including a powerful *capability* (e.g. shell or\n> network access), which is reported but never scored as malicious. To gate on the score instead,\n> use `--fail-on-score`; to accept known findings, use a baseline, an inline\n> `# skilltotal:ignore[ST-ID]`, or a per-rule `[policy]` action (`block` / `warn` / `ignore`).\n\n## CI / GitHub Action\n\nRun SkillTotal in CI and surface findings in your repository's **Security → Code scanning** tab.\n\n```yaml\n# .github/workflows/skilltotal.yml\nname: SkillTotal\non: [push, pull_request]\npermissions:\n  contents: read\n  security-events: write   # required to upload SARIF to Code Scanning\n  pull-requests: write     # required only for comment-on-pr (optional)\njobs:\n  scan:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: pezhik/skilltotal@v0.43.1\n        with:\n          source: .             # a path, a git URL, or an npm:/pypi:<name> spec\n          fail-on: high         # fail the build on a high/critical finding (or 'none')\n          comment-on-pr: 'true' # post a sticky summary comment on pull requests (optional)\n```\n\nThe action installs the CLI, scans `source`, uploads SARIF (so findings appear inline on pull\nrequests and in Code Scanning), and fails the job on a high/critical finding unless\n`fail-on: none`. On pull requests, `comment-on-pr: 'true'` posts a single summary comment (risk\nlevel, score, findings, capabilities) and updates it in place on later runs — it needs\n`pull-requests: write` and is off by default. Pin the action to a released tag (see\n[Releases](https://github.com/pezhik/skilltotal/releases)) and, optionally, pin the engine version\nwith the `version:` input. Prefer plain CLI? It is the same thing:\n`skilltotal scan . --sarif --output skilltotal.sarif --fail-on-high`.\n\n### Use as a pre-commit hook\n\nRun SkillTotal on every commit via [pre-commit](https://pre-commit.com):\n\n```yaml\n# .pre-commit-config.yaml\nrepos:\n  - repo: https://github.com/pezhik/skilltotal\n    rev: v0.43.1\n    hooks:\n      - id: skilltotal\n        args: [\".\", \"--fail-on-high\"]   # scan the repo; block the commit on a high/critical finding\n```\n\nThen `pre-commit install`. The hook installs the CLI in its own environment and scans the repo\non commit; tune the scan with the same flags as the CLI (e.g. `--exclude`, `--fail-on`).\n\n### Use as an MCP server\n\nLet your agent check a component *before* installing it. `skilltotal mcp` runs the engine\nas a stdio MCP server (stdlib-only, still zero dependencies) — register it in Claude\nCode/Desktop, Cursor, Windsurf, or any MCP client:\n\n```json\n{ \"mcpServers\": { \"skilltotal\": { \"command\": \"skilltotal\", \"args\": [\"mcp\"] } } }\n```\n\nTools exposed: `scan_component` (full report for a path / git URL / `npm:` / `pypi:`\nsource), `diff_components` (upgrade review: what changed between two versions), and\n`list_rules`. Scans run locally with the same never-execute static engine — the component's\ncode is not uploaded anywhere.\n\n### Add a status badge\n\nScan a component on [skilltotal.ai](https://www.skilltotal.ai) and each report offers an\n**\"Add this badge\"** snippet — a small SVG that always reflects the component's latest scan and\nlinks back to the full report. Drop it in your README so visitors see the risk at a glance:\n\n```markdown\n[![SkillTotal](https://www.skilltotal.ai/…/badge?source=npm:your-package)](https://www.skilltotal.ai)\n```\n\nCopy the exact, ready-to-paste markdown from the report page — it fills in the badge URL for you.\n\n## Methodology\n\nSkillTotal performs **static** security analysis of AI components — MCP servers, agent\nskills/plugins, npm and PyPI packages, and AI-generated projects/repositories. The engine\ncombines capability analysis, dangerous-pattern detection, privilege analysis, supply-chain\n(install-time) analysis, prompt-surface analysis, and data-flow correlation (e.g. secret\naccess combined with network egress). Findings are mapped to risk categories and contribute to\na **0–100 risk score**; capabilities are reported but never inflate the score — capability ≠ risk.\nNothing is executed and no LLM is called, so results are deterministic and reproducible.\n\n## What it detects\n\n| Category | Examples |\n|----------|----------|\n| Shell execution | `subprocess.*`, `os.system`, `child_process.exec` |\n| Filesystem access | `open`, `read_text`/`write_text`, `fs.readFile`/`writeFile` |\n| Sensitive paths | `~/.ssh`, `~/.aws`, `.env`, `id_rsa`, `credentials`, `secrets` |\n| Network egress | `requests`, `urllib`, `aiohttp`, `fetch`, `axios` |\n| Install-time execution | npm `preinstall`/`postinstall`/`prepare`, `setup.py` hooks |\n| Dynamic code execution | `eval`, `exec`, `compile`, `new Function`, `vm.runInNewContext` |\n| Obfuscation | decode-and-execute chains, base64 blobs, hex escaping, minification |\n| MCP risks | manifests, dangerous tools (shell/fs/network/credential), server commands |\n| Prompt surface | \"ignore previous instructions\", \"reveal system prompt\", exfiltration phrasing |\n\n### Coverage by component type\n\nLegend: **✅** analyzed by default for this component type · **⚠️** the engine detects this, but\nthat surface is uncommon for this type — so it is flagged only when the component actually contains\nit (e.g. prompt-injection text inside an npm/PyPI package) · **❌** not applicable to this type ·\n**🚧** planned (SkillTotal Cloud).\n\nColumns are the component types SkillTotal scans. **AI project** = a scanned repository or folder\n— an agent skill/plugin, an AI-generated codebase, or a set of prompts/configs — that is not a\npublished npm/PyPI package.\n\n| Category | MCP | npm | PyPI | AI project |\n|---|---|---|---|---|\n| Prompt injection / instruction override | ✅ | ⚠️ | ⚠️ | ✅ |\n| Tool poisoning (MCP tool metadata) | ✅ | ❌ | ❌ | ⚠️ |\n| Dangerous capabilities (shell / fs / network) | ✅ | ✅ | ✅ | ⚠️ |\n| Data exfiltration (secret access + egress) | ✅ | ✅ | ✅ | ⚠️ |\n| Secret theft / sensitive-path access | ✅ | ✅ | ✅ | ⚠️ |\n| Dynamic code execution | ✅ | ✅ | ✅ | ⚠️ |\n| Obfuscation (decode-and-execute) | ✅ | ✅ | ✅ | ✅ |\n| Hidden-Unicode smuggling | ✅ | ✅ | ✅ | ✅ |\n| Embedded secrets (hardcoded keys/tokens) | ✅ | ✅ | ✅ | ✅ |\n| Install-time / supply-chain hooks | ⚠️ | ✅ | ✅ | ❌ |\n| Overprivileged / auto-approved tools | ✅ | ❌ | ❌ | ⚠️ |\n| Runtime behavior analysis | 🚧 | 🚧 | 🚧 | 🚧 |\n| Sandbox analysis | 🚧 | 🚧 | 🚧 | 🚧 |\n\n### Typical findings\n\n- An MCP tool can execute arbitrary shell commands\n- A package downloads and runs code from an external URL\n- Access to credential locations (`~/.aws`, `~/.ssh`, `.env`) detected\n- Dynamic code execution (`eval` / `exec`) detected\n- Prompt-injection / instruction-override phrasing in a tool description or skill\n- Sensitive-data access combined with outbound network egress\n- Hardcoded API keys or tokens\n- An MCP server with auto-approved or overprivileged tools\n- Untrusted input (environment, `sys.argv`, a request/response body) flowing into `exec` or a\n  shell — a proven injection path, not just a dangerous API in isolation\n- An **agent skill** does more than its declared `allowed-tools` allow (undeclared capability /\n  least-privilege violation)\n\n## Out of scope\n\nSkillTotal statically analyzes a **single component's own files**. It does not execute code,\nobserve runtime behavior, or assess your environment, deployment, or infrastructure. It is **not**\na substitute for:\n\n- a penetration test\n- an application-security (app-sec) review\n- an architecture / design review\n- a cloud-security or infrastructure assessment\n- a Kubernetes / container runtime audit\n- a business-logic review\n- a manual code review\n\nRuntime behavior and sandbox analysis are planned for **SkillTotal Cloud** (paid).\n\n## Output\n\nA normalized report containing the component identity, a **risk score (0–100)** and\n**risk level** (low / medium / high / critical), detected **capabilities** (each\nevidence-backed), a behavioral **trait fingerprint** (with a CSA / MAESTRO / MITRE ATLAS\ncrosswalk), **findings**, **needs_review**, and **metadata**. See\n[docs/report-schema.md](docs/report-schema.md) and [docs/scoring.md](docs/scoring.md).\n\nEvery finding also carries its **OWASP Agentic Skills Top 10** category ids (`owasp`), emitted in\nboth the JSON report and SARIF (native `taxonomies`/`relationships`);\n[docs/owasp-agentic-skills-mapping.md](docs/owasp-agentic-skills-mapping.md) explains the coverage\n(AST01–AST05) and the honest gaps. For MCP servers,\n[docs/mcp-owasp-mapping.md](docs/mcp-owasp-mapping.md) maps SkillTotal's checks to the OWASP MCP\nSecurity Cheat Sheet (and names the runtime controls a static engine can't cover).\n\nThe report's **`traits`** array is a behavioral fingerprint — a higher-level projection over the\nfindings (e.g. `execution_authority`, `embedded_credential`, `untrusted_perception`, and the\n*emergent* `exfil_correlation` combination) — each mapped to the Cloud Security Alliance\ntrait-based model, a MAESTRO threat-model layer, and a MITRE ATLAS tactic where there is an honest\nfit. It is descriptive and never affects the score; see\n[docs/trait-crosswalk.md](docs/trait-crosswalk.md).\n\n## Architecture\n\nThe package under `skilltotal/` (except `cli.py`) is a pure, side-effect-free library so the\nsame engine can power the future web app and enterprise SaaS. See\n[docs/architecture.md](docs/architecture.md).\n\n## Development\n\n```bash\npip install -e \".[dev]\"\npytest\n```\n\n## Accuracy notes\n\n- Python is analyzed via an **AST** (resolves import aliases, tells `open(p,'w')` from a\n  read, ignores API names that only appear in strings/comments). Node.js/config use regex.\n- **Test code** (`__tests__/`, `*.test.*`, `tests/`, `conftest.py`, …) is demoted to\n  `needs_review` — it is not executed by consumers, so it does not affect the score.\n- Ambiguous signals (bare `secrets`/`credentials` words, lone base64 blobs, \"before\n  answering\" phrasing, minified files) go to `needs_review`, never to `findings`.\n- **Hidden Unicode** (ASCII-smuggling tag characters, Trojan-Source bidi overrides,\n  zero-width chars) is detected and decoded — a real evasion used to smuggle instructions\n  past human review. See `tests/manual_eval/` for calibration against real-world attacks.\n- Shell execution covers `subprocess`/`os.system`, `asyncio.create_subprocess_*`, Node\n  `child_process`, and common process-spawning libraries (Python `sh`/`plumbum`/`pexpect`/\n  `invoke`/`fabric`; Node `zx`/`execa`/`cross-spawn`/`shelljs`/`tinyexec`/`node-pty`).\n- MCP dangerous tools are classified by name/description both in JSON manifests **and when\n  defined in code** (`server.tool(\"run_command\", …)`, `@mcp.tool` over `def read_file`).\n- **Limitations:** detection is at the call/import level. Capability via an *unrecognized*\n  higher-level library (e.g. a git library that writes files internally, a browser library)\n  may not be flagged as a raw filesystem/shell call. Capabilities indicate *presence*, not\n  proven misuse.\n\n## Open source vs SkillTotal Cloud\n\nSkillTotal is **open core**. This engine (analysis + all detection rules + CLI) is open source\nand **complete on its own** — run it locally or in CI, free, offline, with zero runtime\ndependencies. It tells you **what** a component does, with evidence.\n\nPaid features are delivered only via **SkillTotal Cloud** (the website) and explain **why it\nmatters**: LLM interpretation and prioritization of findings, dynamic sandbox execution,\nhosting, scan history, and monitoring. They are server-side services on top of this engine —\ntheir code is not part of this repository. See [docs/open-core.md](docs/open-core.md).\n\n## License\n\n[Apache-2.0](LICENSE). See also [NOTICE](NOTICE).\n",
  "bytes": 22409,
  "sha": "74473a4293bfc321d44572f2c52d0713363544d1306f9cb843111afb15e69ae0",
  "repo_slug": "pezhik/skilltotal",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_ai_skilltotal_skilltotal_e84e4664/readme"
}