Articoli approfonditi sulla tecnologia che plasma il futuro.

I tool CLI non dovrebbero installare daemon in background

I tool CLI AI installano daemon persistenti e auto-aggiornanti di default. Perché questo rompe il modello di fiducia e come fare meglio.

Un piccolo dispositivo senza marchio collegato di nascosto a un grande pannello di controllo in una stanza buia
Uno strumento installato una volta sola, che gira in silenzio e si riscrive per sempre: ecco il nuovo default.

Uno sviluppatore esegue npm install -g @openai/codex per provare un assistente di programmazione basato su AI, e si ritrova con un daemon in background persistente e auto-aggiornante che non aveva mai chiesto. È la situazione esplosa di recente, quando gli utenti della Codex CLI di OpenAI hanno scoperto che il tool avvia automaticamente un processo in background, scrive file pid e lock in ~/.codex, conserva su disco vecchie versioni del binario (un utente ne ha segnalate circa 12 GB) e si aggiorna da solo senza chiedere. Non è una storia su un bug di una sola azienda. È una storia su un modello di fiducia su cui gli strumenti per sviluppatori si sono basati per decenni, e su come lo si stia abbandonando in silenzio.

Ho passato anni a occuparmi di infrastruttura e gestione degli incidenti, e lo schema qui è uno che ho già visto: negli adware, negli agent di build compromessi, nei servizi di aggiornamento «utili» distribuiti dai produttori di hardware. Quindi analizziamo le difese più comuni di questo design e testiamole una per una, perché la maggior parte non regge al contatto con il modo in cui gli ambienti di produzione funzionano davvero.

Mito 1: «È solo un aggiornatore, lo fanno anche i browser»

È la difesa più comune, e suona ragionevole. Chrome e Firefox si aggiornano di continuo. Lo fanno anche VS Code e Slack. Perché un harness da CLI non dovrebbe?

Perché il contesto di fiducia è completamente diverso. Un browser è un'applicazione grafica con un'esperienza di primo avvio, una pagina delle impostazioni visibile, un installer firmato e, fatto cruciale, un canale di aggiornamento irrobustito e sottoposto ad audit da oltre un decennio. L'updater di Chrome è uno dei componenti software più attaccati al mondo, e Google ha team dedicati a tenerlo sicuro. Quando installi Chrome, l'aggiornamento fa parte di un accordo a cui hai aderito in modo esplicito.

Una CLI installata via npm porta con sé un contratto implicito diverso. Gli sviluppatori si aspettano che giri quando viene invocata e si fermi quando ha finito. Non è nostalgia: è un pilastro portante. Pipeline CI, container, build server condivisi e revisioni di sicurezza danno tutti per scontato che npm i -g some-tool ti dia un binario che viene eseguito su richiesta. Un daemon in background che sopravvive al logout, si rilancia da solo e sostituisce il proprio binario viola ognuna di queste assunzioni. Mi è capitato personalmente di stare in call d'incidente in cui la domanda «perché c'è un processo che non riusciamo a spiegare?» ha trasformato un alert di routine in un'indagine forense di tre ore. La persistenza non dichiarata è indistinguibile da una compromissione finché non provi il contrario.

C'è anche una differenza pratica nel raggio d'impatto. Il browser renderizza le pagine web in una sandbox. Un harness di programmazione basato su AI esegue comandi shell, legge il tuo albero dei sorgenti e spesso tiene in ambiente chiavi API e credenziali cloud. Affidargli un componente auto-modificante sempre attivo è un rischio di un'altra categoria rispetto all'aggiornamento di un browser.

Mito 2: «Gli utenti possono disattivarlo con un flag di configurazione»

È tecnicamente vero, e praticamente irrilevante. Sì, esiste un feature flag:

# ~/.codex/config.toml
[features]
daemon_auto_start = false

Il problema è questo: non era documentato quando gli utenti sono andati a cercarlo. Un opt-out che nessuno conosce non è consenso, è un tranello. E nota qual era il piano B della community: cancellare i file pid e lock, creare dei symlink verso /dev/null e renderli immutabili con chattr +i, così il daemon va in crash all'avvio se il flag dovesse mai sparire. Quando gli utenti minano le proprie home directory per difendersi dal tuo software, non hai costruito un sistema di configurazione. Hai costruito una relazione conflittuale.

Ne ho già parlato in riferimento alle app fitness che perdono dati di localizzazione: lo schema è sempre lo stesso. La funzione viene spedita attiva di default, l'interruttore è nascosto o non documentato, e l'onere di stare all'erta ricade sull'utente. I default sono una politica. Un default che installa persistenza è una dichiarazione su chi il software serve davvero.

La soluzione è banalmente semplice e lo è sempre stata: chiedere una volta sola, al primo avvio. Codex runs a background service to keep itself updated. Enable it? [y/N]. Strumenti come apt, Homebrew e la maggior parte dei daemon Linux funzionano con un'attivazione esplicita da decenni. systemctl enable esiste proprio perché far partire qualcosa al boot dovrebbe essere un atto deliberato.

Mito 3: «Per andare veloci serve l'auto-aggiornamento silenzioso»

Questo ha un certo fondamento, e voglio darne la versione migliore. Gli harness AI vanno davvero veloci. Una CLI vecchia di tre settimane potrebbe comportarsi male con un'API cambiata, e un client bacato in giro è un vero costo di supporto. Un team che sviluppa un IDE per legal-tech ha raccontato di aver considerato un daemon, scegliendo poi un controllo di aggiornamento esplicito a ogni avvio: se l'app è obsoleta, te lo dice e si aggiorna all'avvio, e se non ti va bene, smetti di usarla. È un design legittimo.

Ma «abbiamo bisogno di aggiornamenti» non implica «abbiamo bisogno di un daemon persistente che si aggiorna mentre non guardi». Esiste un'ampia via di mezzo:

  • Controllo all'invocazione. Confronta le versioni all'avvio della CLI, mostra un avviso e aggiorna alla run successiva. Lo fanno Homebrew, gh e tanti altri.
  • Aggiorna tramite il package manager. Lo hai installato via npm, quindi aggiorna via npm. L'utente ha già un meccanismo che capisce e che può fissare, auditare e bloccare.
  • Daemon opt-in, disattivato di default. Per chi vuole un aggiornamento senza attriti, offri il daemon come scelta documentata.
  • Elimina le vecchie versioni. Tenere ogni binario precedente finché non hai mangiato 12 GB del disco di qualcuno non è una strategia di aggiornamento; è una perdita.

La vera ragione per cui i team ricorrono ad aggiornatori silenziosi non è la velocità, è il controllo. Un aggiornamento tramite package manager rispetta il lockfile, i mirror e il flusso di approvazione dell'utente. Un auto-aggiornatore aggira tutto questo. Quando un vendor insiste sul percorso di auto-aggiornamento, sta dicendoti che gli importa più della sua pipeline di deploy che della tua change management. In un'azienda che ha già punti ciechi nel logging, è così che finisci con codice non revisionato che gira con le credenziali degli sviluppatori.

Uno schema illustrato con una biforcazione: un percorso attraversa un checkpoint, l'altro lo aggira passando per un tunnel
Due percorsi di aggiornamento: uno passa dal tuo controllo, l'altro lo aggira con un tunnel.

Mito 4: «È open source, puoi leggere il codice»

L'open source aiuta, ma non risolve il problema reale, cioè la divergenza tra ciò che hai revisionato e ciò che sta girando. Lo scopo stesso di un daemon auto-aggiornante è che il binario sulla tua macchina oggi non sia quello che hai installato. Leggere il sorgente della versione 0.157.0 non ti dice nulla sulla build che verrà scaricata il prossimo martedì. A meno che tu non verifichi firme e build riproducibili a ogni aggiornamento silenzioso, e nessuno lo fa, «è open source» è una coperta di Linus.

C'è un secondo problema, più sottile: l'intreccio tra stato e configurazione. Gli utenti che cercano di gestire Codex in modo dichiarativo (uno ha raccontato di non riuscirci con nix-darwin) hanno scoperto che lo strumento mescola configurazione e stato di runtime mutabile nella stessa directory. Questo rende impossibile fissare, confrontare o auditare cosa è cambiato. I buoni strumenti Unix lo sanno da sempre: configurazione in ~/.config, stato in ~/.local/state, cache in ~/.cache, e non lasciano mai che lo strumento modifichi la propria configurazione. Se vuoi capire perché il percorso auditabile conta, il divario tra specifica e implementazione è esattamente il posto dove si annidano queste sorprese.

Se vuoi controllare cosa sta girando davvero sulla tua macchina in questo momento, ci vogliono trenta secondi:

# What AI-tool daemons are alive right now?
ps auxww | grep -Ei 'codex|claude' | grep -v grep
# What's been accumulating on disk?
du -sh ~/.codex ~/.local/share/claude 2>/dev/null
# What launchd/systemd units did tools register?
ls ~/Library/LaunchAgents 2>/dev/null   # macOS
systemctl --user list-units --type=service | grep -Ei 'codex|claude'  # Linux

Lancialo su qualche laptop di sviluppatori della tua organizzazione. Ti garantisco che almeno una persona resterà sorpresa dall'output.

Mito 5: «Lo fanno tutti, quindi va bene»

Anche Claude Code conserva le versioni binarie precedenti ed esegue task in background, come hanno confermato gli utenti nella stessa discussione. Quindi sì, è uno schema dell'industria, non una svista di un singolo vendor. Ma «lo fanno tutti» non è mai stato un argomento di sicurezza; è il modo in cui le cattive abitudini si incrostano. Gli incidenti della supply chain degli ultimi anni avrebbero dovuto insegnarci che le macchine degli sviluppatori sono il bersaglio più morbido e di valore nella maggior parte delle organizzazioni: custodiscono credenziali cloud, chiavi di firma e accessi di push, ed eseguono una quantità impressionante di codice non auditato con quei privilegi.

Ogni componente persistente, connesso alla rete e auto-modificante che aggiungi a quella macchina è superficie d'attacco puntata verso le tue credenziali più sensibili. Un canale di aggiornamento compromesso per un tool molto diffuso è uno scenario da incubo proprio perché il meccanismo di aggiornamento è considerato fidato per default. Più vendor normalizzano i daemon silenziosi, più ognuno di essi diventa un bersaglio appetibile.

E il livello di qualità conta. Gli utenti hanno segnalato che il daemon di Codex corrompeva i permessi durante l'auto-aggiornamento, lasciando le directory .git in sola lettura e bloccando i repository di lavoro. Un daemon bacato non se ne sta lì fermo; rompe attivamente cose con privilegi che non hai mai concesso consapevolmente. «Lo fanno tutti» più «è bacato» non è rassicurante. È una previsione.

Come appare un meccanismo di aggiornamento rispettoso del consenso

È un problema già risolto. Non servono tecnologie nuove; servono vendor che scelgano la risposta noiosa. Se stessi scrivendo il documento dei requisiti di una qualsiasi CLI AI oggi sul mercato, avrebbe questo aspetto:

  1. Nessuna persistenza di default. Il tool gira quando viene invocato ed esce quando ha finito. Qualsiasi componente in background è opt-in, richiesto esplicitamente al primo avvio.
  2. Kill switch documentati e stabili. Un flag di configurazione e una variabile d'ambiente (es. CODEX_NO_DAEMON=1) documentati, testati e che non spariscono in silenzio.
  3. Aggiornamenti tramite il canale di installazione. I tool installati via npm si aggiornano via npm. Avvisa all'invocazione; non modificare mai il tuo binario sotto i piedi dell'utente.
  4. Release firmate, versionate e con changelog. Se distribuisci un updater, firma gli artefatti e lascia che gli utenti fissino le versioni e controllino cosa è cambiato.
  5. Spazio su disco limitato e separazione pulita dello stato. Conserva al massimo una versione precedente, separa configurazione e stato, e rispetta le convenzioni XDG.
  6. Rispetta il modello delle distribuzioni. Come ha scritto un commentatore, il packaging delle distro esiste perché i maintainer testino il software e tolgano le stranezze prima che arrivi agli utenti. Non combatterlo, pubblicaci sopra.

Nulla di tutto questo rallenta in modo significativo un team che si muove velocemente. Sposta solo il consenso all'inizio dell'interazione, dove deve stare.

Le conclusioni

La verità scomoda è che gli strumenti di programmazione AI chiedono più fiducia di qualsiasi altro tool per sviluppatori nella storia (accesso shell, le tue credenziali, l'intero albero dei sorgenti) adottando però l'igiene degli aggiornamenti dell'adware del 2008. Questi due fatti non possono coesistere in sicurezza. Una CLI che installa per default un daemon persistente e auto-aggiornante ha preso una decisione al posto tuo, e la decisione è che la comodità del vendor vale più del tuo controllo sulla tua stessa macchina.

Opponiti. Imposta i flag, controlla le tue macchine, apri le segnalazioni e preferisci i tool i cui default ti rispettano: lo stesso istinto che spinge le persone a cercare la libertà del sideloading rispetto alle piattaforme blindate vale anche qui. Gli strumenti che oggi lasciamo girare senza supervisione sui laptop degli sviluppatori diventeranno i report sugli incidenti di supply chain di domani. Il consenso non è un optional nel design degli aggiornamenti. È l'intero meccanismo.