Repository navigation
Releases
v1.6.0: Runtime Protection
What's new
Three security layers from an external ChatGPT-agent contribution, independently verified across three REVIEW passes:
Startup Pin Verification
Before any proxy or CLI runtime spawns a server, the Ed25519 signature of pins.json is verified against pins.sig. A tampered store throws at startup. Hex validation prevents silent truncation. An invalid committed key no longer silently falls back. Semantic change: orphan-sig is now tampered (strict fail-closed).
Runtime Auto-Quarantine
In enforce mode, drifted tools are blocked at CALL time (JSON-RPC error -32603), not just stripped from tools/list. Per-tool, not per-server. HTTP responses correlated by request-ID. The P2-1 race (pipelined call before first tools/list) is closed fail-closed. Semantic change: UNCHANGED-unapproved tools now quarantined.
Canary Response Shapes
Replay validation compares every distinct array element structure, preserves JSON property names, accounts for MCP isError outcomes. __proto__ protection via Object.defineProperty.
526 tests (+120 since 1.5.0) · zero dependencies · no telemetry · on-chain verified (Base Mainnet)
v1.5.0
What's new
- outputSchema pinning (R14) - a third hash
outputHashpins what tools RETURN, not just what they accept. A server that quietly widens its response shape is drift now. - Resource content pinning (R13-full) -
resources/readon up to 20 envelope-only resources; the prompt-injection payload hidden in a resource body is a finding, not a surprise. annotations.titlepinned +iconsin toolHash - a silent rename from "Safe File Reader" to "Data Export Utility" is ANNOTATION drift. Ships with the policyVersion bump: legacy pins get POLICY stop, never a silent re-grade.- MIRRORED class + OpenAPI crosscheck (R35/R36) - tighten changes the vendor's published spec already promised are regraded BREAKING -> MIRRORED via
diff --openapi <spec>. BREAKING now means "a previously-successful call starts failing". scan --prune(R37) - drop departed servers/tools/skills/prompts from the pin store on purpose.- A19: payment-credential exfiltration - descriptions instructing the agent to POST card numbers/CVC/expiry. Zero FP on 1152 benign descriptions.
- A20: hidden directive blocks (FORCED) -
<IMPORTANT>/<NOTE TO AGENT>tags (attributes + hyphenated variants), ChatML markers,[//]: #markdown stubs, HTML comments carrying directive text. Benign build markers and linter pragmas stay clean. Class surfaced by the mcp-shield comparison (teleport#61434). - CI badge (
https://rugsnare.com/badge/:owner/:repo.svg), GitHub composite Action, richer PR-comment renderer, Smithery.mcpbbundle. - Preverification fixes: outputHash in the skip-guard, contentHash preserved by approve; signed pins restored for the corpus and repo root.
384 tests, zero dependencies, no telemetry. On-chain pin follows shortly.
RugSnare 1.4.3 - POLICY stop-rule (PIN-SPEC §3.1)
When the pin store's policyVersion differs from the running binary, diff now emits the POLICY finding and STOPS - exactly one finding, no tool-level classes (BREAKING, LOOSENED, COSMETIC, GONE, NEW) follow. Each re-graded class would look like ordinary drift to anyone who scrolled past the POLICY line. The spec says "stops for that pin", and now the code does too. Exit 1 with a hint: "re-run after rugsnare scan to grade under the current policy".
359 tests. Verified: sha256 57483327...6727 matches the on-chain pin. Native launcher unchanged (1.3.0-native.1).
RugSnare 1.4.2 - §7 byte-stability for skills, prompts and resources
All three pin branches (tools, skills, prompts/resources) now share the same skip-guard pattern: a re-scan of unchanged content leaves the entry untouched. Before this fix, pinAllSkills rewrote pinnedAt on every scan (293/293 entries in a field diff), and cmdScan rewrote firstSeen for prompts and resources. The Go native launcher is fixed in the same pass.
359 tests. Verified: artifact sha256 d3f9d643...a71a matches the on-chain pin. Native launcher unchanged (1.3.0-native.1) - binaries attached, rebuilt from the tagged tree.
RugSnare 1.4.1 - skills pin paths are now relative (PIN-SPEC §2)
Patch release: skills pin path field is now stored relative to the skill root instead of machine-absolute (PIN-SPEC §2). The 1.4.0 writer emitted absolute paths, breaking byte-stability across machines (the same skill tree scanned from two different directories produced different bytes) and leaking local layout in published catalog snapshots. Fixed in both the JS CLI and the Go native launcher; pre-v1.4.1 pins with absolute paths are read via a legacy fallback.
357 tests. Verified: artifact sha256 37cbf185...c80e matches the on-chain pin (pinned via Basescan Write Contract - the contract is source-verified there).
Native launcher: unchanged since 1.3.0 (1.3.0-native.1) - binaries attached for convenience, rebuilt from the tagged tree.
RugSnare 1.4.0 - PIN-SPEC v1.1: identity, policy stamp, byte-stable pins
PIN-SPEC v1.1 (promised in microsoft/autogen#7353 and snyk/agent-scan#482): every pin carries an identity block (package, resolvedVersion, entryPath, url) bound by an identityHash; a policyVersion stamp with the POLICY drift class (pins graded under an older verifier policy are never silently re-graded - the ruler changes, the vendor did nothing wrong); the IDENTITY drift class (tool hashes intact but the surface is served by a different build/path - supabase moved its stdio entry with contracts unchanged); and byte-stable pins.json (sorted keys, unchanged entries never rewritten, identical saves skip the write - third parties can JCS-hash the file as an opaque record).
Also in this release: paywall-introduction detection ([PAYWALL] flag - "requires a paid plan" rewrites are schema-silent); hosted endpoints in the public drift-feed (first live hosted catch within 40 minutes of a release); contract provenance (resolved zod/SDK versions per capture - a floating schema dep can rewrite a server's contract with no release); launch-entry pinning (bin moves surface even with zero contract findings); pure-expand finally grades EXPANDED (the P5 label was unreachable since 1.2.0); and verify now really defaults to Base Mainnet, as 1.0.1 promised.
354 tests, zero dependencies, no telemetry. Verified end to end: artifact sha256 c78018cc...4ed2 matches the on-chain pin (tx) - and the ReleaseLog contract itself is now source-verified on Basescan.
Native launcher: unchanged since 1.3.0 (1.3.0-native.1) - binaries attached for convenience.
RugSnare 1.3.0 - deep schema analysis, skills parity, ATR cross-references
Deep schema analysis: schemaDiff now recurses into properties/items/anyOf/oneOf at ANY depth (R21) - changes at depth 2+ are direction-graded for the first time (MongoDB pipeline[][0].$vectorSearch[0].numCandidates, Netlify nested required). Router-union intelligence (R2 cross-tool branch movement, R4 anyOf-to-oneOf keyword swaps graded NOTATION when branches match). Skills: canonical root skills/ (R25), advisory-layer parity via one shared location table - 16 platforms (R26), the .agents/skills standard in both scopes (R27). ATR-compatible: every advisory signal and SARIF rule cross-references the Agent Threat Rules ID for the same technique (docs/ATR-MAPPING.md).
Release re-run fixes, found by re-running the docs/servers pages with this very build: additionalProperties true/{}/absent equivalence (27 false BREAKINGs on the chrome-devtools SDK v2 wave), history --timeout plumbing (flag was parsed but never reached the scanner), R4 swaps no longer grade LOOSENED. New field finding documented as R32: a floating schema dependency (zod ^4.4.3 in mongodb-mcp-server 2.1.2) can rewrite a server's tool contract with no server release.
336 tests, zero dependencies, no telemetry. Verified end to end: npm artifact sha256 af5286af...2fe1 matches the on-chain pin (tx).
Native launcher 1.3.0-native.1 (R25+R27 in its location table) attached for all platforms.
RugSnare 1.2.0 - Drift gradation, constraint keys, rename inference, kill-switch detection
Four rounds of drift-gradation improvements from the KyttoMCP dialogue (P3-P6, all from @heyitsjakub's feedback), plus scanner robustness from field scans of 10+ npm MCP servers.
Four rounds of drift-gradation improvements from the KyttoMCP dialogue
(P3-P6, all from @heyitsjakub's feedback), plus scanner robustness.
Drift gradation (P3-P6: BREAKING / LOOSENED / EXPANDED / NOTATION)
- Direction-aware grading (P3+P4): schema drift now grades by direction.
BREAKING = tighten (new required params, narrowed types, added constraints -
agent must send more, new data channels are exfil-risk). LOOSENED = loosen
(constraints dropped, types widened, parameters removed - validation
weakened, still exit 1 but a distinct failure mode). NOTATION = semantically
empty (dialect switch only). Mixed tighten+loosen = BREAKING (conservative).
Validated on chrome-devtools-mcp 1.8.0-1.10.1: 30 former BREAKING findings
now read 30 NOTATION + 0 BREAKING (the MCP SDK v2 migration wave was pure
notation). - EXPANDED direction (P5): a new optional parameter labels EXPANDED
instead of riding under tighten - backwards-compatible for callers but
attack surface widened (a newcontextparam is a classic exfil vector).
Same exit 1, same severity slot as BREAKING; the label just stops
semver-literate reviewers from reading "breaking" on a non-breaking change. - Guard-parameter warnings (P5+P6): when a schema removes, defangs, or
flips the default of a guard parameter (dry_run, confirm, force,
safe_mode...), the diff adds a context-specific warning. Conditional on
additionalProperties (AP:false = loud failure, no silent-ignore warning). - Constraint keys (R3, from MongoDB field scans): schemaDiff now detects
minItems, maxItems, minimum, maximum, minLength, maxLength, pattern,
multipleOf, uniqueItems, exclusiveMinimum/Maximum, and number-integer
transitions. Previously invisible (NOTATION on real constraint changes). - Default value tracking (P6): schemaDiff compares default values for
all parameters (previously invisible - schemaHash changed but schemaDiff
returned [], grade=NOTATION).
Scanner robustness
- Publish-time version ordering (R10, playwright bug): history now
sorts versions by npm publish timestamp, not semver. Packages with two
versioning epochs (1.52.0-alpha from 2025 semver-older than 0.0.x from
2026) no longer produce phantom cross-epoch pairs. - Rename inference (R11, azure-devops flagship): GONE+NEW tool pairs
with identical schema+prose hashes collapse intoRENAMED a -> b-
the azure case goes from 104 scattered lines to readable
"renamed: N, really-gone: M, new: K". - Kill-switch classification (R12, bybit case): unreachable versions
now carry a cause (KILLSWITCH / GATED / GIT_DEPS / CRASH / TIMEOUT)
based on stderr pattern matching - a remote kill-switch is visible as
a systematic finding, not a generic "exited early". --server-argsflag forrugsnare history: per-package launch
arguments (e.g. LaunchDarkly needsstart --transport stdio). Passed
as a fixed array after the entry point - no shell, no interpolation.--stub-envflag forrugsnare history: injects presence-only dummy
values for common credential env vars - servers that only check key
presence at boot now enumerate their tools/list.- Version stamp in output:
rugsnare diffandrugsnare historyprint
the running rugsnare version in the footer (prevents stale-binary
debugging sessions when comparing outputs). - Pins-version mismatch warning (R1/R9):
rugsnare scanrecords the
package version it scanned against;rugsnare diffwarns when the pins
were taken against a different version than what's currently installed
("if you just upgraded: re-scan first"). - openai-mcp added to --chameleon rotation (R6): Netlify officially
serves 21 granular tools to openai-mcp vs 9 routers to other clients.
Corpus and docs
- Corpus 05: key-reorder fixture (
corpus/05-key-reorder/): two
servers with semantically identical schemas in different key order;
rugsnare diff reports clean (canonicalization proof). Requested by
@heyitsjakub as a fixture for KyttoMCP#12. - Open Pin Format specification drafted at
docs/PIN-SPEC.md(internal;
publication gated on ecosystem timing). - Em-dash cleanup: all long dashes replaced with short hyphens across
source files and documentation (575 replacements).
On-chain: artifact sha256 68d08748... pinned to Base Mainnet (tx 0x5c35...4b13); verify locally with npx rugsnare verify rugsnare-1.2.0.tgz --version 1.2.0 --chain base.
Web: the Runtime scan at rugsnare.com/#history runs rugsnare history in an ephemeral GitHub Actions sandbox - every result links to its public run log. The archive lives at rugsnare.com/scans.
Native launcher (Go, 7 MB, no Node.js needed): unchanged from 1.1.0 - download from v1.1.0 Releases.
RugSnare 1.1.0 — Skills Security, whole-history scanning, native launcher
Runtime integrity for AI agents. This release adds two whole product surfaces on top of the MCP contract pinning core: Skills Security (your agent's instruction files, 14 platforms) and whole-history scanning (has this npm package ever quietly changed its tool contracts?).
-
Whole-history scanning (new):
rugsnare history <package> [--last N] [--from X --to Y]— downloads every published version from the registry
(tarballs pulled directly, deps installed with --ignore-scripts and
--legacy-peer-deps), actually runs each version, takes tools/list, and
diffs consecutive versions with the same split-hash logic. Prints
was/became per drifted tool; exit 1 on silent changes, exit 2 when no
version could be started. On the web: the
Runtime scan button runs the same CLI in an ephemeral GitHub Actions
sandbox and publishes the result with a link to the public run log as
evidence; every scan lands in the public archive at rugsnare.com/scans
(the instant static scan was retired — runtime truth only). -
Skills Security (new):
rugsnare skills scan|diff|report— pin, diff, and
visually report on AI agent skill files (SKILL.md, .mdc, etc.) across Claude
Code, Cursor, Windsurf, Continue, ZCode, Copilot, Codex, and Cline.
Severity classification (DANGEROUS/REVIEW/SAFE) based on content analysis
of changed lines. HTML report with plain-language was/became diffs and
actionable recommendations - designed for non-technical users. -
Native launcher (new): a single Go binary (
native/) with the whole
skills-security half — no Node.js, no npm, double-click and get the HTML
report in your browser. Reads/writes the same.rugsnare/pins.json
skillssubtree as this CLI (verified interop both directions); the
serverssubtree passes through untouched. Windows/macOS/Linux, ~7 MB. -
No silent updates, applied to ourselves:
rugsnare versionprints the
running version;rugsnare doctor --check-updatecompares it against the
npm registry (opt-in, one GET, nothing sent) and links the changelog —
plaindoctorstays fully offline. CI examples now pin the version — an
unpinnednpx rugsnarefloats to latest on every launch, the exact vector
our own floating-version check flags in MCP configs. The native launcher
checksrugsnare.com/latest-native.txtbefore writing a report
(opt-out:-no-update-check). -
Undeclared tool detection (new): the live proxy catches tools called by
the agent that were never listed in tools/list (progressive-discovery servers).
Blocked in enforce, one-time advisory in observe. -
rugsnare diffnow prints the human-readable WAS/NOW description text for
description drift (COSMETIC and ANNOTATION) instead of bare hashes — you see
the exact sentence the agent used to read and the one it reads now. -
Scheduled checks (new, native launcher):
rugsnare-skills install-scheduleregisters a logon check (Startup folder) and a daily
check (Task Scheduler), no admin rights, no resident process — the binary
runs and exits. Quiet mode (-quiet) stays silent when everything
matches and opens the report only when something changed. -
Cold-start audit (new, both CLIs): pinning is trust-on-first-use — it
would bless a skill poisoned before RugSnare was installed. Every skill
file's content is now scanned by the advisory engine (A01-A18) at scan
and report time; pre-existing risks render as a separate "Already on
your machine" section that explicitly says these are not update drift. -
Security fixes (review 28): P0 canary leak via HTTP, P1 error scrubbing,
committed verification key for CI, loud policies degradation, P2 guards. -
Review 32 fixes: P0
osnot imported — everyrugsnare skillscommand
crashed for real users withoutRUGSNARE_TEST_HOMEset (tests masked it);
file-pattern skill locations (.github/copilot-instructions.md,
CONVENTIONS.md) were never discovered (readdir on a file → ENOTDIR);
pure-deletion drift is now REVIEW, not SAFE (silently removed safety
language must never read as safe); bare "token" no longer trips the
credential pattern ("count the tokens" is LLM prose); compareVersions
follows semver prerelease ordering (1.1.0-native.2<1.1.0).
Downloads (native skills scanner, no Node.js required): see the assets below — double-click, get a browser report. Works with Claude Code, Cursor, Windsurf, Continue, Cline, ZCode, Copilot, Codex, Amp, Kiro, OpenCode, Antigravity, Aider, Devin.
On-chain: artifact sha256 21b23f9dd5b64f81a3639775581726cdb56b502a580429b774428a8422e9d335 pinned to Base Mainnet (tx 0xa8ef…47ff); verify locally with npx rugsnare verify rugsnare-1.1.0.tgz --version 1.1.0 --chain base.
Web: the Runtime scan at rugsnare.com/#history runs rugsnare history in an ephemeral GitHub Actions sandbox — every result links to its public run log. The archive of all scans lives at rugsnare.com/scans.
v1.0.1 — CLI now defaults to Base Mainnet for --chain base
Fix release: the 1.0.0 npm tarball was built one commit before the Base Mainnet contract address was added to DEFAULT_CONTRACTS, so rugsnare verify --chain base failed with "No default ReleaseLog contract for chain base".
1.0.1 is built from the correct commit — --chain base works out of the box.
Verification
npx rugsnare verify rugsnare-1.0.1.tgz --version 1.0.1 --chain base
→ VERIFIED
On-chain pin: 0x8c3eb1…48a95
Contract: 0x78406c32…38B1e