
Host-agnostico hook di sicurezza pre-scrittura per agenti di codifica: rileva pattern di input utente tramite Semgrep ed emette una guida di sicurezza deterministica, senza LLM.
Un checkpoint di sicurezza per gli strumenti di AI per programmare. Esamina ogni file che un assistente AI scrive e ferma quelli pericolosi prima che arrivino sul disco.
Gli assistenti AI per programmare (Claude Code, Codex, …) scrivono codice velocemente — incluso codice che gestisce cose come password, email, chiavi API o input utente grezzo. Per un assistente è facile cablare quei dati direttamente in una query di database, un comando shell o una risposta HTTP senza pensare alla sicurezza.
VibeGate si frappone tra l'assistente e il tuo filesystem. Ogni volta che l'assistente prova a scrivere o modificare un file, VibeGate analizza prima il nuovo codice:
Nessun LLM è coinvolto nell'analisi stessa — è un'analisi statica veloce e deterministica, quindi non inventa mai nulla e non costa token.
Ecco tutto ciò che VibeGate attualmente controlla:
L'elenco completo e aggiornato si trova in guidance.TECHNICAL_RISKS e formatter.BLOCKING_CATEGORIES, nel caso questa tabella dovesse diventare obsoleta.
┌───────────────────────────────────┐
│ Chiedi a Claude Code di │
│ scrivere o modificare un file │
└───────────────┬───────────────────┘
│
▼
┌───────────────────────────────────┐
│ Claude Code prova a salvare │
│ il file (strumento Write/Edit) │
└───────────────┬───────────────────┘
│
▼
┌───────────────────────────────────┐
│ Hook di VibeGate │
│ (viene eseguito automaticamente, │
│ prima che il file venga salvato)│
└───────────────┬───────────────────┘
│
analizza il nuovo codice con Semgrep
│
┌─────────────────────┼─────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────────────┐
│ Nessun input │ │ Input rischioso, │ │ Input rischioso │
│ rischioso trovato │ │ ma rischio basso │ │ raggiunge un sink │
│ │ │ (es. mostrato in │ │ critico │
│ │ │ una risposta HTTP) │ │ (SQL/comando/RCE, │
│ │ │ │ │ template injection) │
└──────────┬───────────┘ └──────────┬──────────┘ └─────────────┬────────────┘
│ │ │
▼ ▼ ▼
File salvato, File salvato, File NON salvato.
nulla mostrato. più un avviso nel Claude Code vede
terminale con il il motivo del blocco
rischio e come e sa cosa deve
risolverlo. correggere.
In breve: il codice sicuro passa inalterato, il codice rischioso ma sopportabile viene salvato con un avviso, e il codice che è a un passo da cose come SQL injection, command injection o esecuzione di codice remoto viene fermato prima di arrivare sul disco.
Se VibeGate stesso incontra un errore imprevisto, lascia sempre passare la scrittura — un bug nell'hook non dovrebbe mai essere il motivo per cui il tuo lavoro viene bloccato.
Ogni avviso e blocco include anche un’istruzione esplicita che dice a Claude Code di menzionare il risultato nella sua risposta, non di correggerlo in silenzio. Questo rende visibile l'attività di VibeGate nella conversazione, non solo in un log del terminale che dovresti cercare.
| Cosa vede VibeGate | Cosa succede |
|---|---|
| Nessun input utente, o un linguaggio non ancora supportato | Il file viene salvato normalmente, nulla mostrato |
| Input utente trovato, ma il rischio è moderato (es. reindirizzamento aperto, mass assignment) | Il file viene salvato, il terminale mostra un avviso + guida |
| L'input utente fluisce non sanitizzato in un sink critico (query SQL/NoSQL, comando shell, motore di template, deserializzatore, parser XML, percorso file, nome di file caricato o output HTML grezzo) |
Vedi la tabella in "Che problema risolve?" qui sopra per la suddivisione completa controllo per controllo di cosa blocca e cosa solo avvisa.
Oggi VibeGate supporta Python, JavaScript/TypeScript, Go, Java, PHP e Ruby, e si integra con Claude Code e Codex. Altri linguaggi e strumenti possono essere aggiunti senza toccare la logica principale.
Controlla anche i file di workflow di GitHub Actions per due comuni errori della supply chain CI/CD: azioni fissate a un tag mutabile (@v4) invece di un commit SHA, e il trigger non sicuro pull_request_target. Entrambi generano un avviso anziché un blocco, poiché sono controlli di hardening e non prova di un exploit attivo.
Ecco una registrazione reale di Claude Code mentre crea da zero un'app per la lettura di feed RSS, con VibeGate in esecuzione per tutto il tempo. Osserva i momenti in cui Claude Code si ferma e dice esplicitamente cosa VibeGate ha segnalato, e perché, prima di continuare — incluso un vero rischio SSRF nel codice di recupero del feed che corregge al volo.
Ecco un secondo esempio, come immagine fissa: Claude Code sta creando un'app che permette alle persone di caricare una foto e vederne i dettagli. VibeGate nota che il nome del file e altri dettagli del file verranno poi mostrati a schermo, e avvisa che questo potrebbe essere usato per iniettare codice dannoso nella pagina (questo si chiama XSS). Claude Code adatta il codice in modo che le informazioni siano mostrate in modo sicuro.
In entrambi i casi, nulla è stato bloccato senza motivo, e nessuno ha dovuto leggere il codice riga per riga per cogliere il problema. VibeGate lo ha rilevato nel momento in cui il file è stato scritto, e l'AI lo ha corretto sul posto.
Ci sono due modi per fare in modo che un assistente AI scriva codice più sicuro. Un modo è caricare un grande set di istruzioni sulla scrittura di codice sicuro nella conversazione prima che inizi, ad esempio una checklist che copre SQL injection, XSS, gestione delle password, caricamento di file e altro. L'altro modo è quello che fa VibeGate: controllare il codice automaticamente, proprio quando un file viene scritto, e parlare solo quando qualcosa è effettivamente sbagliato.
Il primo approccio costa token su ogni singolo messaggio, che siano necessari o meno. Una tipica checklist per la scrittura di codice sicuro che copre diverse categorie di rischio può facilmente aggiungere qualche migliaio di token. Se un assistente AI scrive 50 file in una sessione, e quella checklist viene ricaricata o mantenuta nel contesto ogni volta, potresti pagare ben oltre centomila token di consigli che, il più delle volte, non si applicano al file che si sta scrivendo in quel momento. Una pagina di login e un semplice file di costanti di colore non hanno bisogno degli stessi avvisi, ma una checklist caricata non può distinguerli in anticipo.
VibeGate inverte questa logica. Rimane in silenzio, e non costa nulla in più, per ogni file che non contiene pattern rischiosi. Solo quando trova qualcosa, come input utente che fluisce in una query di database, aggiunge una nota breve e specifica su quel singolo problema, di solito una piccola frazione delle dimensioni di una checklist completa. Quindi invece di pagare un costo fisso di token per ogni file indipendentemente dal contenuto, paghi un costo piccolo solo per i file che richiedono effettivamente attenzione, e quel costo è mirato esattamente al problema trovato, non a una lezione generale sulla sicurezza.
Questo rende anche le indicazioni più affidabili. A un assistente AI a cui viene chiesto di "tenere a mente la sicurezza" mentre scrive cento righe di codice può semplicemente sfuggire una riga rischiosa tra molte. Un gate non si stanca né si distrae: controlla ogni singola scrittura, ogni volta, usando le stesse regole fisse.
Installalo una volta — questo installa anche Semgrep, da cui VibeGate dipende:
pipx install git+https://github.com/theMiddleBlue/vibegate
Poi attivalo all'interno del progetto che vuoi proteggere:
cd tuo-progetto
vibegate on # attiva qui (ricarica Claude Code dopo)
vibegate status # verifica se è attivo per questo progetto
vibegate off # disattiva qui
vibegate on aggiunge un hook PreToolUse per Write|Edit|MultiEdit nel file .claude/settings.local.json di quel progetto. È limitato per progetto, quindi attivarlo in un repository non influisce sugli altri.
Claude Code esegue l'hook come vibegate run --host claude_code — non sono coinvolti percorsi assoluti, quindi continua a funzionare anche se reinstalli o sposti le cose.
vibegate status mostra anche un registro cronologico di ciò che VibeGate ha effettivamente rilevato in questo progetto — ogni avviso e blocco, con file, riga e categoria — in modo da poter vedere la sua attività nel tempo invece di sapere solo se è attivo:
$ vibegate status
█ █ █████ ████ █████ ████ ███ █████ █████
...
● VibeGate è ABILITATO in .claude/settings.local.json
Attività recente (ultimi 2 di 2 registrati, più recenti per primi):
2026-07-02T17:35:48+00:00 ⛔ BLOCCATO server.py:3 EXEC_INPUT (FREE_TEXT)
2026-07-02T17:35:46+00:00 ⚠ AVVISATO app.py:2 HTTP_BODY (EMAIL)
Questo registro si trova in .vibegate/activity.jsonl nella root del progetto — aggiungilo al tuo .gitignore, è uno stato locale dello sviluppatore, non qualcosa da committare.
VibeGate capisce con quale host sta comunicando in quest'ordine: un flag esplicito --host <nome>, poi la variabile d'ambiente VIBEGATE_HOST, poi il rilevamento automatico dal payload ricevuto, con fallback a claude_code.
Se VibeGate segnala qualcosa che hai deliberatamente deciso essere sicuro, aggiungi un commento vibegate-ignore sulla stessa riga — funziona con qualsiasi sintassi di commento (#, //, …), dato che VibeGate cerca solo il testo:
query = f"SELECT * FROM users WHERE id = {user_id}" # vibegate-ignore
Per sopprimere solo categorie specifiche invece di tutto sulla riga, elencale dopo i due punti (corrisponde sia alla categoria tecnica che al tipo semantico, separato da virgole, case-insensitive):
query = f"SELECT * FROM users WHERE id = {user_id}" # vibegate-ignore: DB_QUERY
src/vibegate/
├── hook.py # punto di ingresso
├── cli.py # comandi on/off/status + banner ASCII
├── activity_log.py # persiste avvisi/blocchi in .vibegate/activity.jsonl
├── colors.py # codici colore ANSI condivisi (report + banner CLI)
├── core.py # pipeline indipendente dall'host
├── models.py # InputEvent / ClassifiedFinding / AnalysisResult
├── semgrep_runner.py # esegue Semgrep come sottoprocesso (fail-safe)
├── classifier.py # mappa regola Semgrep → categoria, nome variabile → tipo di dato
├── guidance.py # descrizioni statiche di rischio/soluzione
├── formatter.py # trasforma i risultati in un report per terminale + contesto host
├── adapters/ # base, claude_code, codex + un piccolo registro
└── rules/ # regole Semgrep — un file per linguaggio (Python, JS/TS,
# Go, Java, PHP, Ruby) più un placeholder generico
La pipeline stessa (core.py) non parla mai direttamente con un host specifico — tutto l'input/output specifico dell'host vive in adapters/, quindi aggiungere un nuovo host non richiede di toccare la logica di analisi.
semgrep --validate --config src/vibegate/rules/ # verifica che le regole siano valide
pytest tests/ # test unitari e di integrazione
Per vedere il funzionamento end-to-end senza Claude Code:
python3 -c 'import json; print(json.dumps({"tool_name":"Write","tool_input":{"file_path":"/tmp/t.py","new_content":"email = request.json.get(\"email\")"}}))' \
| python3 src/vibegate/hook.py --host claude_code
rules/<lingua>-user-input.yaml, registra i nuovi ID regola in classifier.RULE_TO_TECHNICAL, e mappa l'estensione del file in core.EXT_TO_LANGUAGE.classifier.VARNAME_TO_SEMANTIC e una descrizione in guidance.SEMANTIC_GUIDANCE.RULE_TO_TECHNICAL e una scheda in guidance.TECHNICAL_RISKS.adapters/ e registralo in adapters/__init__.py.codex è una mappatura iniziale, al meglio dello sforzo. Controlla il suo contratto di eventi rispetto alla tua versione di Codex prima di fare affidamento su di esso per bloccare qualcosa."requires login" invece della riga effettivamente corrispondente, quindi il classificatore ricostruisce il frammento stesso dal contenuto del file usando i numeri di riga.Edit/MultiEdit, l'adapter claude_code ricostruisce il file completo dopo la modifica dal disco, in modo che una sorgente contaminata e un sink introdotti da modifiche separate siano ancora connessi — ma vengono segnalati solo i risultati sulle righe che la modifica ha effettivamente toccato. Se un sink esiste già e una modifica successiva aggiunge solo la sorgente contaminata che lo raggiunge, questo non verrà rilevato (la riga del sink non faceva parte della nuova modifica). Questa ricostruzione è specifica di Claude Code; l'adapter codex non la fa ancora.| Controllo | Cosa rileva | Risultato |
|---|
| Iniezione di comandi | Input non sanitizzato raggiunge un comando shell | Blocca |
| SQL injection | Input non sanitizzato raggiunge una query al database | Blocca |
| NoSQL injection | Il corpo della richiesta viene usato direttamente come filtro del database | Blocca |
| Template injection (SSTI) | La sorgente del template stessa, non solo i suoi dati, proviene dall'input utente | Blocca |
| Deserializzazione non sicura | Dati non fidati raggiungono un deserializzatore non sicuro (pickle, YAML non sicuro, ...) | Blocca |
| Path traversal | Input non sanitizzato raggiunge una lettura, scrittura o cancellazione di file | Blocca |
| XXE | XML non fidato viene analizzato con entità esterne abilitate | Blocca |
| XSS | Input non sanitizzato viene renderizzato come HTML grezzo | Blocca |
| Caricamento file senza restrizioni | Il nome del file caricato viene usato per costruire il percorso di salvataggio | Blocca |
| SSRF | Il server recupera un URL che non è hardcodato | Avvisa |
| Reindirizzamento aperto | Una destinazione di reindirizzamento che non è hardcodata | Avvisa |
| Mass assignment | L'intero corpo della richiesta viene passato a un costruttore o aggiornamento di modello | Avvisa |
| Dati sensibili nel corpo di una richiesta | Email, password, token, ecc. letti dal corpo della richiesta | Avvisa |
| Dati sensibili in un URL/query | Email, password, token, ecc. letti dalla stringa di query | Avvisa |
| Dati sensibili nelle intestazioni | Email, password, token, ecc. letti dalle intestazioni della richiesta | Avvisa |
| Percorso file da input utente | Una variabile, non una stringa hardcodata, viene usata come percorso di file | Avvisa |
| Argomenti CLI | I dati provengono da argomenti della riga di comando | Avvisa |
| Input standard | I dati provengono da stdin | Avvisa |
| Variabili d'ambiente | I dati provengono da una variabile d'ambiente | Avvisa |
| GitHub Action senza pin | Un workflow usa un tag mutabile (@v4) invece di un commit SHA | Avvisa |
pull_request_target non sicuro | Un workflow usa il trigger pull_request_target | Avvisa |
| Credenziali nei log | Una password, chiave API o token viene passata a print/console.log/un logger | Avvisa |
| Segreto hardcodato | Una variabile chiamata come un segreto viene assegnata a un valore letterale che sembra reale | Avvisa |
| Il file non viene salvato — a Claude Code viene spiegato il motivo |