Skip to main content
Glama
skedaddle

skedaddle

skedaddle-mcp

Check an open-source package before an AI coding agent installs it. A pre-install hook and an MCP server for npm, PyPI and crates.io that blocks:

  • names that do not exist (hallucinated or mistyped, the "slopsquatting" vector),

  • known malware and packages npm has taken down,

  • HIGH/CRITICAL CVEs in the exact version when a fixed version exists (it tells you which one),

  • and signs of a compromised release: provenance attestation lost, a new publisher, an install script or new dependencies appearing in a patch release, a version that was published and then pulled.

No account, no API key, no telemetry. Apache-2.0.

$ skedaddle-mcp check npm axios@1.14.1 | jq -r '"\(.verdict): \(.findings[0].message)"'
block: axios@1.14.1 was published on 2026-03-31T00:21:58.168Z and later removed from the registry (removal usually follows a compromise or malware report)
$ skedaddle-mcp check npm event-stream@3.3.5 | jq -r '"\(.verdict): \(.findings[0].message)"'
warn: event-stream@3.3.5 was published by 'right9ctrl', who published none of the previous 10 releases (dominictarr), without provenance

The full output is JSON: verdict, and each finding with its signal, severity, evidence and source URL.

Why this exists

  • Agents run npm install and pip install in shells nobody hardened. The package manager's own protections (release cooldowns, provenance checks, build-script allowlists) are off unless someone turned them on.

  • Compromised releases are short-lived and high-impact. axios 1.14.1 was live for about three hours on 2026-03-31 (StepSecurity) on a package with about 108M weekly downloads (opensourcemalware.com); litellm 1.82.7/1.82.8 reached PyPI with a stolen token on 2026-03-24 (HN).

  • On npm, OSV holds about 223,000 malicious-package records against about 8,100 ordinary advisories (counted from the OSV npm dump, 2026-11-08; records, not incidents).

  • LLMs invent package names: at least 5.2% of commercial-model and 21.7% of open-model code samples referenced a package that does not exist (Spracklen et al., USENIX Security 2025).

  • The #1 reason developers mute security tools is noise: false positives and unactionable alerts (npm maintainer survey, arXiv 2601.20240). So skedaddle stays quiet by default: ordinary CVEs are not reported, a fresh release alone is not a warning, and every finding carries the evidence and the URL it came from.

Related MCP server: agent-guard-mcp

Install

uv tool install git+https://github.com/altairzhambyl/skedaddle-mcp
skedaddle-mcp --version

An MCP tool is advisory: the model may not call it. A hook runs on every shell command. Add to ~/.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      { "matcher": "Bash", "hooks": [{ "type": "command", "command": "skedaddle-mcp hook", "timeout": 60, "onFailure": "block" }] }
    ]
  }
}

"onFailure": "block" (Claude Code 2.1.295+) makes a crashed or timed-out hook block the command instead of letting it run; skedaddle itself answers within SKEDADDLE_HOOK_BUDGET seconds (default 20) and asks about anything it did not finish.

On block the agent is denied (the user can still run the command themselves). On warn the install proceeds and the agent is told why. If a registry or OSV cannot be reached, the user is asked (set SKEDADDLE_ON_ERROR=allow or deny to change that). Anything skedaddle cannot check is asked about, never silently allowed: a git/URL/ tarball source, a custom registry or index (--registry, -i, --extra-index-url, npm_config_registry, PIP_INDEX_URL, UV_INDEX_URL, an index line inside a requirements file), or more than 50 packages in one command. A bare npm install / npm ci after the agent edited package.json or the lockfile is checked too: dependencies the lockfile does not pin yet, and lockfile entries that changed since git HEAD. npm: aliases are checked as the real package; cd dir && ... and sh -c '...' are followed.

As an MCP server (any MCP client)

claude mcp add skedaddle -- skedaddle-mcp

Tools: check_package(ecosystem, package) and audit_lockfile(path).

From a shell or CI

skedaddle-mcp check pypi requests==2.32.3
skedaddle-mcp audit package-lock.json      # also npm-shrinkwrap.json, requirements*.txt
skedaddle-mcp doctor                       # which package-manager protections are off, and the lines to add

Exit codes: 0 allow, 1 warn, 2 block, 3 could not verify.

Signals

Signal

Severity

Ecosystems

What it means

not-found

block

all

the name does not exist (hallucinated / typo)

malware, security-placeholder

block

all / npm

OSV MAL-* or a malware advisory; npm replaced the package with a -security placeholder

unpublished-version, yanked

block

npm / PyPI, crates

the version was pulled after publication

provenance-lost

block

npm, PyPI

earlier releases had a provenance attestation (npm) or PEP 740 attestation (PyPI); this one does not

install-script-added

block

npm

a preinstall/install/postinstall script appears that the previous release did not have

cve

block

all

HIGH/CRITICAL in this exact version and a fixed version exists (SKEDADDLE_ALL_CVES=1 reports the rest as info)

fresh-package

block

all

the package itself is under 30 days old

new-publisher

warn

npm, PyPI

published by an account / trusted publisher that published none of the recent releases, without provenance (info on a major bump)

deps-added-in-patch, no-git-head

warn

npm

a patch release adds dependencies; not published from a git checkout

fresh-release

info (warn next to another signal)

all

the version is under 3 days old

low-downloads

warn

npm

under 50 downloads last week

What leaves your machine

Only package names and versions, sent to the public registries (registry.npmjs.org, api.npmjs.org, pypi.org, crates.io) and to OSV (api.osv.dev). Nothing else, no telemetry.

How it compares (credit where due)

Most of this problem is solved by settings you should turn on anyway; skedaddle-mcp doctor shows which are off: npm min-release-age, ignore-scripts; pnpm minimumReleaseAge, trustPolicy: no-downgrade, strictDepBuilds; uv exclude-newer. A cooldown alone would have stopped the axios and litellm releases.

Tool

Overlap

Difference

npq (Apache-2.0)

provenance regression, new maintainer, install scripts (npm)

skedaddle adds PyPI/crates, the agent hook and MCP

pnpm settings

cooldown, trust downgrade, build scripts

only when pnpm is the package manager and configured

Aikido safe-chain, Socket sfw

malware gating as an install wrapper, no account

different licences; skedaddle adds release-integrity signals

Socket MCP

package scores over MCP

needs a Socket sign-in per call

Threat model

skedaddle catches the mistakes of a cooperative agent using ordinary commands: a hallucinated name, a pinned version that was compromised, a lockfile edit, a git or custom-registry source it did not notice. It is not a sandbox: an agent (or a prompt injection) that deliberately hides an install — a script file, eval, base64, a binary that fetches packages — is out of scope. For that, run installs without network access or in a container.

Limitations

  • A custom registry in your global ~/.npmrc or pip.conf is not detected (a project .npmrc is): the checks run against the public registries.

  • No tarball-vs-source diff yet (the xz-utils class); no-git-head is a weak proxy.

  • Typosquats that sit quietly for months, and long-con maintainers, pass the integrity signals; only OSV catches them once reported.

  • The hook understands: npm|pnpm|yarn|bun install/add/i/it/ci, npm exec|x|create|init, npx, pnpm|yarn dlx, bun x, bunx; pip/pipX.Y/python -m pip install, uv add, uv pip install|sync, uv tool install, uv run --with, uvx, pipx install|run|inject, poetry add; cargo add|install. Also through cd, sh -c, env, sudo, nice, timeout. Not yet: uv sync / poetry install from pyproject.toml, pnpm/yarn/bun lockfile diffs (only package-lock.json is diffed against git HEAD). A script that installs packages by other means is not seen.

  • Thresholds (30-day package age, 3-day release age, 50 downloads) are judgement calls; open an issue with data.

Development

uv sync
uv run pytest            # offline: recorded registry/OSV answers in tests/fixtures
uv run ruff check src tests
uv run python tests/record_fixtures.py   # re-record fixtures (network)

Tests cover real incidents from recorded registry data (event-stream, axios 1.14.1, ua-parser-js, crossenv, hallucinated names), honest packages (no false alarms), and synthetic versions of incident patterns whose malicious releases are no longer in the registry.

License

Apache-2.0. See LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    An MCP server that verifies npm and PyPI packages before installation, checking for existence, known vulnerabilities, OpenSSF scorecard, and typosquatting, returning an ALLOW/WARN/BLOCK verdict.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI coding agents to automatically verify npm packages against the live registry before installation, flagging hallucinated, slopsquatted, or otherwise suspicious packages with risk verdicts.
    5 npm
    MIT