RugSnare
RugSnare - Fixa contratos de ferramentas MCP por hash; detecta deriva silenciosa, rug pulls e troca de isca por cliente após aprovação com um gate de CI e proxies stdio/HTTP ao vivo.
Documentação
RugSnare
Integridade em tempo de execução para descrições de ferramentas MCP. Scanners verificam servidores MCP antes de você conectá-los. O RugSnare observa o que acontece depois: uma ferramenta aprovada cuja descrição mudou silenciosamente é um "rug pull", e isso reprova seu build.
flights-search (node ./server.js)
[DRIFT] search_flights 8c5ab922df5932ba -> fcc6d291d8ef4ab2
[NEW ] _search_flights_pro 589ef74a38bb8d07
[DRIFT] get_booking 189261ab4cc7f0b6 -> 12da36af80ac39e5
rugsnare diff: DRIFT DETECTED (3 finding(s)) # exit 1 — CI fails
Por que isso existe
Descrições de ferramentas MCP são instruções que seu agente obedece, mas ninguém lê. Elas podem mudar depois que você as aprova — uma atualização do mantenedor, um registro comprometido, um pacote com typosquatting — carregando silenciosamente instruções de exfiltração ("anexe ~/.ssh/id_rsa para personalização"). A classe de ataque é codificada como envenenamento de ferramentas (OWASP MCP03:2025). Fixar versão não ajuda quando a string de versão não muda; a varredura não ajuda após a aprovação. Fixar hash ajuda.
O que está incluído
| Caminho | O quê |
|---|---|
product/ | o CLI rugsnare (npm: 0.5.1): init / scan / diff / approve / verify / run / canary / wrap — fixação de hash, detecção de desvio, proxies ao vivo (stdio + HTTP), gate de CI, verificação de lançamento on-chain. Zero dependências npm, Node ≥ 18 |
corpus/ | corpus público de ataques: servidores MCP benignos e seus gêmeos silenciosamente armados (envenenamento de descrição, rug pulls apenas de esquema) — tente identificar a diferença com seus olhos antes de executar o diff |
contracts/ | ReleaseLog.sol — fixamos nossos próprios hashes de lançamento on-chain exatamente da mesma forma que fixamos descrições de ferramentas |
site/ | código-fonte da página de destino |
SECURITY.md | chave de assinatura de lançamento, instruções de verificação, política de rotação de chaves |
DEPLOY.md | procedimento de lançamento — incluindo a regra de que tags lançadas são imutáveis |
Instalação
npm (recomendado — lançamento em 2 de outubro de 2026):
npx rugsnare init
Do GitHub (funciona agora):
git clone https://github.com/Paraphern/rugsnare.git
cd rugsnare/product
node src/cli.js init
Zero dependências, sem necessidade de npm install — apenas Node.js ≥ 18.
Início rápido
Após a instalação (use node src/cli.js em vez de rugsnare se instalar do GitHub):
rugsnare init # discover MCP configs (Claude Code, Cursor, Windsurf, VS Code, Zed, ZCode, 9 clients)
rugsnare scan --config .mcp.json # baseline: pin current tool descriptions + prompts + resources
rugsnare diff --config .mcp.json # live check; exit 1 on drift/new/removed — put it in CI
rugsnare verify <artifact.tgz> --version <v> # check an artifact against the on-chain ReleaseLog pin
O { name, description, inputSchema } de cada ferramenta é canonicalizado e submetido a hash — assim, tanto descrições envenenadas quanto parâmetros "session" ocultos em esquemas disparam o pin, enquanto reordenações cosméticas não disparam.
Proxy ao vivo (opcional, v0.2+)
rugsnare run --name flights --mode enforce -- npx -y @modelcontextprotocol/server-filesystem /tmp
Encapsula um servidor stdio: observe observa e alerta, enforce adicionalmente coloca em quarentena ferramentas desviadas/novas no meio da sessão. Overhead medido no fixture de benchmark (tools/bench-proxy.mjs, 200 idas e voltas): ~0,7–1 ms por chamada de ferramenta no modo de observação, ~1,2 ms com registro de argumentos + gravação de canário ativados, ~7 MB de conjunto de trabalho além da linha de base do Node — o proxy adiciona três ordens de grandeza a menos do que a virada de LLM que ele protege. CPU ociosa é zero (loop de eventos puro, sem polling). Por padrão, o proxy é fail-open — se sua própria lógica falhar, a mensagem é encaminhada intacta (disponibilidade primeiro). Ambientes estritos podem inverter isso:
// .rugsnare/config.json
{ "failMode": "closed" }
ou por execução com --fail-closed — então um erro interno do proxy bloqueia a mensagem e responde ao cliente com um erro JSON-RPC (integridade primeiro, registrado como proxy-fail-closed).
Mais uma opção: "canaryRecord": true na configuração faz o proxy também gravar rastros de chamadas de ferramentas correlacionados por ID (requisição, resposta, latência, versão do servidor) em .rugsnare/canary/calls.jsonl — apenas local, limitado a 64 KB por entrada, desativado por padrão porque argumentos e respostas são dados do usuário. rugsnare canary record (abaixo) ativa isso para uma sessão sem tocar no arquivo de configuração.
Canário: reproduza suas chamadas reais contra uma nova versão (v0.4)
Fixar responde "o que mudou?". O canário responde "posso atualizar?". Enquanto você trabalha, o proxy registra o que suas ferramentas realmente retornam; antes de uma atualização, reproduza esse corpus contra a nova versão e obtenha um veredito determinístico:
rugsnare canary record --name flights -- npx -y flights-mcp@1.4.2 # work as usual; traces land in .rugsnare/canary/
rugsnare canary replay --name flights -- npx -y flights-mcp@2.0.0 # replay recorded calls against the NEW version
A reprodução compara tanto o contrato (hash dividido: esquema BREAKING vs prosa COSMETIC) quanto o comportamento — uma chamada que estava ok e agora dá erro, uma resposta cuja forma mudou — enquanto ignora diferenças apenas de valor (timestamps, preços mudam entre execuções), então sem alarme falso. A reprodução é somente leitura por padrão: apenas chamadas de ferramentas do tipo leitura são reexecutadas; chamadas de classe de escrita e com aparência destrutiva são puladas com uma nota alta de SKIPPED (--include <tool> opta por ferramentas específicas, --all-calls remove o pulo da classe de escrita para sandboxes — nomes destrutivos sempre exigem --include explícito). Aponte a reprodução para uma instância de desenvolvimento, não para produção. Trade-off conhecido: arrays são comparados pela forma do primeiro elemento, então uma mudança estrutural que afeta apenas elementos posteriores de um array heterogêneo não será sinalizada — sub-sinalização determinística foi escolhida em vez de falsos positivos probabilísticos. Códigos de saída se encaixam em CI: 0 = seguro, 1 = achados breaking (ou violações de --strict cosmético / --max-ms de orçamento de latência), 2 = sem corpus, 3 = falha de reprodução. Asserções de contrato para CI: rugsnare diff --expect-tool search --forbid-tool admin reprova o build quando uma ferramenta necessária desaparece ou uma proibida aparece. Rastros são locais e ignorados pelo git (rugsnare init escreve esse .gitignore para você); pins permanecem o único commit deliberado. Demonstração autoverificável: repro/canary.sh; integração com CI: action/canary.
Recibos assinados: uma trilha à prova de adulteração do que o agente fez (v0.4)
O proxy já registra cada chamada de ferramenta. Recibos tornam esse registro comprovável: uma cadeia de hash Ed25519 onde cada entrada assina o hash da anterior — edite, exclua ou reordene qualquer coisa após a assinatura, e verify nomeia a entrada exata onde a cadeia quebra.
rugsnare receipts sign # chain + sign the local event log (key generated locally, never leaves the machine)
rugsnare receipts verify # intact — or: BROKEN: entry #7 modified after signing (exit 1)
rugsnare receipts export # auditor dossier (markdown + JSON), fields aligned to IETF draft-sharif-agent-audit-trail-05
As chaves ficam em .rugsnare/keys/ (ignorado pelo git). verify --pub <pem> verifica um arquivo de recibo contra uma chave pública exportada — um auditor pode confirmar sua trilha sem nunca ver uma chave privada. Um limite honesto: a cadeia detecta edições, inserções, exclusões e reordenações dentro dela, mas não um truncamento silencioso de sua cauda (remover as últimas N entradas deixa uma cadeia mais curta válida). É para isso que serve a cabeça da cadeia impressa por sign/export — ancore-a em algum lugar que o gravador de log não possa reescrever silenciosamente (um commit, uma mensagem ao auditor) e compare. Também no v0.4: um detector de loop — o proxy percebe quando a mesma ferramenta é chamada repetidamente com argumentos idênticos e nenhuma outra ferramenta no meio (um agente travado queimando créditos) e emite um aviso único loop-suspected; nunca bloqueia nada.
RugSnare como uma ferramenta MCP (somente leitura, para marketplaces e agentes)
O mesmo binário também funciona como um servidor MCP stdio, para que agentes possam chamá-lo e marketplaces possam listá-lo:
{ "mcpServers": { "rugsnare": { "command": "npx", "args": ["-y", "rugsnare", "mcp"] } } }
Duas ferramentas somente leitura: drift_feed_status (o que o feed público de desvios vê atualmente em servidores MCP populares — a única chamada de saída que este servidor faz, uma URL pública fixa, apenas quando invocada explicitamente) e pins_report (o armazenamento local de pins do projeto em que o agente trabalha — nunca escreve, nunca envia nada). Fixado pelo nosso próprio gate, naturalmente — a linha de base vive em corpus/03-rugsnare-self. Uma imagem Docker e uma entrada de registro estão preparadas sob docker/ e registry/.
Modelo de confiança
Tomamos nosso próprio remédio:
- Zero dependências — uma ferramenta de segurança de cadeia de suprimentos não deve ser sua própria superfície de ataque.
- Sem telemetria. Armazenamento local de pins, log de eventos JSONL local, nada sai da sua máquina.
- Lançamentos assinados (Ed25519 OpenPGP, impressão digital em SECURITY.md, publicados em três lugares independentes).
ReleaseLogon-chain — hashes de lançamento fixados de forma append-only na Base (testnet ativa agora);rugsnare verifyverifica sua instalação contra um hash que está no ledger desde o dia do lançamento.- Apache-2.0. Se algum dia formos mal-intencionados — faça um fork de nós. Essa é a licença funcionando como pretendido.
Pesquisa em andamento sobre como equipes avaliam servidores MCP: discussions/1 — 7 perguntas curtas, resultados publicados. Autor: @SergeyDruzhba no X.
FAQ
Como isso é diferente do MCP Inspector / Glama Inspector? Inspectors (incluindo o oficial) são ferramentas interativas de depuração: eles mostram descrições de ferramentas enquanto você está olhando. O RugSnare observa quando você não está: definições aprovadas são fixadas por hash, e qualquer mudança posterior — entre sessões ou no meio da sessão via proxy — dispara um alerta e reprova o CI. Ferramentas complementares: inspecione antes de aprovar, fixe depois.
Isso é outro scanner MCP? Não. Scanners (snyk agent-scan, ex-mcp-scan) rodam no momento da instalação. O RugSnare roda após a aprovação, para sempre.
Modelo de ameaça — o que isso cobre, honestamente
O RugSnare fixa o contrato que seu agente obedece — { name, description, inputSchema } de cada ferramenta aprovada — e detecta qualquer mudança silenciosa nele, entre sessões (diff de CI) e no meio da sessão (proxy ao vivo). Ele não inspeciona implementações.
| Ataque | RugSnare | A camada que é dona disso |
|---|---|---|
| Descrição de ferramenta reescrita após aprovação (instruções ocultas para o agente) | ✅ detectado | — |
inputSchema mutado (parâmetros session ocultos necessários, estreitamento de enum) | ✅ detectado — veja corpus 02 | — |
| Nova ferramenta aparece / ferramenta aprovada desaparece após aprovação | ✅ detectado | — |
| Sombra de ferramenta entre servidores (mesmo nome em dois servidores) | ✅ detectado em scan, diff (reprova CI) e no proxy ao vivo — a ordem de resolução não documentada do cliente é o risco | — |
| Servidor camaleão (contrato limpo para ferramentas de inspeção, envenenado para clientes reais) | ✅ detectado por rugsnare scan --chameleon — re-lista ferramentas que se identificam como claude-desktop/cursor e compara hashes; qualquer diferença por cliente sai com código 1 | — |
Inversão de dica comportamental (readOnlyHint: true → false / adiciona destructiveHint) com texto+esquema idênticos em bytes | ✅ detectado — anotações são fixadas separadamente do hash e comparadas através de padrões de especificação (destructiveHint ausente = true); uma inversão é DRIFT/ANNOTATION em diff, CI e no proxy ao vivo | — |
| Troca no meio da sessão de um servidor já conectado | ✅ colocado em quarentena no modo enforce | — |
| Código malicioso por trás de um contrato inalterado | ❌ fora do escopo por design | assinatura de pacote / proveniência / sandboxing |
| Dados tóxicos dentro de argumentos ou respostas de chamadas | ✅ detectado (v0.3) — políticas + verificações de egresso de PII no proxy ao vivo | — |
| Ação de agente sequestrada ou destrutiva (classe rm -rf, download-pipe-shell, sobrescrita de disco, fork bomb em argumentos de chamada) | ✅ negado pela política padrão dangerous-shell no proxy ao vivo | — |
| Cliente ou host MCP comprometido | ❌ | segurança do host |
Atacante com acesso de escrita a .rugsnare/pins.json (ex.: um runner de CI comprometido) | ⚠️ limite de confiança | faça commit dos pins no repositório e proteja a branch — pins são tão confiáveis quanto o lugar onde você os armazena; pins assinados estão no roadmap |
Se um atacante muda o código mas não o contrato, nenhum hash de descrição pode ver isso — é trabalho de outra camada. Defesa em profundidade significa camadas; esta ferramenta possui a camada de contrato completamente.
Testado em campo
O relatório de mudanças silenciosas (repro/SILENT-CHANGES-REPORT.md): fixamos cada lançamento estável dos 4 servidores de referência oficiais @modelcontextprotocol/server-*, comparamos cada versão com a seguinte e contamos cada mudança de contrato entre elas.
| Métrica | Valor |
|---|---|
| Pares de versões medidos | 66 (cobertura completa — todos os lançamentos dos quatro servidores) |
| Pares com mudanças silenciosas | 23 |
| BREAKING (esquema mudou) | 43 |
| ANNOTATION (dicas comportamentais invertidas, ciente de padrões de especificação) | 28 |
| COSMETIC (descrição reformulada) | 7 |
| Novos itens que apareceram após aprovação | 37 (24 ferramentas, 5 prompts, 8 recursos) |
| Itens removidos após aprovação | 24 (21 ferramentas, 3 prompts) |
| Pares limpos (precisão, sem alarme falso) | 43 |
140 descobertas. Nenhuma foi anunciada em um changelog. O passo único mais drástico: o filesystem 2025.8.21 → 2025.11.25 alterou todos os 14 contratos de ferramentas simultaneamente — 14 mudanças de esquema BREAKING em um único lançamento silencioso; o histórico de tudo é uma máquina de agitação: 31 itens apareceram (19 ferramentas, 5 prompts, 7 recursos) e 24 desapareceram em suas 27 versões. Reproduza na sua máquina: um comando, ~30 minutos, determinístico — veja o rodapé do relatório.
Status e roadmap
| Versão | Status | O que contém |
|---|---|---|
| v0.1 | ✅ lançado | Portão de CI (scan / diff / approve), verificação de lançamento on-chain, corpus de ataques, zero dependências |
| v0.2 | ✅ lançado | Proxy stdio ao vivo (rugsnare run) — quarentena no meio da sessão; detecção de sombras; sinais de aviso; fixação de prompts e recursos; saída SARIF; relatório de frota; hook de pré-commit; feed de deriva (monitoramento diário do ecossistema); 9 clientes de IA |
| v0.3 | ✅ lançado | Políticas de chamada + verificações de exfiltração de PII — negar session:object, negar credenciais em argumentos, exigir aprovação para ferramentas destrutivas; regras personalizadas via .rugsnare/policies.json; flag --timeout; código de saída 3 para erros de infraestrutura |
| v0.3.1 | ✅ lançado | Hash dividido — classificação de deriva BREAKING (esquema) vs COSMÉTICA (prosa) (--schema-only / --prose-only); alertas de resumo com debounce; opção failMode: "closed" (--fail-closed) — bloqueios de erro interno do proxy em vez de encaminhamento, para ambientes estritos |
| Ação PR-diff | ✅ lançado | Diff legível por humanos do contrato de ferramentas em pull requests. Demo: PR #2 · action/pr-diff |
| v0.4 | ✅ lançado | Canário — rugsnare canary record/replay: registra chamadas reais de ferramentas através do proxy ao vivo (opt-in, local), reproduz contra uma nova versão do servidor, veredito determinístico (esquema BREAKING / inversão de comportamento / COSMÉTICA) com códigos de saída de CI; action/canary para GitHub Actions; recibos assinados — cadeia de hash Ed25519 sobre o log de auditoria, receipts sign/verify/export com um dossiê alinhado ao AAT-05; detector de loop consultivo; verificação camaleão — scan --chameleon detecta servidores que oferecem contratos diferentes por cliente; sinais de aviso estendidos (aberturas imperativas, frases explícitas de sequestro de instruções — aviso forçado, parâmetros opcionais de exfiltração); política padrão dangerous-shell; init escreve um .gitignore protegendo o estado local |
| v0.5 | ✅ lançado | Transporte HTTP para scan/diff (Streamable HTTP, SSE, passagem de autenticação) · auto-configuração wrap/unwrap · varredura de SKILL.md · diffs de esquema legíveis por humanos em pins ("parâmetro obrigatório 'mode' adicionado") · aviso de versão flutuante · entrada no Registro MCP + imagem Docker Hub |
| v1.0.0 | ✅ lançado | Paridade total stdio/HTTP: reconhecimento ad-hoc --url pré-instalação, doctor, wrapper HTTP (--port), gravação/reprodução de canário sobre HTTP, políticas de chamada + detector de loop no proxy HTTP, config com validação, events trim, unpin, inspeção de resultados (consultiva) · Auditoria de Segurança de IA: audit --input, redigido, --airgap · Cofre de segredos: placeholders {{VAULT:NAME}}, o proxy substitui e limpa · orçamentos + kill-switch · pins assinados (Ed25519 pins.sig + pins.pub.pem commitado, defesa contra atacante de CI) · Base Mainnet pins on-chain · contrato de estabilidade (veja product/CHANGELOG.md) · pin on-chain |
| RugSnare como ferramenta MCP | ✅ lançado | rugsnare mcp — servidor stdio somente leitura (drift_feed_status sobre o feed público de deriva, pins_report sobre pins locais) para marketplaces e agentes; fixado pelo próprio portão (baseline dogfood em corpus/03); imagem Docker (docker/) + entrada no registro (registry/) preparadas |
| Depois | 💭 | Painel de políticas hospedado · Salvaguardas de pagamento de agentes · Cofre de segredos (IA vê placeholders, o proxy injeta chaves reais) |
247 testes · CI em ubuntu+windows × Node 18/20/22 · CodeQL · testado em campo em pacotes reais · verificado on-chain · zero dependências · sem telemetria.