
Indurimento della catena di fornitura Layer-2 per server MCP — manifesti degli strumenti firmati con Ed25519, attestazione di spawn runtime, sanitizzatore di argomenti default-deny. Difende contro l'avvelenamento del marketplace + CVE-2025-69256 + CVE-2025-61591.
<!-- studiomeyer-mcp-stack-banner:start --> > **Parte dello [StudioMeyer MCP Stack](https://studiomeyer.io)** — Costruito a Maiorca 🌴 · ⭐ se lo usi <!-- studiomeyer-mcp-stack-banner:end --> # mcp-server-attestation <!-- badges --> [](https://www.npmjs.com/package/mcp-server-attestation) [](https://www.npmjs.com/package/mcp-server-attestation)    <!-- /badges --> Rafforzamento della supply chain di Layer-2 per i server Model Context Protocol. Manifest degli strumenti firmati con Ed25519, attestazione runtime degli spawn, sanitizer degli argomenti con negazione predefinita. Risposta diretta a: - **OX Security marketplace-poisoning, Aprile 2026** — 9 degli 11 registri MCP hanno accettato server dannosi. Posizione pubblica di Anthropic: 'comportamento atteso'. - **CVE-2025-69256** — Serverless Framework MCP RCE tramite iniezione di comandi in `child_process.exec()`. - **CVE-2025-61591** — Cursor MCP RCE tramite server dannoso installato via OAuth con dirottamento degli spawn. Questo pacchetto fornisce ciò che Anthropic ha scelto di non fornire: verifica crittografica di quali strumenti un server può esporre e quali chiamate di spawn può effettuare. È una dipendenza plug-and-play, non un sostituto runtime. ## Una nota da parte nostra Costruiamo strumenti e sistemi per noi stessi da due anni. Il fatto che questa repo sia piccola e abbia poche stelle non è perché è nuova. È perché abbiamo deciso solo ora di condividere ciò che abbiamo costruito. Non è un esperimento fresco, è una lunga storia con un commit recente. Amiamo costruire cose e condividerle. Non amiamo le tattiche dei social media, i growth hack o inseguire stelle e follower. Quindi questa repo è piccola. Il codice è reale, viene utilizzato, le issue ricevono risposta. Giudica tu stesso. Se ti aiuta, condividere, testare e dare feedback ci aiuta. Se potrebbe essere migliore, un'issue è più utile. Se ci costruisci qualcosa sopra, diccelo a [email protected]. Ci rallegra davvero la giornata. Da un piccolo studio a Palma di Maiorca. ## Pacchetti (npm workspaces) | Package | Scopo | | --- | --- | | `mcp-server-attestation` (`packages/lib`) | Libreria: firma/verifica Ed25519, schema manifest, sanitizer, attestatore spawn, trust store TOFU. | | `mcp-attest-cli` (`packages/cli`) | CLI `mcp-attest`: `keygen`, `sign`, `verify`, `inspect`, `fingerprint`, `check-pin`. | | `mcp-attest-demo` (`packages/demo-server`) | Server MCP di riferimento (stdio, specifica 2025-06-18) che espone 5 strumenti che dimostrano la libreria. | ## Installa ```bash npm install mcp-server-attestation # CLI: npm install -g mcp-attest-cli # Server MCP di riferimento: npx mcp-attest-demo ``` Node 20+. Nessuna dipendenza crittografica esterna — utilizza le primitive Ed25519 di `node:crypto`. ## Avvio rapido del server in cinque righe ```ts import { verifyManifestStrict, attestSpawnStrict, type SignedManifest } from "mcp-server-attestation"; import signed from "./signed/manifest.json" assert { type: "json" }; // 1. All'avvio: dimostra che il manifest che spedisci è quello che hai firmato. verifyManifestStrict(signed); // 2. Prima di ogni child_process.spawn: attestSpawnStrict(signed as SignedManifest, { command, args }); ``` Questa è l'intera integrazione. Due chiamate di funzione, nessun SaaS, nessun demone. Se preferisci riverificare la firma ad ogni spawn (difesa in profondità contro un manifest non verificato o scambiato che raggiunge il gate), usa invece la singola chiamata fail-safe — verifica *poi* attesta: ```ts import { attestSpawnVerified, type SignedManifest } from "mcp-server-attestation"; attestSpawnVerified(signed as SignedManifest, { command, args }); ``` ## Strumenti (server di riferimento `mcp-attest-demo`) | # | Nome | readOnlyHint | destructiveHint | | - | ---- | ------------ | --------------- | | 1 | `attest_verify_manifest` | true | false | | 2 | `attest_inspect_spawn` | true | false | | 3 | `attest_generate_manifest_template` | true | false | | 4 | `attest_sign_manifest` | false | false | | 5 | `attest_keygen` | false | false | Le annotazioni sono oneste: `attest_sign_manifest` e `attest_keygen` scrivono file su disco, quindi non sono di sola lettura, ma non distruggono dati esistenti, quindi destructiveHint rimane false. Vedi `docs/THREAT-MODEL.md` per la tabella delle capacità per strumento. ## CLI ```bash mcp-attest keygen --out-dir ./keys --name prod mcp-attest sign --manifest manifest.json --private-key keys/prod.key --out signed.json mcp-attest verify --signed signed.json --pin # TOFU pin mcp-attest verify --signed signed.json --sigstore # cross-ref Rekor opzionale mcp-attest inspect --signed signed.json --command /usr/bin/echo --arg "hello" mcp-attest fingerprint --public-key keys/prod.pub mcp-attest check-pin --server my-server --signed signed.json ``` `verify` esce con codice 2 su firma errata, codice 3 su mancata corrispondenza del pin. ## Compatibilità con la specifica MCP | Versione specifica | Stato | | --- | --- | | 2024-11-05 | analizzabile nel manifest, non obiettivo del server di riferimento | | 2025-03-26 | analizzabile nel manifest, non obiettivo del server di riferimento | | 2025-06-18 | obiettivo completo | La libreria è indipendente dal trasporto. Il server di riferimento è solo stdio. ## Modello di sicurezza - **Trust-on-First-Use** è l'impostazione predefinita. La prima volta che verifichi un server, la sua chiave pubblica viene fissata a `~/.mcp-attest/trust.json` (sovrascrivi: `MCP_ATTEST_TRUST_FILE`). Le verifiche successive rifiutano qualsiasi nuova chiave per lo stesso nome server con `TRUST_PIN_MISMATCH`. Questo intercetta il vettore di aggiornamento dannoso stile Cursor. - **Nessuna lista di chiavi fidate inclusa.** Questo pacchetto non funge da gatekeeper. Se desideri una garanzia più forte, opta per `--sigstore` per incrociare l'impronta della chiave pubblica con il registro di trasparenza Sigstore Rekor. - **Sanitizer degli argomenti con negazione predefinita.** `shellSafeString` blocca ogni metacarattere shell ASCII, NUL, CR, LF, VT, FF, NEL, caratteri a larghezza zero, BOM, override RTL/LTR, isolati Trojan-Source, e confondibili fullwidth-Latin. Il comportamento di allowlist richiede i tipi di regole esplicite `regex` / `enum` / `prefix` / `literal`. - **Regole `regex` sicure contro ReDoS.** Il pattern di una regola `regex` è firmato dall'autore, ma il valore dell'argomento è controllato dall'attaccante. Il sanitizer rileva staticamente i pattern soggetti a backtracking (quantificatori innestati illimitati come `(a+)+`) e si rifiuta di eseguirli, quindi un singolo argomento malformato non può bloccare il percorso caldo dello spawn. Le regole `regex` hanno anche un limite massimo di input `maxLength` (default 4096). - **Regole `prefix` sicure contro traversal.** Le regole `prefix` rifiutano i componenti di percorso `..` per impostazione predefinita (`denyTraversal: true`, inclusa la forma codificata `%2e%2e`), quindi `/safe/../../etc/passwd` viene bloccato anche se soddisfa `prefix: "/safe/"`. - **Verifica poi attesta.** `attestSpawnVerified` controlla la firma del manifest prima di attestare lo spawn in un'unica chiamata fail-safe — usala invece di `attestSpawnStrict` a meno che tu non abbia misurato la verifica Ed25519 per spawn fuori da un ciclo realmente caldo. - **JSON canonico** è la superficie firmata. La riserializzazione non può modificare i byte firmati. Cosa questo pacchetto NON fa (fuori ambito): - Isolare o containerizzare il processo server. - Indurimento del flusso OAuth (build separata `mcp-oauth-shield`). - Controllo del traffico di rete in uscita. - Auto-patch dei server esistenti. ## Test ```bash npm install npm run typecheck npm test ``` Il corpus di test include fixture di replay CVE (`packages/lib/tests/fixtures/cve-2025-69256-payloads.json`, `cve-2025-61591-payloads.json`). La compilazione è un controllo di regressione: ogni payload deve essere bloccato. ## Distribuzione - Pubblicazione npm tramite GitHub Actions OIDC con `--provenance`. - Server di riferimento inviato a mcp.so e FastMCP Directory. - Libreria pubblicata separatamente come `mcp-server-attestation`. ## Informazioni su StudioMeyer [StudioMeyer](https://studiomeyer.io) è uno studio di AI e design con sede a Palma di Maiorca, che lavora con clienti in tutto il mondo. Costruiamo siti web personalizzati e infrastrutture AI per piccole e medie imprese. Stack di produzione su Claude Agent SDK, MCP e n8n, con Sentry, Langfuse e LangGraph per l'osservabilità e un layer di protezione interno. ## Licenza MIT, Copyright 2026 Matthias Meyer (StudioMeyer). Vedi `LICENSE`.