Venerdì sera mi arriva una mail: [YOURLS] Short URL deleted: ....
Ero in viaggio, in autostrada, in mezzo al traffico e ai campioni dello slalom tra corsie a velocità che porca miseria levati perché altrimenti ti prendo a schiaffi, non avevo sicuramente modo di accorgermene né tanto meno di capire perché mai il mio YOURLS avesse effettuato una cancellazione senza passare per una mia azione. Poco dopo un’altra, e un’altra, e poi un’altra ancora. Short URL che uso da anni, con decine di migliaia di clic alle spalle, che sparivano uno dopo l’altro dalla mia istanza di YOURLS. Il primo pensiero è stato quello che avresti fatto anche tu: qualcuno mi ha bucato lo shortener.
Spoiler: nessun attacco.
Ma per arrivarci mi è servita un’oretta di log, e la spiegazione è abbastanza istruttiva da meritare un post, soprattutto se anche tu tieni attivo, come me, un plugin che avevi installato e dimenticato lì.
La caccia all’intruso che non c’era
Prima cosa, accesso SSH all’hosting e giù dentro i log di Apache.
Cosa cercavo: richieste alla API di YOURLS (yourls-api.php), POST all’area admin/, qualunque cosa somigliasse a una cancellazione pilotata da fuori.
Niente. Zero chiamate alla API in tutto il log. Un solo POST all’admin nella giornata: il mio, fatto dopo aver ricevuto l’allarme per andare a controllare. Il filesystem era pulito: nessuna webshell, nessun file PHP modificato di recente, ~/.ssh/authorized_keys vuoto, nessun utente aggiunto all’array degli amministratori in config.php. Eppure i link sparivano davvero: me lo confermava il database, le righe non c’erano più, le notifiche ricevute dal mio Change Notifier erano la conferma ultima a mezzo posta elettronica (maledettamente comodo, diversamente non me ne sarei accorto per tempo e chissà quanti altri link avrei lasciato per la strada).
Un’azione che tocca il database di YOURLS ma non lascia traccia nei log web è il tipo di contraddizione che di solito significa che stai guardando nel posto sbagliato.
L’indizio era nella mia stessa mail
Come ti dicevo poco sopra, quelle notifiche me le manda un plugin che ho scritto io, YOURLS-ChangeNotifier: invia una mail a ogni creazione, modifica o cancellazione di uno short URL. Dando un’occhiata più approfondita al corpo del messaggio di uno dei messaggi di cancellazione, saltava fuori questo:
Event: DELETE When: 2026-08-29T08:26:27+00:00 By: user: (authenticated) IP: 34.10.46.191
Due dettagli che prima avevo letto di sfuggita. Il campo By: diceva user: (authenticated) senza nome utente: è l’ultima spiaggia del mio plugin, quello che scrive quando yourls_is_valid_user() dice “sì” ma non riesce a tirare fuori né un login, né un cookie di sessione, né un header di autenticazione. Tradotto: nessun accesso vero all’area riservata.
E l’IP: cambiava a ogni mail. In un caso era quello di un monitor esterno che mi passa a controllare i redirect ogni mattina alla stessa ora.
Non un attaccante: solo chi, per caso, stava visitando quel link nel momento esatto della cancellazione.
Il che restringeva parecchio il campo: qualcosa dentro YOURLS cancellava i link quando venivano visitati.
Il colpevole: un plugin antispam del 2012
user/plugins/antispam/. Il plugin Anti spam di Ozh, uno dei più vecchi dell’ecosistema YOURLS. Attivo da anni sulla mia istanza, mai toccato, completamente uscito dai radar. Fa due cose. Alla creazione di uno short URL controlla la destinazione contro alcune DNS blacklist e rifiuta se è elencata: legittimo. Ma poi c’è la seconda parte, agganciata all’evento redirect_shorturl, cioè eseguita a ogni click:
// Has the remote link become compromised lately? Check on redirection
yourls_add_action( 'redirect_shorturl', 'ozh_yourls_antispam_check_redirect' );
function ozh_yourls_antispam_check_redirect( $url, $keyword = false ) {
// ...
if( $chances == mt_rand( 1, $chances ) ) {
if( ozh_yourls_antispam_is_blacklisted( $url ) != false ) {
// Delete link & die
yourls_delete_link_by_keyword( $keyword );
yourls_die( 'This domain has been blacklisted. This short URL has been deleted from our record.', 'Domain blacklisted', '403' );
}
}
}
Con probabilità 1 su 5 (link creato da meno di tre giorni) o 1 su 15, a ogni visita interroga la URL di destinazione contro cinque blacklist:
'zen.spamhaus.org', 'multi.surbl.org', 'bl.spamcop.net', 'combined.abuse.ch', 'dnsbl.sorbs.net',
Se una sola risponde positivo, il link non viene sospeso, non finisce in quarantena, non ti manda un avviso: yourls_delete_link_by_keyword(). Cancellato.
E l’utente si becca un 403, quella pagina da 866 byte che nel frattempo avevo visto passare decine di volte nei log senza dargli peso.
Perché proprio adesso
Perché quelle blacklist, nel 2026, sono in buona parte inaffidabili se non le usi nel modo giusto:
- SORBS (
dnsbl.sorbs.net) è stata spenta a giugno 2024. La zona DNS non è garantito che risponda in modo sensato. - SpamCop e SURBL degradano di proposito le risposte quando le query arrivano da resolver pubblici o ad alto volume, cioè esattamente lo scenario di un hosting condiviso, dove il resolver è in comune con centinaia di altri account.
Il risultato è falsi positivi a raffica. Il readme del plugin, va detto, non nasconde niente:
Checking against DNS blacklists may or may not work for you […] It may even result in all domains being blacklisted from your server. Try and see.
L’ho provato: ha deciso che Reddit, Amazon, un blog tecnico di Microsoft e il mio canale Twitch erano tutti “domini blacklistati”, e li ha rimossi.
Il fix
Disattivazione del plugin: rimosso da active_plugins nel database e cartella rinominata in .antispam.disabled, solo per scrupolo, giuro che poi dopo passo pure a cancellare definitivamente.
Da quel momento nessun link è stato più toccato.
Se anche tu tieni attivo questo plugin, il consiglio è di andare a vedere subito se ti sta erodendo lo storico: cerca i 403 anomali nei log e le eventuali mail di cancellazione. Come protezione antispam ci sono alternative che almeno non distruggono dati: Google Safe Browsing per YOURLS (ma occhio, che pure questo è stato archiviato e non viene più aggiornato da quattro anni), o più banalmente un captcha sull’interfaccia pubblica. Io sto seriamente pensando di mettermi alla ricerca di un sostituto mantenuto ancora oggi o – in alternativa – tirare in piedi qualcosa di nuovo che svolga però questo vecchio mestiere.
Il recupero: le statistiche erano ancora tutte lì
Qui la notizia buona.
Quando YOURLS cancella uno short URL rimuove la riga dalla tabella yourls_url, ma non tocca yourls_log, dove vive lo storico dei click.
Le statistiche c’erano ancora tutte, riga per riga, per ognuno dei link cancellati.
Ho recuperato destinazione, titolo e data di creazione dal dump notturno del database (Server Plan ne tiene uno automatico e non mi costringe così ad andare a recuperare il backup che mi porto in casa con cPanelVault), ho reinserito le righe con un INSERT mirato e ho rimesso i contatori clicks allineandoli al conteggio reale dei record ancora presenti nel log.
Verifica finale con un curl per keyword, per controllare che ogni redirect puntasse di nuovo dove doveva:
/r 301 -> https://www.reddit.com/r/Gioxx/ /shopping 301 -> https://www.amazon.it/shop/gioxx /ee4li 301 -> https://techcommunity.microsoft.com/.../ba-p/3851357 /twitch 301 -> https://www.twitch.tv/gioxx85
Come se non fosse successo niente, con un’unica eccezione: twitch era stato cancellato prima che partisse il backup della notte, quindi la sua destinazione non era in nessun archivio e ho dovuto ricostruirla a memoria (non che fosse così complicato, ma è giusto dirlo, altrimenti mi sarebbe andato a tirare fuori dall’armadio il backup di qualche giorno fa).
In conclusione
Il giudizio è netto: per come è scritto, cancellazione automatica e irreversibile al primo hit di una qualunque blacklist, per giunta durante il redirect, cioè nel percorso più caldo e meno sorvegliato, questo plugin non ha senso su un’installazione viva e usata nel 2026, e ancora meno su hosting condiviso. Il controllo in fase di creazione è un’altra storia e ci può stare; è l’azione distruttiva a runtime il problema.
Due cose che mi porto a casa.
- La prima: le notifiche via mail su creazione/modifica/cancellazione degli short URL, che tenevo più che altro per curiosità, si sono rivelate l’unico motivo per cui me ne sono accorto in tempo. Se hai un sistema di alert simile, quelle mail vanno lette quando arrivano, non archiviate.
- La seconda: tenere YOURLS aggiornato all’ultima versione (oggi la 1.10.5) resta buona regola a prescindere, il mio YOURLS-diff serve proprio a rendere la cosa meno noiosa, anche se stavolta la versione non c’entrava niente (ma per coincidenza, essendo stata pubblicata una manciata di ore prima rispetto all’accaduto, mi ha fatto sorgere il dubbio di uno 0-day corretto che però mieteva vittime into the wild).
L’area commenti è a tua disposizione, soprattutto se ti è capitato di ritrovarti con dei link spariti e non sapevi da dove partire 😅
#KeepItSimple