Come entrano: servizi di sviluppo esposti su internet
Il vettore d'ingresso reale — webssh gateway e Vite dev server lasciati in ascolto su 0.0.0.0
La maggior parte delle intrusioni su server di produzione non parte da un exploit sofisticato. Parte da qualcosa che qualcuno ha lasciato in ascolto su internet senza rendersene conto. Un servizio di sviluppo, comodo mentre lavori, che non è mai stato pensato per stare esposto e che nessuno ha spento. A giugno 2026, su un server Linux di produzione, l'ingresso è avvenuto esattamente così: nessuna vulnerabilità zero-day, nessun brute-force da film. Solo porte aperte con dentro strumenti che, esposti, sono l'equivalente di una chiave lasciata nella toppa.
Questo articolo si concentra su una cosa sola: il vettore d'ingresso. Non su cosa è successo dopo, ma su come si entra. Due protagonisti ricorrenti: i gateway SSH via browser (webssh) e il dev server di Vite. Se scrivi codice full-stack, è quasi certo che tu abbia acceso almeno uno dei due oggi.
La superficie d'attacco: dove ascolta un processo
Ogni servizio in rete si lega (bind) a un indirizzo. La differenza tra un incidente e una serata tranquilla sta quasi sempre in quale indirizzo.
Un processo in ascolto su 127.0.0.1 (loopback) è raggiungibile solo dalla macchina stessa. Nessuno da fuori può parlarci, punto. Un processo in ascolto su un'interfaccia VPN — per esempio l'IP Tailscale 100.x.x.x — è raggiungibile solo da chi è dentro quella rete privata. Un processo in ascolto su 0.0.0.0 è in ascolto su tutte le interfacce, inclusa quella pubblica: chiunque su internet che conosca IP e porta può connettersi.
Il problema è culturale prima che tecnico. Moltissimi strumenti di sviluppo bindano di default su 0.0.0.0 "per comodità" — così puoi aprire il dev server dal telefono, o dal portatile del collega sulla stessa rete. Comodo in locale, letale su un server con IP pubblico. E siccome funziona lo stesso, nessuno va a controllare. Il servizio resta lì, in ascolto su tutto, per settimane.
Verificare cosa ascolta è banale e dovrebbe essere un'abitudine:
ss -tlnp
Ogni riga con 0.0.0.0:PORTA o *:PORTA è una porta esposta al mondo. Se non sai giustificare perché quella porta è pubblica, hai appena trovato un problema.
webssh: una shell dietro una pagina web
Un gateway webssh è un terminale SSH incapsulato in una pagina HTML. Tipicamente è un piccolo server.js costruito su ssh2 per il lato connessione e xterm.js per il terminale nel browser. Apri l'URL, digiti, e stai eseguendo comandi su una macchina reale. Nasce come strumento legittimo: accesso rapido a un server da un browser, senza client SSH.
Esposto su internet, è la cosa più pericolosa dell'elenco, per un motivo semplice: è letteralmente una shell raggiungibile via HTTP. Non serve un exploit. Serve trovare la porta. Chi ci arriva e riesce a stabilire la sessione ottiene un terminale sul server, con i privilegi dell'utente che fa girare il processo. Se quel processo gira come root, l'attaccante ha root.
I modi in cui questi gateway falliscono sono sempre gli stessi:
Autenticazione opzionale o assente. Molte implementazioni fai-da-te lasciano il login come esercizio per il lettore. Il terminale funziona, l'auth "la aggiungo dopo". Dopo non arriva mai.
Credenziali di default o hardcoded. Il gateway si connette a un host SSH con user e password scritti nel codice o in un config di esempio mai cambiato. Chi legge il sorgente (spesso pubblico) conosce già le credenziali.
Sessioni non protette. Il token di sessione è debole, prevedibile, o la pagina del terminale è servita senza alcun controllo su chi sta guardando. In alcuni casi la connessione SSH viene stabilita lato server e il browser ci si aggancia senza autenticarsi davvero.
Esposizione diretta senza reverse proxy. Il server.js gira su una porta pubblica senza nulla davanti — niente nginx con Basic Auth, niente allowlist IP. La "sicurezza" è solo il fatto che l'URL è poco noto. Non è sicurezza, è speranza.
Vite dev server: un interprete esposto
Il dev server di Vite (di default sulla porta 5173) è l'altro protagonista. È lo strumento con hot-reload che usi mentre sviluppi il frontend React o Vue. Non è mai stato pensato per la produzione, e tantomeno per l'esposizione pubblica: la documentazione lo dice a chiare lettere. Ma tra un deploy e l'altro capita che resti acceso su un server, magari lanciato in una sessione tmux "solo per provare".
Perché è pericoloso esporlo, al di là del fatto che serva contenuti non minificati?
Lettura di file arbitrari. Vite ha avuto una serie di bug della stessa famiglia — path traversal e arbitrary file read. Come classe, si va da CVE-2023-34092 fino alla nidiata del 2025 (CVE-2025-30208 e affini): lettura di file fuori dalla root del progetto abusando dei suffissi di query come ?raw e ?import, o bypassando il controllo server.fs.allow. In pratica: una richiesta HTTP costruita ad arte fa restituire al dev server il contenuto di file che non dovrebbe mai servire. Il primo bersaglio è sempre lo stesso, .env: dentro ci trovi chiavi API, credenziali DB, token. Da lì l'attaccante non ha più bisogno del bug — ha i segreti.
WebSocket e controlli origin/host deboli. Il dev server usa un WebSocket per l'HMR (hot module replacement). Se i controlli su origin e host sono laschi, quel canale diventa un'altra superficie: richieste da origini che non dovrebbero essere ammesse, o host header manipolati per aggirare i filtri.
Il punto vero. Un dev server è, per progetto, un ambiente con esecuzione di codice: trasforma moduli al volo, carica plugin, valuta configurazioni. Esporlo non è come esporre una cartella di file statici. È come esporre un interprete. Il file read è solo la parte comoda; sotto c'è una macchina che esegue trasformazioni su input.
La catena, in astratto
Il meccanismo, senza scendere in dettagli operativi che non servono a nessuno tranne a chi attacca, è lineare. Servizio esposto trovato tramite scansione delle porte. Da lì, una di due strade: o lettura di file sensibili (i segreti nel .env, chiavi private, config), oppure esecuzione diretta di codice o accesso a shell. Con i segreti o con la shell si scarica un secondo stadio — un payload più completo — e si stabilisce un punto d'appoggio persistente sul server. Foothold. Fine del vettore d'ingresso, inizio dei guai.
La cosa da interiorizzare è che nessuno di questi passaggi richiede genialità. Richiede che tu abbia lasciato la porta aperta.
Come si chiude
La difesa è quasi tutta a monte, nella configurazione, e costa pochi minuti.
Bind su loopback o VPN, mai su 0.0.0.0. Tutto ciò che è di sviluppo o interno deve ascoltare su 127.0.0.1 o sull'interfaccia Tailscale. Per Vite significa non usare il flag --host a caso, e semmai legarlo esplicitamente all'IP della VPN. Se serve accesso da un'altra macchina, si passa da una VPN o da un tunnel autenticato, non aprendo la porta al mondo.
I dev server non escono mai su internet. Vite, webpack, il dev server di Next, qualsiasi cosa con hot-reload: zero esposizione pubblica, sempre. In produzione ci va la build statica servita da nginx, non il dev server.
webssh, se proprio serve, blindato. Dietro un reverse proxy con autenticazione forte, allowlist degli IP che possono raggiungerlo, e preferibilmente accessibile solo da dentro la VPN. Un terminale via HTTP senza almeno questi tre strati non va acceso.
Segreti fuori portata. Il .env non deve mai essere world-readable (chmod 600) e non deve mai stare dentro il document root o in una directory che un dev server possa raggiungere. Se un bug di file read colpisce, deve trovare il meno possibile.
Aggiornare. Le CVE di Vite citate sono già patchate nelle versioni recenti. Tenere aggiornate le dipendenze di sviluppo non è igiene astratta: chiude esattamente queste falle.
Inventario periodico. Un ss -tlnp ogni tanto, sui server che contano, e la domanda per ogni porta pubblica: "questa perché è esposta?". Se non c'è una risposta esplicita, la porta va chiusa.
Il principio che tiene insieme tutto è uno solo. "Esposto a internet" è una decisione, non un default da subire. Ogni servizio che ascolta su un IP pubblico dovrebbe essere lì perché qualcuno ha scelto consapevolmente che ci stesse, con le difese al posto giusto. Tutto il resto — il dev server dimenticato, il webssh "temporaneo", la porta aperta "per comodità" — è la porta da cui si entra. E si entra, prima o poi, senza bisogno di essere bravi.