Import Guardian

io.github.Baneado98Published by GitHub account Baneado98v0.3.0Updated Oct 25, 2026

Catch AI-hallucinated (slopsquatted) npm imports in generated code before npm install.

VerifiedSTDIODesktop onlyDeveloper ToolsSecurity & Monitoring

Overview

AI-generated overview

A local MCP server that checks npm imports in AI-generated code against the live npm registry, flagging hallucinated or suspicious package names before install.

What you can do
Scan a block of generated JS/TS and check every npm import it references, returning CLEAN, REVIEW or BLOCK verdicts with a suggested real package name when one looks invented or risky. Verify an explicit list of package names, or deep-check a single package for existence, age, versions, source repo, weekly downloads and closeness to popular packages. Resolve scoped and subpath imports to their base package and skip Node built-ins and local paths. A premium lockfile audit and a free HTTP API are described in the README but are not part of the local tool set.
When to use it
Use it when an assistant writes or edits code that adds npm dependencies, so invented or freshly squatted package names are caught before an install command runs. Useful as a read-only guardrail in code-generation workflows.
Requirements
Runs locally over stdio, typically launched with npx from the import-guardian-mcp npm package, so Node.js and network access to the npm registry and download-stats API are needed. No authentication, environment variables or headers are declared.
Before you install
Read-only: it does not install or execute packages, and the README says it is a guardrail rather than a guarantee. The README describes a paid premium lockfile audit billed per call in USDC on Base or via a prepaid Stripe key, and a free HTTP endpoint that withholds affected package details; these send code or lockfile contents to a third-party hosted service. Verdicts lean toward REVIEW, so expect some false positives on new but legitimate packages.

Installation

In SourceWeft

  1. Open Import Guardian in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

import-guardian 🪝

Catch AI-hallucinated (slopsquatted) npm imports in generated code — before you run npm install.

An LLM just wrote some code. It might import a package that doesn't exist — a name the model confidently hallucinated. Attackers register exactly those names and ship malware. This is slopsquatting, and in 2026 it's one of the fastest-growing supply-chain attacks: code generators have been observed referencing 205,000+ unique non-existent package names, and real hallucinated packages (react-codeshift, a fake huggingface-cli with 30k+ downloads) have already shown up in the wild.

import-guardian reads the generated code, extracts every npm package it imports, and tells you which ones are real — so an agent never installs a name its own model invented.

It's part of the guardian set: npm-guardian audits a package you've already chosen for CVEs and malicious behaviour, license-guardian audits the licenses of your dependencies (GPL/AGPL/BUSL traps) before you ship, and lockfile-guardian audits the resolved package-lock.json for integrity tampering and risky install scripts. import-guardian works one step earlier than all of them, at the moment the code — and its dependency names — are generated.

What it catches

👻 Hallucinatedimports of packages that do not exist on npm — the model invented the name. Returns BLOCK with a "did you mean" to the closest real package.
🪤 Fresh squatspackages that do exist but were published days ago, have no source repo, near-zero downloads, or are a 1–2 edit typo of a popular library. Returns REVIEW.
🧩 Import-awareresolves import x from "@scope/pkg/sub" → @scope/pkg, lodash/fp → lodash; skips Node built-ins (fs, node:path) and local paths. Plain regex, no AST, zero runtime deps beyond the MCP SDK.

Verdicts: 🟢 CLEAN · 🟠 REVIEW · 🔴 BLOCK.

Use it as an MCP server (free)

json
{  "mcpServers": {    "import-guardian": { "command": "npx", "args": ["-y", "import-guardian-mcp"] }  }}

Tools:

  • scan_code_imports — give it a block of generated JS/TS; it extracts and checks every npm import. Run this on code you just generated, before its install command.
  • check_packages — verify an explicit list of package names.
  • verify_package — deep-check a single package name (existence, age, versions, repo, weekly downloads, edit distance to popular packages).
  • audit_lockfile 🔒 (premium) — the deep one. Give it a lockfile from npm (package-lock.json), yarn (yarn.lock), pnpm (pnpm-lock.yaml), PyPI (requirements.txt / poetry.lock / Pipfile.lock) or Go (go.mod / go.sum) and it resolves the whole transitive tree and audits every package for dependency confusion, transitive typosquats / homoglyph clones, maintainer-takeover fingerprints, nonexistent pins, and install-script risk. See below.

Deep lockfile audit (premium) 🔒

scan_code_imports looks at the handful of imports you can see. audit_lockfile looks at the hundreds you can't — the fully resolved dependency graph in your lockfile — and finds the supply-chain attacks an LLM cannot reason about from source alone:

🎯 Dependency confusiona package the lockfile resolves from a private / internal registry whose name is unclaimed on the public index — an attacker can publish that exact name publicly and shadow it. The single highest-impact supply-chain bug, and impossible to detect without the resolved lockfile + a live public-registry cross-check. On PyPI it's sharper still: pip install --extra-index-url merges your private index with public PyPI and installs the highest version from either (the 2021 attack that hit Microsoft / Apple / Tesla). Returns critical.
🪞 Transitive typosquatshomoglyph/Unicode-confusable clones (rеact with a Cyrillic e), transpositions (axois→axios), and registry-specific squats (PyPI python3-dateutil vs python-dateutil, normalized per PEP 503) across the entire tree — matched against a large per-ecosystem corpus of high-traffic packages.
🕳️ Maintainer takeoverthe fingerprint of a compromised maintainer: a dormant package suddenly republished, a sole-maintainer project, or a rapid republish burst — the pattern behind event-stream, ua-parser-js, node-ipc and PyPI's ctx hijack.
💉 Install-script version-diffingthe sharpest injection signal: a package whose newest release ADDED a postinstall/preinstall/install/prepare hook that the previous release did not have. A previously-clean dependency that suddenly gains code-execution-on-install is exactly how event-stream and ua-parser-js shipped — caught by diffing the two releases' metadata on the live registry. Returns critical, and tells you the last clean version to pin.
🔬 Install-script PAYLOAD analysisgoes past whether a hook exists to what it does: downloads the package tarball, gunzip+untars it in-memory (no deps), resolves the lifecycle command to its entry file, and statically analyzes the actual code for malware behavior — network egress, credential/env exfil, child-process exec, download-and-run, obfuscation. An obfuscation-resistant AST/token analyzer decodes \x/\u/octal escapes and folds split-string concatenation, so a sink hidden as require("child_pro"+"cess") or global["ev"+"al"](…) is still caught. The payload lives inside a binary artifact the buyer's agent never fetches — that's the access+compute moat.
🐍 PyPI sdist setup.py payload analysisthe PyPI analogue of the npm tarball pass, and the sharpest PyPI surface: a source distribution runs setup.py — arbitrary Python — at pip install time, before any of your code. We download the sdist (anti-DoS capped), untar it in-memory, and statically analyze setup.py / setup.cfg / pyproject.toml for the stealer/loader pattern — os.environ exfil, os.system/subprocess exec, .pypirc/AWS/SSH credential theft, urllib/requests egress, exec/eval/__import__ obfuscation, download-and-run, and a non-standard build backend. A Python AST de-obfuscator decodes \x/\u/octal escapes and folds split + implicit-adjacent strings, so getattr(__import__("o"+"s"),"sys"+"tem")(…) is still resolved. The ctx / jeIlyfish / colourama attack class — caught from an artifact the buyer's agent never fetches. BLOCK is gated on the malware combination (exfil/download-exec/packed-loader), so a legitimate C/Cython build that merely shells out to a compiler is reported as an informational note, not a false-positive block.
🦠 Known-malware / known-vuln (live OSV cross-reference)every resolved package is cross-referenced — at its exact pinned version — against the live OSV.dev advisory database (which ingests the OpenSSF Malicious Packages feed as MAL-* plus GitHub/PyPI/Go/crates/Maven/Packagist advisories). If the version your lockfile pins is documented malware (e.g. [email protected], [email protected]), that's a critical / BLOCK — the strongest possible signal. The mapping is version-specific: [email protected] is malware, 3.3.4 is clean, and only a live database query can tell them apart. This is a different kind of moat from the static passes above — the buyer's model doesn't hold the advisory corpus and can't resolve version↔advisory. Queries are batched, cached (TTL), concurrency-capped, and degrade clean if OSV is unreachable (it never turns a clean package into a false positive).
🏗️ Local build-backend follow-hop (PyPI)when pyproject.toml declares a non-standard build backend that ships inside the sdist (backend-path = ["."]), the package runs its own code as the PEP 517 backend at every build/install. We resolve that module to its file in the sdist and analyze its real source (and follow setup.py's local imports one hop), instead of merely flagging the backend name — closing the gap where a payload hides one indirection away from setup.py.
🔀 Go replace hijacka replace … => host/path in go.mod pointing at an external host, live-verified against the Go module proxy. If the replacement doesn't resolve (a private / attacker host), the code your build actually compiles isn't the module you audited or anything go.sum can vouch for.
💣 Install-script & provenance riskpackages in the resolved tree that run install scripts, brand-new pins, missing repos, and near-zero real downloads (verified against npm / pypistats / crates.io).

Seven ecosystems. The same resolved-graph engine runs over npm / yarn / pnpm, PyPI (requirements.txt, poetry.lock, Pipfile.lock), Go modules (go.mod, go.sum), Rust / Cargo (Cargo.lock, Cargo.toml), Java (Maven pom.xml, Gradle build.gradle / .kts / gradle.lockfile) and PHP / Composer (composer.json, composer.lock) — each cross-checked against its own public index (npm registry, PyPI, the Go module proxy, crates.io, Maven Central, Packagist). On crates.io the matcher knows the -/_ equivalence (rustdecimal vs rust_decimal); on Maven an internal groupId:artifactId unclaimed on Central is the dependency-confusion target; on Composer an internal vendor/package unregistered on Packagist while a private repo is merged with the public index is the confusion target, and a Packagist-abandoned package is flagged as a takeover risk. Large lockfiles are bounded: direct + private-source packages are always live-checked first, then transitive up to a cap, so one call never fans out to tens of thousands of requests.

POST /pro/audit   { "lockfile": "<contents of package-lock.json>", "filename": "package-lock.json" }

Pay per call via x402 (USDC on Base) or a prepaid Stripe key. The free POST /audit returns the verdict and issue counts by severity, but withholds which packages are affected and why — that's the paid report. This deep engine runs server-side only and is never shipped in the npm package.

Example

scan_code_imports({ code: 'import shift from "react-codeshift";\nimport React from "react";' })
🟠 REVIEW — 1 referenced package(s) look risky.🟠 react-codeshift  (risk 57/100)    • No source repository linked.    • Only 1 published version.    • Only 3 downloads in the last week despite being 158 days old.🟢 react  (ok) — established package.

Free HTTP API

POST /scan        { "code": "import x from 'reqeusts'\nimport y from 'lodash'" }GET  /verify?name=express

Hosted at https://import-guardian.vercel.app · try /verify?name=express vs /verify?name=reqeusts.

Pay-per-call (x402)

The /pro/* routes are gated by x402. Your agent pays $0.02 USDC per call automatically — no sign-up, no API key. Payment settles on-chain (USDC on Base). The server holds no private key; it only declares a public receiving address.

POST /pro/scan    { "code": "…" }   # 402 → pay → result, no rate limit

How it works (and its limits)

  • Existence + freshness come straight from the live npm registry (registry.npmjs.org) and the download-stats API — these are facts, not guesses, which is the moat: an agent can't reliably know on its own whether a name it generated is real and trusted.
  • "Did you mean" uses Levenshtein distance against a curated list of high-impact packages attackers impersonate.
  • It does not execute or install anything (read-only), and it intentionally errs toward REVIEW rather than silently passing a brand-new lookalike. It is a guardrail, not a guarantee — pair it with npm-guardian for behavioural/CVE auditing of packages you decide to keep.

License

MIT.

Source: README.md at commit 4a7985c

Tools

0
SourceWeft has not started this package in its sandbox yet, so its tools are not known.

Version history

1
  1. v0.3.0LatestSep 16, 2026

Score

50% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts

    Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.

  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listed15 pts

    Answer tools/list without a credential, or ship a package that starts in a sandbox without one.

  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts