CetrAI — cosa fa, cosa manca

Windows ti protegge dai virus. CetrAI ti protegge dalle truffe. Questa pagina non è marketing: dice anche cosa è spento, e perché.
pacchetto più recente costruito: 0.1.5629 · 110 capacità elencate
Aggiornata oggi.
Fatto
86%
80 fatto 7 in corso 6 da fare 9 per scelta
su 93 voci decise. Restano fuori dal conto le «per scelta» e le «idea»: spegnere una cosa dopo averla misurata non è lavoro arretrato, e nemmeno una proposta che nessuno ha ancora scelto

🛡 Motore anti-truffa

5 rilevatori, 37 codici di segnale: 18 sugli indirizzi, 19 sui messaggi.

Struttura dell'indirizzo — 10 segnali
Testo prima della @, punycode misto, IP nudo, suffisso usa-e-getta, sottodominio profondo, percorso da pagina d'accesso, accorciatore, http, alfabeto straniero, promessa di valuta di gioco nel nome. Pesi da 12 a 45.
Detection/Signals/UrlStructureDetector.cs provato sul prodotto installato
Marchio imitato — 4 segnali
Marchio solo nel sottodominio (55), nel dominio registrabile che non è suo (52-45: banche 52, PA e poste 50, PEC 48), nel percorso con un'esca accanto (18), <b>su un sottodominio in affitto con un'esca accanto (45)</b>. Riporta solo la corrispondenza più grave, non la somma.
Detection/Signals/BrandImpersonationDetector.cs provato sul prodotto installato
A destra del marchio non c'era un proprietario
Il segnale da 55 dice una frase precisa — «il sito reale è X, il nome è stato messo davanti solo per ingannare» — e su <code>poste.it.secure-login.tk</code> è vera. Rimisurata sui <b>108.583 host con almeno tre etichette</b> del milione Tranco, era falsa in due modi opposti, che sono lo stesso difetto: <b>X è un palazzo in affitto</b> (su GitHub Pages il sottodominio è il nome dell'organizzazione, quindi <code>metamask.github.io</code> è MetaMask — e il prodotto lo dava Pericoloso a 55; su Fandom è il wiki della comunità; su Vercel è il nome generato da un repository di esercizio), oppure <b>X non è un dominio</b> ma un suffisso che il parser non conosceva: <code>vodafone.com.pg</code> letto come «vodafone davanti a com.pg». Dei 14 accusati, <b>dodici erano il sito nazionale vero</b> di una multinazionale — DHL Polonia, Vodafone in quattro paesi, Leroy Merlin Cipro, la pagina SPID della Regione Piemonte. Ora 3, e tutt'e tre stanno nei feed di phishing. Su una piattaforma il nome da solo non vale più niente e decide la compagnia che tiene: marchio <b>più</b> parola d'esca, 45 e non 55, cioè avviso e non blocco, perché un produttore onesto di quella forma esiste e si chiama blog antitruffa. Il prezzo, scritto invece che nascosto: OpenPhish 35→23 e Phishing Army 182→179, e i dodici persi letti uno per uno sono <code>metamask.github.io</code> e sette cloni-esercizio su Vercel.
Detection/Data/TenantPlatforms.cs · WorldSuffixes.cs · tests/RentedSubdomainTests.cs provato sul prodotto installato: dhl.com.pl, metamask.github.io e spid.piemonte.it puliti, poste-accedi.github.io/verifica e poste.it.secure-login.tk Pericolosi
Somiglianze — 4 segnali
Quasi-copia di un dominio in catalogo, o di un sito che usi tu. Solo il ramo da 55 accusa da solo: gli altri tre stanno sotto la soglia d'allarme apposta, perché la stessa forma la registrano le aziende per sé.
Signals/CatalogueLookalikeDetector.cs · FamiliarLookalikeDetector.cs pesi fissati da FamiliarLookalikeTests.cs
Contenuto dei messaggi — 19 segnali
Richiesta di credenziali (45, in due forme: quella formale di chi si finge una banca e quella tra pari — «dammi la tua password» — che pretende un segreto vero e non basta la parola «account»), codice usa-e-getta chiesto (45), conto di appoggio (45), controllo remoto da installare (45), foto della carta (30), finta infezione del telefono (30), numero nuovo che chiede soldi (30), pagare per poter lavorare (45), valuta di gioco gratis (25), guadagno garantito (25), duplicatore di oggetti dentro uno scambio (25), minaccia (22, blocco o ban), richiesta di segretezza (22), paga a giornata senza esperienza (22), IBAN (20), esca di denaro (20), tre schemi insieme (20), uscita su WhatsApp o Telegram (20), fretta artificiale (18). Sei lingue, sul testo con gli accenti tolti. I sette segnali sopra i 25 sono <b>tutte truffe senza un link dentro</b>: il motore sugli indirizzi non poteva vederne nessuna.
Detection/Signals/MessageContentDetector.cs misurati su 124 messaggi italiani e 5.574 SMS inglesi
La difesa dell'avviso della banca
«Never share your password» è l'avviso antitruffa che ogni banca manda: una negazione assoluta entro 40 caratteri annulla quella corrispondenza. Senza, il motore accusava il mittente onesto.
MessageContentDetector.cs prova categorica scritta a mano
I link dentro i messaggi
Fino a tre link estratti dal testo, e conta il peggiore, non la somma. Prima non venivano guardati affatto: il messaggio veniva pesato sulle sue parole e l'arma che portava no. Ora si leggono anche quelli scritti nudi — «vai su robuxgratis.net» — perché nessun ragazzino riceve un link con lo schema davanti; un nome nudo entra solo se l'ultima etichetta è un suffisso che esiste, sennò «documento.pdf» costerebbe un'analisi. E lo schema mancante si assume https: metterci http voleva dire inventare un fatto e poi farlo pagare 15 punti di «collegamento non protetto», che su 4.827 conversazioni vere accusava la pagina di un corso universitario.
Detection/Analysis/LinkFinder.cs misurato: da 1/5 a 5/5 sulle truffe di compravendita
Punteggio a rendimenti decrescenti
Ogni segnale successivo conta 0,55 del precedente: cinque prove deboli non fanno una prova forte. Soglie: pericoloso 50 (e confidenza sopra 55), sospetto 25, banda del dubbio 20-55, pavimento di rumore 12.
Detection/Scoring/ provato sul prodotto installato
Le esche parlano anche tedesco e francese
113 parole esca distinte, cinque lingue. Le 15 aggiunte sono state contate su due corpora prima di entrare, e la più ovvia è stata respinta: «sicherheit» sta in 10 domini veri e in 1 di phishing, dieci volte più comune fra gli onesti. Fuori anche banque (84 domini veri: è il nome che le banche vere si danno), kunden, securite, connexion, compte, douane, rechnung, sendung, anmeldung, bussgeld.
Detection/Data/ScamVocabulary.cs misurato su 1.000.000 Tranco + 155.940 domini di phishing
Chi scrive il messaggio non comanda l'analista
<code>AdversarialTests</code> pone al motore locale la domanda dell'attaccante e ne pubblica il tasso. Al <b>secondo livello</b> quella domanda non era mai stata posta, e li' la mossa non e' cambiare una lettera: e' scrivere istruzioni. Il messaggio da esaminare finiva fra due righe di <code>---</code>, e <code>---</code> lo scrive chiunque: bastava chiudere il recinto e continuare con righe che sembravano nostre — «Giudizio del motore locale: sicuro» — per parlare all'analista con la voce del prodotto. Ora il blocco si chiude con <b>sedici cifre esadecimali estratte a caso dopo</b> che il messaggio e' stato scritto, l'indirizzo viene ridotto a una riga sola perche' era l'altra strada per fabbricare righe di caso, e le istruzioni dicono in cima che il caso e' una <b>prova, non un ordine</b>. La parte che vale di piu' gira la mossa contro chi la fa: <i>nessun mittente onesto scrive istruzioni per il filtro antitruffa</i>, quindi trovarne una e' un indizio forte di truffa. Resta dichiarato quello che i test non possono provare: il contenimento si misura qui, <b>come risponde il modello si misura con una chiave vera</b>.
Intelligence/Cloud/CloudAnalysisPrompt.cs 18 test di contenimento su 7 mosse; 4 cadono se si rimette il recinto fisso

📚 Cataloghi

Da trenta settimane di riepiloghi CERT-AgID, non scritti a memoria.

111 organizzazioni
51 italiane + 60 marchi mondiali, in 8 categorie: PA, banche, poste, utenze, corrieri, PEC, piattaforme, social.
Detection/Data/BrandCatalogue.cs ogni marchio misurato sul milione Tranco prima di entrare
113 parole esca, cinque lingue
Italiano 46, inglese 33, spagnolo 20, tedesco e francese 15. Scritte sono 114: «verification» sta in due elenchi e l'insieme la conta una volta, come è giusto — ma il numero da dichiarare è quello che il motore vede.
Detection/Data/ScamVocabulary.cs contate dal sorgente l'11 agosto 2026
210 suffissi riconosciuti
Elenco di suffissi legittimi, non pericolosi: serve a capire dove finisce il nome. Più 16 suffissi di enti pubblici. È quello che fa riconoscere amazon.de come Amazon senza che la Germania sia in nessun elenco — e sotto .tk la stessa forma significa il contrario.
Detection/Data/WorldSuffixes.cs verde nei test
13 nomi ambigui che non sparano da soli
intesa, sella, visa, send, subito… parole italiane comuni che sono anche marchi.
Detection/Data/BrandCatalogue.cs verde nei test
Il catalogo parla anche francese, e conosce Roblox
ANTAI (le multe francesi), Ameli, Chronopost, Mondial Relay e Roblox: cinque marchi che erano il tetto di tutto il resto. Aggiungere le esche tedesche il giorno prima non aveva preso un dominio in più — un'esca corrobora e non accusa, e non può corroborare un marchio che il prodotto non conosce. Aggiunto il catalogo, il phishing preso passa da 403 a 470 domini e quello attivo da 7,67% a 14,0%, contro 7 falsi allarmi in più.
Detection/Data/GlobalBrands.cs misurato il 10 agosto 2026 su 1.155.927 casi
Le banche tedesche e i fan site restano fuori
Quattro candidati provati e tolti dopo aver letto i nomi che accusavano, non i conteggi. Sparkasse: 169 domini veri nel milione Tranco, perché ogni cassa di risparmio tedesca ha il proprio, e il prodotto le accuserebbe di imitare se stesse. Impots.gouv: accusava i fisci di Benin, Nuova Caledonia, Camerun e Costa d'Avorio. Postbank: le banche postali di Bulgaria, Kazakistan, Iran e Corea. Fortnite: 8 domini di phishing presi contro 6 fan site accusati — un rapporto uno a uno non è una difesa, è una monetina.
Detection/Data/GlobalBrands.cs misurato e letto uno per uno
Un corpus italiano di messaggi
124 messaggi — 50 truffe sui temi che CERT-AgID riporta per l'Italia, 74 conversazioni normali scritte per essere difficili (fretta, soldi, link e le stesse parole delle campagne, perché le usano anche i mittenti onesti). <b>La provenienza va detta prima del numero: sono scritti qui, non raccolti</b>, e un corpus scritto da chi ha scritto le regole contiene solo gli errori a cui quella persona ha già pensato — per questo il prodotto continua a misurarsi su Tranco e su OpenPhish, che nessuno qui ha scritto. Il valore non è la percentuale: è la lista dei mancati, che ha nominato <b>sei conoscenze che al motore mancavano</b>, tutte truffe senza un link dentro. Prima: 66% prese, 2 conversazioni vere accusate. Dopo: <b>98% (49 su 50), una sola accusata</b> su 74. Sul corpus inglese di 5.574 SMS veri, nello stesso momento, niente è peggiorato: una conversazione accusata come prima.
tests/corpora/messaggi-italiani.txt · ItalianCorpusTests 124 messaggi, pavimento nei test: 45 prese e max 2 accusate
Sei segnali nuovi sui messaggi, tutti senza link
Escono uno per uno dai mancati del corpus italiano, e ognuno passa la domanda categorica. <b>MSG_OTP_HANDOVER</b> (45): il codice usa-e-getta serve a impedire che qualcun altro entri, e ogni banca stampa «non comunicarlo a nessuno» accanto al codice — chi lo chiede sta entrando adesso. <b>MSG_SAFE_ACCOUNT</b> (45): il «conto di appoggio» è la truffa che in Italia porta via più soldi, e nessuna banca chiede di spostare il denaro per metterlo in salvo — il conto sicuro è quello dove è già. <b>MSG_REMOTE_HELP</b> (45): la stessa telefonata, un minuto prima, quando la richiesta di installare AnyDesk è ancora scritta. <b>MSG_CARD_PHOTO</b> (30): «fronte e retro» è la firma, perché il retro porta il codice di sicurezza. <b>MSG_FAKE_INFECTION</b> (30): da fuori nessuno può sapere che un telefono è infetto. <b>MSG_NEW_NUMBER_MONEY</b> (30): né il numero nuovo né la richiesta di soldi accusano da soli — è la coincidenza dei due, cioè il «ciao mamma». E uno è stato tolto un'ora dopo averlo aggiunto: «in giacenza» sembrava il tema più frequente delle campagne, ed è anche la prima riga dell'avviso vero di Poste, che ne manda milioni.
Detection/Signals/MessageContentDetector.cs misurati sul corpus italiano e su 5.574 SMS inglesi
L'IBAN da solo non accusa più
Pesava 25, cioè esattamente la soglia del sospetto: bastava un IBAN perché il prodotto gridasse. Sulle 74 conversazioni italiane vere l'unica accusata era «ti mando l'IBAN per il regalo di Luca» — e la domanda categorica ha una risposta imbarazzante, perché un IBAN in un messaggio lo manda chiunque abbia diviso una cena, un affitto o un regalo. Ora vale 20 e corrobora: dentro una truffa vera un IBAN non è mai solo, gli stanno accanto la fretta, il conto di appoggio o il numero nuovo, e la somma passa la soglia lo stesso.
Detection/Signals/MessageContentDetector.cs il falso allarme è sparito, le truffe con IBAN restano prese

🧠 Apprendimento locale

Quello che esce non può contenere un indirizzo, un messaggio o un nome — non è un dato reso anonimo, è un dato che non ha mai riguardato nessuno.

Quello che l'analisi pagata ha già deciso
Chiave = fascia di punteggio + sigle dei segnali, mai un indirizzo. Tre accordi e zero disaccordi per diventare regola, un disaccordo squalifica per sempre. 500 voci, dimentica dopo 90 giorni.
Core/Learning/LessonBook.cs verde nei test
Le tue abitudini di navigazione
Dalla cronologia locale, per utente Windows, solo in memoria e mai su disco. Tre pagine distinte fanno un'abitudine, 120 giorni indietro.
Service/FamiliarDomainsStore.cs misurato su una cronologia vera: 1 falso allarme su 1.053 indirizzi
La grammatica che non sa dire un dato personale
Il consenso si difende col formato, non con una promessa: ^[0-9]{1,4}\|[A-Z][A-Z0-9_]{0,39}(+…){0,19}$.
Core/Learning/SharedExperience.cs verde nei test
La query dell'indirizzo non si tiene
Il motore deve leggere tutto l'indirizzo — il marchio imitato sta spesso nel percorso o nella query — ma <b>tenerlo scritto e' un altro gesto</b>. Il filtro esisteva, <code>NavigationFilter.Sanitize</code>, e stava su una sola delle due strade che portano allo stesso tavolo: l'estensione era filtrata, il controllo che legge la cronologia del browser no. Letto nel database di questa macchina il 21 agosto 2026: <code>signin.ollama.com/api/login?…&amp;state=&lt;blob&gt;&amp;authorization_session_id=01KW32…</code> e otto ricerche su Google coi termini interi. Ora il taglio si fa <b>una volta sola</b>, nel punto in cui un'analisi diventa un ricordo, quindi vale per cronologia, registro, risposta all'estensione e cruscotto insieme. Le correzioni gia' salvate vengono portate alla forma nuova all'avvio: senza, una persona che aveva detto «questo sito e' sicuro» si sarebbe rivista l'avviso senza che nulla dicesse perche'.
Core/WrittenDown.cs · Detection/ThreatAnalyzer.cs · Storage/OverrideStore.cs letto sul database del prodotto installato; 17 test, e quelli sul motore assemblato provano anche che la query resta visibile all'analisi
Il file che leggeva chiunque su questo PC
La cronologia sa di chi e': il canale legge chi chiama dalla connessione e la query chiede <code>WHERE owner IS $owner</code>. Sotto, il file dove quelle righe vivono aveva i permessi predefiniti di <code>%ProgramData%</code>. Misurato: <code>SYSTEM FullControl · Administrators FullControl · <b>Utenti ReadAndExecute</b></code> — cioe' un account qualsiasi della macchina apriva <code>cetrai.db</code> con un qualunque strumento SQLite e leggeva la cronologia di tutti, <b>senza chiedere niente al prodotto</b>. La separazione era vera e stava un piano sopra la cosa che difendeva. Il file non lo apre nessuno tranne il servizio — cruscotto e <code>cetrai</code> passano dal canale — quindi chiuderlo non costa niente. Fatto a ogni avvio e non nell'installazione, per la ragione che la cassaforte delle copie aveva gia' imparato: i permessi messi una volta li perde la prima riparazione.
Platform.Windows/PrivateStateFiles.cs · Service/StateLockdown.cs ACL letti sulla macchina prima e dopo
Esperienza condivisa fra installazioni
Spenta nel pacchetto perché non esiste un indirizzo a cui parlare, non perché non funzioni: la schermata di consenso non viene nemmeno compilata — la domanda si fa solo quando esiste una risposta. Il giro completo è stato eseguito su questa macchina, client vero contro backend vero: due installazioni concordano su una forma, la terza la riceve e la adotta («ricevute 2 da 5 installazioni, 1 nuova qui»). Una regola «Safe» non può attraversare il filo in nessuna direzione, così un voto falso può al massimo produrre un falso allarme visibile, mai far tacere una minaccia vera.
Core/Learning/SharedExperience.cs eseguito su HTTP vero contro il backend

🔒 Ransomware

Rilevamento e avvisi anche in Free. Copie e ripristino: Premium.

Rilevamento a finestra di 2 minuti
25 file, 3 cartelle, 5 file rotti, note di riscatto in 2 cartelle. «Rotto» si stabilisce dal numero magico dell'intestazione, non dall'estensione.
Core/Ransom/ provato su un attacco inscenato: 120 file, fermato al quinto
L'attesa fra i tentativi segue il ritmo dell'attacco
I file persi durante la risposta sono due addendi con cure diverse: la <b>soglia</b> (cinque file rotti, e non si abbassa senza abbassare la prudenza) e il <b>tubo</b> — il tempo fra la certezza e il congelamento. Windows dice chi tiene un file solo <b>mentre</b> lo tiene, quindi fra un tentativo e l'altro bisogna dare all'attaccante il tempo di aprire il prossimo: era fisso a 400 ms, scelto contro l'attacco inscenato che ne scriveva quattro al secondo. Lì vale un file e mezzo; contro uno da trecento al secondo vale centoventi file per giro, e i giri sono tre. Ora è il doppio dell'intervallo mediano osservato, fra 25 e 400 ms — e quando il ritmo non è noto resta 400, perché non sapere non è una ragione per avere fretta.
Core/Ransom/AttackResponse.cs · EncryptionBurstDetector.cs misurato: a 300 file/s la risposta costa 111 file invece di 448, e a 4 file/s non cambia niente
La domanda a Windows parte prima della certezza
Chiedere chi tiene aperti i file costa ~90 ms, e si pagavano <b>dopo</b> essere certi — nell'unico momento in cui ogni millisecondo è un file. Ora la domanda parte quando l'attività è solo anomala, insieme alla copia di salvataggio: guarda e basta, il diritto di agire continua a nascere dalla certezza. Non rende il dato più vecchio, lo rende pronto — anche prima si agiva su un elenco catturato quando la domanda <i>partiva</i>. E se alla certezza non è ancora tornata <b>si aspetta quella</b> invece di rifarla: era il difetto del primo disegno, perché il salto fra anomalo e certo a 300 file/s dura 67 ms, meno della domanda stessa, e scartarla avrebbe buttato via il vantaggio proprio dove è l'unico che conta. Oltre 1,5 s si ricomincia: più in là non è «poco prima», è un'altra fase dell'attacco.
Service/RansomGuard.cs · Core/Ransom/AttackResponse.cs misurato a due velocità: a 50 file/s alla certezza resta 0 ms, a 300 ne restano 25 invece di 98
La certezza arriva al 10° file se l'attacco è a raffica
Il pavimento dei file persi non era la latenza della risposta: era la <b>certezza</b>. Finché servono 25 file per esserne certi, 25 file sono persi a qualunque velocità. Abbassare il numero e basta sarebbe meno prove per congelare il programma di qualcuno, quindi la terza gamba è il <b>ritmo</b>: dieci file resi illeggibili, in tre cartelle diverse, con intervallo mediano sotto 200 ms. La domanda categorica — quale programma onesto fa questo? — è stata scritta a mano nelle sue risposte candidate: la compilazione è veloce e larga ma quello che scrive è <b>valido</b> per il proprio tipo; il convertitore rovina anche, ma in una cartella sola; il client di sincronizzazione che si pianta lascia file davvero troncati in più cartelle, ma nell'arco di minuti. Se la raffica annega dentro un pomeriggio di lavoro la mediana la fa il lavoro, la regola tace e la certezza arriva comunque per la strada da 25.
Core/Ransom/EncryptionBurstDetector.cs misurato file per file: attacco lento certezza al 25°, a 300 file/s al 10°
Copie a contenuto indirizzato
Lo stesso documento in 50 copie costa una copia sola. Ogni 6 ore, ~40 estensioni non riscaricabili, max 64 MB per file; mai appdata, .git, node_modules, Windows, Programmi.
Service/RansomGuard.cs verde nei test
Lo sfratto toglie dal mezzo
5 GB di tetto. La copia più vecchia e le tre più recenti si tengono, perché durante un attacco le recenti contengono i file già cifrati.
Core/Ransom/ verde nei test
L'archivio si congela sotto attacco
Mentre l'attacco è in corso non si copia e non si sfratta più niente.
Service/RansomGuard.cs verde nei test
Chi sta scrivendo, senza driver
Restart Manager, chiedendo dei file non ancora toccati: Windows avvisa solo dopo la chiusura.
Platform.Windows/Ransom/ provato su attacco inscenato
Congelato, non ucciso
La chiave di cifratura sta nella memoria del processo: ucciderlo la butta via. Reversibile con «cetrai resume --pid». Mai processi di sistema, mai i nostri, mai senza percorso leggibile, e più di un candidato = nessuno.
Platform.Windows/Ransom/ provato su attacco inscenato
Ripristino a secco per difetto
Il prodotto sceglie da sé l'ultima copia certamente intatta — quella prima dell'inizio — e scrive solo se glielo si chiede. Le copie le leggono solo LocalSystem e amministratori: la cassaforte contiene i documenti di tutti.
Service/RansomGuard.cs verde nei test
Prova su un ransomware vero
La detonazione vera resta fuori portata: un limite dichiarato in ADR-0014, non una svista, e serve un laboratorio che la isoli. Nel mezzo c'è però un intermedio che prima mancava: un attacco <b>benigno</b> ma dalla forma vera — legge file veri, li riscrive con byte ad alta entropia, li rinomina in <code>.locked</code>, a raffica e su più cartelle, dentro una sandbox temporanea — che guida il <code>FileSystemWatcher</code> vero. Provava la <b>giunzione</b> che nessuno provava: che un attacco vero venga visto come tale (raggiunge <code>Attack</code>) e che i file nominati siano davvero quelli sotto attacco. Il lavoro onesto in una cartella sola resta a <code>Watching</code>, così il numero non è comprato accusando chi scrive in fretta.
docs/adr/ADR-0014 · tests/CetrAI.Platform.Tests/RansomwareSimulationTests.cs la detonazione reale resta da fare in laboratorio; il comportamento è provato end-to-end
Cartelle sorvegliate oltre quelle di Windows
Chi tiene il lavoro in <code>D:\Progetti</code> guardava una stanza vuota: l'attacco cifrava l'unica cartella che contava senza che un solo evento arrivasse al rilevatore, e il cruscotto diceva «tutto tranquillo». Ora le cartelle si <b>deducono</b> invece di assumerle, e senza chiedere niente a nessuno: le scorciatoie che Windows scrive in «Recent» dicono quali file una persona ha davvero aperto. Misurato su questa macchina: 132 scorciatoie, 108 leggibili, <b>65 fuori dal profilo</b>, che si raggruppano in tre cartelle di lavoro vere. Le scorciatoie si leggono byte per byte e non chiedendo alla shell di risolverle, perché <code>IShellLink::Resolve</code> quando il file è sparito si mette a cercarlo e può bloccarsi su una condivisione di rete — dentro un servizio che gira come LocalSystem non è accettabile. Le cartelle dedotte entrano nella <b>sorveglianza</b> e non nelle copie: un osservatore è una sottoscrizione del kernel e non costa niente, una copia di una cartella scelta perché è enorme riempirebbe il disco della persona che dovrebbe proteggere.
Platform.Windows/Ransom/WorkFolders.cs · ShellLinkTarget.cs eseguito dal servizio installato: «Sorveglianza attiva su 8 cartelle personali», e tre sono fuori dal profilo — C:\xampp, C:\ProgLLama, C:\dev
Le cartelle che la macchina si ricostruisce da sola
Nato dalla riga qui sopra e misurato prima di scriverlo: se il lavoro entra nella sorveglianza, ci entra anche un albero di sorgenti — e una <b>sola compilazione ha scritto 289 file, tutti e 289 dentro <code>bin</code> e <code>obj</code></b>, contro una soglia che si allarma a 25 file in 3 cartelle. Senza filtro la protezione ransomware sarebbe passata a «attività insolita» a ogni compilazione, cioè decine di volte al giorno, e un allarme che scatta sempre non è un allarme. Ignorate <code>bin obj node_modules .git dist target __pycache__ venv packages</code>: un ransomware che cifrasse solo <code>node_modules</code> non avrebbe distrutto niente, perché quelle cartelle sono riproducibili per definizione — ed è esattamente la ragione per cui si possono ignorare.
Platform.Windows/Ransom/PersonalFolderMonitor.cs il filtro regge sui 289 file di una compilazione, ma da solo non bastava: il livello che scattava non tornava indietro, e la riga sotto ha i numeri veri
«Attività insolita» non finiva mai, e si mangiava la storia
Questa riga diceva «lasciata com'è, e questa è la misura»: <b>44 copie periodiche contro 9 da attività insolita</b> su quindici giorni, meno di una al giorno. Il numero era vero e la conclusione sbagliata, perché il denominatore era una macchina su cui il servizio <b>ripartiva più volte al giorno</b> — e ogni riavvio azzerava il livello. Contati i giorni in cui il servizio è rimasto su: <b>20 agosto 0 periodiche e 86 insolite, 21 agosto 0 e 110</b>. Su tutti i registri, 12 periodiche contro 436 insolite.<br><br>La causa è una riga sola: il livello era il <b>ricordo dell'ultimo avviso</b>, e gli avvisi arrivano solo quando il quadro <b>peggiora</b> — per il miglioramento non esiste evento, quindi non tornava indietro mai fino al riavvio. Bastano 25 file in due minuti, cioè una sincronizzazione della nuvola o un'importazione di foto. E a quel livello il prodotto <b>copia ogni cinque minuti</b>, <b>rilegge ogni file dal primo byte</b> perché le date non si credono più, e <b>sfratta</b> per far posto: 193 sfratti in due giorni, circa 31 GB letti al giorno da ferma, e la storia recuperabile ridotta a circa <b>un'ora e mezza</b> — su una promessa che vale settimane. Il pannello «I tuoi file» diceva «attività insolita» da giorni. Ora il livello si <b>legge</b> dal rilevatore ogni volta, e la finestra di due minuti si svuota da sola; l'unica cosa che resta in memoria è la <b>certezza</b>, perché a disco fermo durante un attacco l'archivio deve restare congelato lo stesso.
Service/RansomGuard.cs · Core/Ransom/EncryptionBurstDetector.cs · Platform.Windows/Ransom/PersonalFolderMonitor.cs letto sui registri del prodotto installato: 0 copie periodiche in due giorni interi; i cinque test cadono se la correzione si toglie
Il budget contava le copie, il disco ne teneva una
Trovato tirando il filo della riga qui sopra. Lo stesso documento in cinquanta copie occupa <b>una</b> copia sola — è la riga che rende sostenibile tenere settimane di storia — ma il budget sommava il peso di <i>ogni</i> copia come se stesse tutta sul disco. Misurato: 9.967 file per <b>293 MB</b>, quindi diciassette copie facevano 5 GB e l'archivio cominciava a sfrattare mentre di spazio ne occupava 293 MB, <b>sotto il sei per cento</b> di quello che gli era concesso. Il campo si chiamava «quanto contenuto <i>nuovo</i> ha aggiunto» ed era giusto dove veniva scritto; chi elencava l'archivio ci metteva invece il peso totale del manifesto, e le due cose avevano lo stesso nome. Ora il peso lo dà il deposito — contenuto identico contato una volta — e lo sfratto chiede quanto libererebbe davvero: <b>una copia che non tiene niente di suo non si butta</b>, perché costerebbe un giorno di storia e non un byte di spazio.
Core/Ransom/SnapshotPolicy.cs · Storage/FileSnapshotStore.cs 193 sfratti in due giorni sul prodotto installato; due test cadono se la correzione si toglie
Il sorvegliante era cieco proprio quando serviva
Il commento in cima al sorvegliante diceva che l'overflow del buffer «è trattato come un segnale a sé». <b>Non lo era</b>: il gestore scriveva una riga nel registro e tornava. La frase descriveva un'intenzione e si leggeva come un comportamento, e nessun test poteva contraddirla — <b>i commenti non si eseguono</b>. L'ha smentita il prodotto installato: 13 overflow in un giorno su <code>C:\xampp</code> (4 il 13 agosto, 7 il 14), nessuno arrivato al rilevatore. Ora ci arriva, e <b>non come accusa</b>: quel ritmo lo producono una compilazione, uno scompattamento, una copia grossa. Quello che è davvero è una <b>misura del ritmo</b> — e il ritmo è già una delle tre gambe dell'allarme, oggi stimata su ciò che si è visto, mentre l'overflow lo dimostra direttamente perché è il sistema operativo a dire che non stava dietro. Quindi la cecità <b>sostituisce</b> la prova del ritmo e lascia obbligatorie ampiezza e distruzione. E il rovescio conta di più: un attacco abbastanza veloce da riempire il buffer è esattamente quello che sfuggiva alla regola dei tre elementi, perché i file che completerebbero il conteggio sono quelli persi. Due cose in più: il vigilante viene <b>rimesso in ascolto</b> (dopo un errore può smettere di consegnare eventi, e un sorvegliante spento è indistinguibile da una cartella tranquilla), e quando un giudizio viene mostrato dice anche <b>quello che non ha potuto vedere</b> — «è un minimo, non un totale».
Core/Ransom/EncryptionBurstDetector.cs · Platform.Windows/Ransom/PersonalFolderMonitor.cs provato nei due versi: 10 file rotti in 3 cartelle <i>lenti</i> passano da Osservo ad Attacco con la cecità, e 200 file validi di una compilazione cieca restano sotto

🪟 Integrazione con Windows

Ponte con Defender
Otto proprietà lette da WMI, non da PowerShell: servizio antivirus, tempo reale, comportamenti, controllo download, protezione cartelle, anti-manomissione, età firme, ultima scansione.
Platform.Windows/WmiDefenderBridge.cs provato sul prodotto installato
Protezione cartelle personali
Macchina a stati: osserva 7 giorni, legge dal registro eventi di Defender cosa avrebbe bloccato, autorizza quei programmi, poi accende il blocco. Avanza da sola su un orologio — prima aspettava che qualcuno premesse un pulsante che nessuno premeva.
Service/FolderShieldWatch.cs letto nel registro del prodotto installato: «in osservazione da 6 giorni: servono 7 giorni»
Blocco di rete
Filtri WFP in sessione dinamica: spariscono se il processo muore, quindi un servizio in crash non può lasciare una macchina tagliata fuori. Tetto di 256 host.
Platform.Windows/ provato con gli occhi: filtri 16 → 18 nel motore di Windows, bersaglio irraggiungibile, e tutto torna alla scadenza
Cronologia di sei browser
Chrome, Edge, Brave, Vivaldi, Opera, Firefox. L'unico posto del prodotto che la legge, e la cartella del profilo arriva da chi chiama: non viene mai cercata.
Platform.Windows/ provato sul prodotto installato
Riavvio automatico del servizio
Il servizio configura da sé le azioni di ripristino di Windows a ogni avvio, invece di lasciarlo all'installatore.
CetrAI.Service/ provato sul prodotto installato
Avvio sulla scrivania dell'utente
Il servizio vive in sessione 0 e avvia la finestra nella sessione di chi sta usando il computer. Serve dopo un aggiornamento, quando nessun altro lo farebbe fino al logon successivo — dopo un aggiornamento il prodotto spariva dalla scrivania.
Platform.Windows/InteractiveSession.cs · Service/TrayPresence.cs provato su un secondo PC, aggiornamento reale
Il prodotto si accorge quando smette di lavorare
Ogni lavoro batte un colpo e il registro dei battiti dice chi tace da troppo — la tolleranza è due volte e un quarto l'intervallo dichiarato dal lavoro stesso, non una costante scritta a mano. Il tempo si conta senza il sonno: un portatile chiuso per la notte produce lo stesso silenzio di un lavoro morto. Difetto trovato leggendo il registro di questa macchina: l'orologio predefinito contava il sonno, e tredici minuti dopo il risveglio l'utente si è visto dire «da 14 ore la lista delle minacce non si aggiorna, riavvia il computer». Ora l'orologio va passato per forza, non c'è più un valore predefinito su cui sbagliare.<br><br>Secondo difetto, letto sullo stato del prodotto installato sette ore dopo un'installazione pulita: <b>«da 6 ore la lista delle minacce non si aggiorna … riavvia il computer»</b> — a proposito di liste che nel pacchetto sono <b>spente per scelta</b>. I due lavori che si possono spegnere uscivano senza dire niente al registro, e il commento sopra a uno dei due diceva perfino che «un lavoro spento non è un lavoro che tace»: era vero come intenzione e falso come effetto, perché il registro giudica tutti i segni e uno che nessuno ha reclamato tiene la tolleranza predefinita, non risponde mai, e dopo tre ore risulta guasto. Nessun riavvio poteva togliere quel messaggio, mai. Sul <b>piano gratuito</b> lo stesso buco copriva le copie di sicurezza: ogni installazione Free si sarebbe dichiarata rotta poche ore dopo, per una funzione che non aveva comprato. Ora la dichiarazione è simmetrica — un lavoro dice ogni quanto gira <b>oppure</b> che non gira — e chi riaccende torna sorvegliato al primo colpo battuto, così il silenziatore non diventa un punto cieco.
Core/Vitals.cs · Service/FeedUpdater.cs · Service/RansomGuard.cs difetti letti sullo stato del prodotto installato; i due test cadono se la correzione si toglie
Riaccendere Defender quando è spento
Il ponte vedeva la protezione in tempo reale spenta e sapeva solo dirlo, cioè assegnare un compito a casa proprio a chi non sa dove sta l'interruttore. Ora il servizio la riaccende da solo, due volte al giorno, con tre rifiuti scritti in una funzione pura e provati come tale. <b>Se c'è un altro antivirus non si tocca niente</b>: Windows spegne Defender apposta quando qualcun altro si registra, e «aggiustare» quella macchina vuol dire metterci due scanner in tempo reale sugli stessi file — la lista viene da <code>root\SecurityCenter2</code>, la stessa che mostra Sicurezza di Windows. <b>Se lo stato non si legge non si scrive</b>: una risposta mancata non è un «no». <b>E un rifiuto si ricorda</b>: la protezione da manomissioni accetta la richiesta e non la applica, quindi si chiede, si <b>rilegge l'impostazione</b> (il codice di ritorno zero non è una prova: sono parole di Microsoft), e se non è cambiata non si insiste due volte al giorno per sempre — né contro il sistema operativo né contro una persona che l'ha spenta apposta.
Core/RealTimeProtectionPolicy.cs · Platform.Windows/DefenderRealTime.cs · Service/RealTimeProtectionWatch.cs lettura provata su questa macchina (0 antivirus di terzi); il ramo che scrive non è stato eseguito qui, perché cambierebbe un'impostazione di sicurezza di una macchina dove la protezione è già accesa
L'icona che non c'era
Installato da amministratore il 16 agosto: servizio attivo, tutto verde, e <b>nessuna icona nell'orologio</b>. Il tray si piantava a ogni avvio — due volte, una lanciata dall'MSI e una dal servizio — con <code>TypeLoadException: System.Private.Windows.Core.OsVersion</code> dentro <code>ScaleHelper</code>, alla prima voce di menu. La causa era la lettura dei QR: <code>System.Drawing.Common</code> <b>10.0.11</b> su un runtime <b>net9.0</b> depositava nella cartella pubblicata un <code>System.Private.Windows.Core</code> 10.0 accanto al WinForms 9.0 del runtime desktop. <b>Nessun test poteva vederlo</b>: il difetto non sta in una riga di codice, sta nel <i>comporre la cartella</i>, e la decodifica QR nei test gira in un processo senza finestre. Il controllo che lo prende non legge niente e non è un test: <code>tools\verifica.ps1</code> <b>avvia il tray costruito e guarda se è ancora vivo</b>. Rimesso il 10.0.11 apposta, quel passo fallisce.
Platform.Windows/*.csproj · tools/verifica.ps1 tray del pacchetto (msiexec /a) vivo dopo 10s; col difetto rimesso muore in 6s, uscita 0xE0434352
Un commento che ha fatto fallire l'installazione
Il pacchetto 0.1.5508 non si e' installato: <b>«Error 1920: il servizio CetrAI non parte»</b>, tre tentativi, poi rollback, e la macchina e' rimasta col prodotto precedente — che e' il motivo per cui il servizio si chiamava ancora AIDefender il giorno dopo. La causa e' una riga di commento. Questo progetto scrive il perche' accanto all'impostazione, e una di quelle spiegazioni era finita <b>dentro</b> <code>Logging:LogLevel</code>, dove ogni chiave e' una regola di filtro e il suo valore dev'essere un livello: il framework ha letto <code>_commento_http</code> come regola, ha rifiutato il valore e ha lanciato mentre costruiva l'ospite — <b>prima che esistesse un registro dove dirlo</b>. Nei commenti delle altre sezioni non succede, perche' quelle si legano a una classe che ignora i campi che non conosce.<br><br>Il difetto peggiore pero' non e' il commento: e' che il <b>guardiano non ha guardato</b>. L'avvio di prova dentro <code>build.ps1</code> esiste apposta per questo dal giorno in cui un pacchetto non partiva, e ha dato verde. Due omissioni, ognuna sufficiente da sola: partiva <b>senza cartella di lavoro</b>, e fuori dal servizio Windows la radice del contenuto e' la cartella corrente — quindi cercava <code>appsettings.json</code> nella radice del progetto, dove non c'e', e provava l'eseguibile <i>senza la configurazione che il pacchetto spedisce</i>; e catturava <b>solo lo stdout</b>, mentre un ospite che muore durante la costruzione non ha ancora un registro e la sua ultima parola esce dallo stderr. Il controllo decideva su un file vuoto. Ora la prova gira nella cartella di staging, legge tutti e due i flussi, e c'e' un test che carica <b>i due appsettings veri</b> — non una copia — e costruisce il registro con la stessa chiamata del framework.
installer/appsettings.json · installer/build.ps1 · tests/CetrAI.Platform.Tests/ShippedSettingsTests.cs riprodotto e corretto: dallo staging il servizio moriva con InvalidOperationException, ora si avvia; il test fallisce se la riga viene rimessa. Il pacchetto 0.1.5509 e' costruito — <b>l'installazione va rifatta</b>
Il blocco che spegneva GitHub Pages
Trovato nello stesso collaudo, ed è il difetto più grave della giornata perché <b>toglie internet senza dirlo</b>. Analizzato <code>poste-accedi.github.io</code>, il servizio l'ha giudicato Pericoloso, ne ha risolto i quattro indirizzi — <code>185.199.108-111.153</code>, che sono quelli di GitHub Pages <i>e di nessun altro</i> — e li ha bloccati <b>su tutto il PC per trenta giorni</b>. Con quel filtro in piedi <code>metamask.github.io</code> non si apriva; tolto, rispondeva 200. Nessun avviso: un pezzo di internet spento e nessun modo, per la persona, di collegarlo a noi. La regola «infrastruttura condivisa» <b>esisteva già</b> — il difetto è che fosse <b>solo una lista di intervalli IP</b>, e che quella lista avesse le reti di consegna (Cloudflare, Fastly, Akamai) e non le piattaforme dove il sito lo apre chiunque, che è esattamente dove il phishing sta perché costa zero. Due riparazioni, e la prima è quella che non invecchia: il blocco ora <b>guarda il nome prima dell'indirizzo</b> — sotto una piattaforma che affitta sottodomini non si blocca per IP, punto, e resta il blocco nel browser che agisce sul nome esatto. Poi i nove intervalli mancanti (GitHub Pages, Vercel, Netlify, Firebase, WordPress.com, Shopify, Squarespace, Wix). È lo stesso difetto della riga sui marchi, un piano più sotto: <b>anche l'indirizzo IP è un palazzo con mille inquilini.</b>
Core/Network/TenantPlatforms.cs · SharedHostingRanges.cs · Wfp/WfpNetworkBlocker.cs provato nei due versi sul prodotto installato: col blocco metamask.github.io irraggiungibile, tolto il blocco HTTP 200

👁 Le difese che non guardano né indirizzi né testo

La parte che nessun antivirus copre: la truffa non è un virus.

Il finto operatore bancario
Avvisa quando parte un programma di controllo remoto arrivato da poco sul computer. Il segnale non è il programma — centinaia di migliaia di persone lo usano onestamente — ma quando è arrivato: chi ci lavora l'ha installato mesi fa, chi sta per essere derubato durante la telefonata in corso. Avvisa, non blocca.
Core/RemoteHelp.cs · Service/RemoteControlWatch.cs provato sul prodotto installato; base misurata: 229 processi, 0 nominati
L'IBAN sostituito negli appunti
A tradire il malware non è il secondo IBAN — se ne possono copiare due — ma la velocità: deve vincere la corsa contro l'incolla, e sostituisce in millisecondi. Cifre di controllo calcolate davvero, sennò un numero di fattura armerebbe un allarme sul denaro. Vive nel tray, perché gli appunti appartengono a una window station e il servizio non ne ha una.
Core/PaymentClipboard.cs · Tray/ClipboardGuard.cs provato sul prodotto installato
Il sito che può interromperti a browser chiuso
La cronologia è un ricordo che sbiadisce; un permesso di notifica è un invito che resta finché qualcuno non lo ritira, ed è la strada per cui il finto «il tuo antivirus è scaduto» arriva senza che tu stia navigando. Trovato il 21 agosto 2026 sulla macchina di sviluppo, mentre il prodotto era installato: la cronologia aveva letto la visita, il motore le aveva dato zero e aveva detto «nessun problema rilevato», e il permesso che quella visita aveva lasciato non lo guardava nessuno. Ora il controllo lo legge nei tre browser e lo toglie. Se il browser è aperto non chiede di chiuderlo: aspetta, e finisce da solo appena si chiude.
Core/MachineMadeName.cs · Platform.Windows/Browsing/NotificationPermissions.cs · Service/StandingInvitations.cs · Service/InterruptionCleanup.cs forma misurata su Tranco 1M: 1.652 etichette accusate su 870.305 (0,19%), lette una per una, e i due nomi veri che sbaglia stanno in un test; non toglie mai sulla sola forma. Resta da premere SCANSIONA sul pacchetto installato
Una riga al mese
Solo quando c'è qualcosa da dire. Chi non vede mai succedere niente smette di credere che il prodotto ci sia.
Core/MonthlyWord.cs verde nei test
Chat e scambi dentro il gioco
Spenta, e non per mancanza di tempo: la chat di Roblox e la finestra di scambio non passano da nessuna interfaccia di Windows, quindi leggerle vuol dire entrare nel processo del gioco. Ogni anticheat lo tratta — giustamente — come un attacco, e il prezzo lo pagherebbe il bambino con l'account bannato. Quello che passa davvero da fuori si legge gia': i messaggi incollati, la pagina nel browser (Discord, Instagram) e i link dentro il testo.
browser-extension/ · Detection/Analysis/LinkFinder.cs vincolo della piattaforma, non del prodotto
Punteggio di affidabilità di chi scambia
Non è lavoro arretrato: è una cosa che questo prodotto non può misurare, e lasciarla fra le cose «da fare» la faceva sembrare una questione di tempo. Servirebbero l'anzianità dell'account e la cronologia degli scambi dell'altro giocatore, che stanno sui server dell'editore e che nessuna API pubblica dà. Quello che si potrebbe calcolare qui — da quanto quel nome compare nella chat, quante volte è stato visto — non misura l'affidabilità di nessuno: sarebbe un numero con l'aria di una misura, e un numero inventato accanto a una faccia di sconosciuto è peggio di nessun numero, perché autorizza a fidarsi.
rifiutata per mancanza del dato, non per mancanza di tempo
Il riepilogo per il genitore
La riga mensile esiste già e resta sul PC. Mandarla a un secondo destinatario cambia il prodotto in un servizio: serve un canale d'invio, quindi il backend, il consenso raccolto bene e dati personali veri. È la stessa voce di «un familiare che riceve il riepilogo», e aspetta la stessa decisione sull'indirizzo pubblico.
Core/MonthlyWord.cs
La finestra a schermo intero «chiama Microsoft»
È l'unica truffa che non sta in un indirizzo: il dominio è usa-e-getta e non significa niente, la pagina non ha link da seguire né moduli da compilare — il carico è il <b>numero di telefono</b>, e la persona lo digita sul proprio cellulare. Niente di quello che il motore legge può vederla: solo la pagina può. La forma categorica la dà Microsoft stessa, che scrive nero su bianco che i suoi messaggi di errore non contengono mai un numero di telefono. Quindi: la pagina dichiara che <i>questo</i> computer è bloccato o infetto, <b>e</b> si presenta come Microsoft o Apple, <b>e</b> non è sul loro dominio, <b>e</b> fa una delle quattro cose (schermo intero, trappola sull'uscita, allarme sonoro, oppure «chiama subito» accanto a un numero su una pagina corta). E agisce prima di parlare: zittisce l'audio ed esce dallo schermo intero, perché una persona spaventata compone il numero prima di ragionare, poi scrive sopra la pagina la frase che nessuno le sta dicendo. Misurato su 11 casi (4 truffe, 7 pagine vere difficili): l'articolo di giornale <b>che racconta questa truffa</b> ne contiene ogni parola — frase, nome, numero e fretta — e il discrimine che lo salva è la lunghezza: una schermata di truffa è un manifesto da leggere in un colpo d'occhio, un articolo è prosa.
browser-extension/content/support-scam.js · tools/prova-supporto-falso.mjs 11/11, dentro tools\verifica.ps1; la metà che tocca la pagina eseguita su un DOM finto, mai in un browser vero (l'estensione non è pubblicata)
Il QR code delle bollette false
La decisione era di catena di fornitura, non di tempo, ed è stata presa: <b>ZXing.Net</b> è la prima dipendenza non-Microsoft del prodotto. Sta dietro un confine difeso: la decodifica dell'immagine — la superficie d'attacco GDI+ — vive nel layer Windows con tetti su byte (8 MB) e pixel (40 M) che fermano una bomba di decompressione, e qualunque cosa vada storta esce come «nessun QR», mai un'eccezione; quello che attraversa il confine è solo il payload, tagliato. Il resto è il motore che c'era già: un payload URL passa agli indirizzi, un bonifico SEPA/EPC porta l'IBAN al controllo delle cifre, tutto il resto è testo in sei lingue. La bocca per l'utente c'è: una voce nel menu del tray, «Controlla un QR sullo schermo», cattura il desktop, legge il QR e dà il verdetto in un fumetto accanto all'orologio — niente da salvare o ritagliare, la regola del prodotto. È il caso vero su PC: la bolletta PDF aperta al computer, dove non c'è una fotocamera da puntare. L'immagine dello schermo non esce e non viene salvata: si decodifica in memoria, sopravvive solo il payload. <b>Eseguito dal binario del pacchetto, su uno schermo vero</b>, non a parole: la cattura schermo sta in un punto condiviso (<code>ScreenCapture</code>) che il pulsante del tray e il verbo <code>scan --qr-screen</code> chiamano identici. L'MSI è stato estratto con <code>msiexec /a</code> — i file <i>esattamente come li spedisce il pacchetto</i>, runtime self-contained, ZXing e System.Drawing compresi — e mostrando a tutto schermo un QR che manda a un dominio che imita Poste, <code>PFiles64\CetrAI\cetrai.exe scan --qr-screen</code> lo ha letto dal desktop e ha detto PERICOLO (uscita 3). Quello che valida il metro «sul pacchetto» — un difetto di impacchettamento, un file mancante — è coperto: i binari spediti girano. Resta <b>in corso</b> per l'ultimo sliver, che richiede un diritto di amministratore che questa sessione non ha: il servizio installato da MSI in Program Files e il click sull'icona del tray, che chiamano la stessa strada già eseguita.
Tray/ScreenQrScan.cs · Platform.Windows/Qr/ScreenCapture.cs · Core/Qr/ chiusa premendo il pulsante: QR a schermo pieno che imita Poste, <b>voce del menu del tray</b> sull'installazione da MSI, PERICOLO 67 registrato dal servizio alle 19:44:17 — due minuti dopo lo stesso verdetto per la via della riga di comando, che è la prova che le due bocche chiamano la stessa strada
Il verdetto che sparisce e non dice dove è finito
Detto con le parole di chi ha premuto il pulsante la prima volta: <i>«poi ho chiuso e non so cosa ha fatto»</i>. Il fumetto del QR dura otto secondi e poi non c'è più. Il verdetto <b>non</b> era andato perduto — sta nella cronologia come qualunque altra analisi, e cliccare il fumetto apre il cruscotto — ma niente lo diceva, quindi per la persona era indistinguibile da un pulsante che non finisce quello che comincia. È la regola del prodotto letta al contrario: se l'utente non deve fare niente, deve almeno <b>sapere che è stato fatto</b>. Aggiunta una riga sola al fumetto, e nessuna domanda: dove sta il risultato, e che il fumetto stesso ci porta.
Tray/ScreenQrScan.cs difetto riferito da chi ha usato il prodotto installato
Il fascicolo ha trovato un falso allarme in mezz'ora
La prima volta che qualcuno ha premuto «Prepara il fascicolo per la denuncia» sul prodotto installato, il file conteneva <b>due volte</b> <code>instagram.it.uptodown.com</code> — il <b>5.988° sito più visitato al mondo</b> — descritto come «quasi certamente una truffa», in un documento da portare alla Polizia Postale. È lo stesso difetto della riga sui marchi, su una categoria che non avevo in elenco: i <b>cataloghi</b>. Lì il sottodominio non lo sceglie un estraneo, lo sceglie il sito stesso, una voce per ogni programma elencato — il nome del marchio davanti non è una pretesa di identità, è il titolo di una scheda. <b>Dove è stato trovato conta quanto il difetto</b>: nessun corpus pubblico poteva mostrarlo, perché il milione Tranco elenca <code>uptodown.com</code> e non <code>instagram.it.uptodown.com</code>. L'ha trovato la cronologia vera di una persona — e il prodotto quella cronologia la legge già, nel controllo del PC: «494 indirizzi, 1 pericolosi». Quell'uno era questo, e nessuno leggeva quel numero come un corpus di falsi allarmi.
Core/Network/TenantPlatforms.cs · tests/RentedSubdomainTests.cs letto nel fascicolo prodotto dall'installazione, non in un test
Il fascicolo dell'incidente
«Prepara il fascicolo per la denuncia» scrive sul desktop un file di testo e apre la cartella con quello già selezionato: data, ora con fuso, indirizzo, giudizio e motivo di ogni tentativo, più i blocchi applicati. Non è rilevamento, è trascrizione — allo sportello chiedono tre cose che nessuno conserva e che il prodotto ha. Tre decisioni lo rendono un documento e non un registro. <b>Ci va solo ciò che è stato segnalato</b>: l'elenco di tutto quello che una persona ha guardato, prodotto dal suo antivirus e consegnato da lei alla polizia, sarebbe un fascicolo di sorveglianza. <b>La parte dopo il punto interrogativo è tagliata</b>, perché negli indirizzi di phishing contiene spessissimo la posta elettronica della vittima, e il taglio è dichiarato nel file. <b>Non si spaccia per una perizia</b>: dice che le ore vengono dall'orologio di quel computer e che è un file di testo modificabile, quindi vale come dichiarazione di chi lo presenta.
Core/IncidentReport.cs · Tray/DashboardWindow.xaml premuto sull'installazione: 6.573 byte sulla scrivania, nove tentativi con data, ora e motivo, letti uno per uno
Un modo per vedere che funziona senza aspettare una truffa
«Vedi come funziona» nel cruscotto analizza <code>poste.it.sicurezza-accesso.invalid/login/verifica</code>. Due decisioni lo rendono una prova invece di uno spettacolino. L'indirizzo non può essere di nessuno: il suffisso <code>.invalid</code> è riservato dalla RFC 6761 e non viene mai delegato, mentre un nome verosimile sotto un suffisso vero diventerebbe proprietà di qualcuno il giorno che lo registra. E il verdetto non è recitato: nel motore non c'è una riga che conosca quella stringa, esce PERICOLO per i due segnali veri (marchio nel sottodominio 55, percorso da pagina d'accesso) con le stesse parole di una campagna vera. Un caso speciale avrebbe dimostrato che il pulsante funziona, che non è la cosa in dubbio. I pulsanti di correzione restano nascosti: «non è una truffa» sulla dimostrazione spegnerebbe l'unica prova che la persona ha.
Core/SelfTest.cs · Tray/DashboardWindow.xaml premuto nel cruscotto installato: PERICOLO 66, registrato dal servizio alle 21:27:42
I due comandi del cruscotto sono controlli veri, e l'avevo detto sbagliato
Avevo scritto che «Vedi come funziona» e «Prepara il fascicolo» sono <i>testo, non controlli</i>, e che per un lettore di schermo non esistono — una cosa seria, visto che qui si parla di una modalità per anziani. <b>Era falso, e l'errore era nel mio strumento</b>: il cercatore prendeva il <code>TextBlock</code> che li contiene, il cui nome è tutta la frase, e si fermava lì. Chiesto a Windows per tipo invece che per nome, sono <code>Hyperlink</code> con il modello <code>Invoke</code> e <code>IsKeyboardFocusable</code> vero: un lettore di schermo li annuncia come collegamenti e la tastiera li raggiunge. La prova è che uno di loro è stato <b>premuto dall'automazione</b> e il servizio ha registrato il verdetto. Resta aperta, e separata, una domanda che questa misura non tocca: sono testo da 11 punti in fondo a un'area che scorre, e chi li ha cercati ha premuto due volte il pulsante sbagliato — ma è una persona sola, e su una persona sola non si ridisegna niente.
Tray/DashboardWindow.xaml chiesto a Windows: ControlType.Hyperlink, Invoke, focus da tastiera

Superficie di comando

Canale locale, 11 operazioni
Ping, Scan, Status, History, Feedback, RansomStatus, Restore, FolderShield, Checkup, Blocks, Unblock. Messaggi max 64 KB, 4 minuti per conversazione così un client che tace non porta via il canale a tutti.
Core/Ipc/IpcContracts.cs provato sul prodotto installato
Chi chiama si riconosce dal token
Mai da quello che dichiara. Utenti autenticati leggono e scrivono; solo amministratori e LocalSystem possono alterare il canale — provato: un utente normale che prova a prendersi il nome del tubo riceve ACCESS_DENIED. E vale anche al contrario: il 13 agosto il servizio <b>pubblicato</b> è stato avviato a mano da un utente normale, ha dichiarato «in ascolto sul canale CetrAI.Service», e il comando pubblicato lo ha <b>rifiutato</b> — perché guarda chi ha creato il tubo, non chi dice di essere. Il rifiuto era giusto; sbagliato era il rimedio stampato accanto, «dotnet run --project src/…», una cartella di sorgenti che su una macchina installata non esiste. Ora dice <code>sc start CetrAI</code> e spiega perché una copia avviata a mano è indistinguibile da un servizio spento.
Service/IpcServer.cs · Cli/Program.cs eseguito fra i due binari pubblicati, senza installare
Il canale occupato aspetta invece di spegnersi
Prima quell'eccezione portava giù l'intero prodotto: sei morti del servizio in un giorno solo. Ora riprova all'infinito e lo dice nel registro una volta ogni cinque minuti.
Service/IpcServer.cs provato tenendo il canale con un altro processo
Riga di comando, 11 verbi
scan, status, scansiona, blocks, netblock, feedback, harden, watch, snapshot, restore, resume. Ogni forma stampata nell'aiuto è coperta da un test, perché una di esse non aveva mai funzionato.
src/CetrAI.Cli/CliArguments.cs provato sul servizio in esecuzione, e la prova fallisce se si rimette il difetto
Cruscotto
Sette righe di protezione, avvisi, stato browser per browser, attività, un riquadro per analizzare un indirizzo a mano, e una finestra «cosa fa» a un clic dal nome del prodotto: diciotto capacità in sei gruppi, una riga ciascuna. In fondo alla stessa finestra restano i dieci limiti dichiarati, senza il dettaglio lungo — toglierli sarebbe stata l'unica modifica capace di fare male a qualcuno, perché chi crede di aver comprato un antivirus smette di stare attento.
src/CetrAI.Tray/ provato sul prodotto installato
Il cruscotto sta in un processo suo
L'icona che resta accesa tutto il giorno pesa 33 MB; la stessa icona dopo aver aperto la finestra una volta ne pesava 76, e non li restituiva più — né chiudendo la finestra né forzando una raccolta compattante. Quasi tutto è di WPF (una finestra vuota ne pesa 42,8) e l'unica cosa che li rende è la fine del processo. Ora la finestra è un processo a parte. Misurato sui processi del prodotto installato: vassoio 37,0 MB da solo e 37,0 anche dopo aver aperto e chiuso la finestra, cruscotto 61,9 MB finché è aperto e zero appena si chiude; aprirlo una seconda volta non ne avvia un altro, alza quello che c'è già ed esce con 0.
src/CetrAI.Tray/App.xaml.cs provato sul prodotto installato

🧩 Estensione per il browser

Chrome, Edge e Firefox. Manifest V3.

La pulizia del nome vecchio girava dove non poteva riuscire
Il ponte aveva gia' la rimozione delle voci lasciate da <code>it.aidefender.host</code>, e girava a ogni installazione. Le voci personali pero' stanno nel profilo della persona, l'installazione gira come LocalSystem, e aprire in scrittura il ramo di un altro account puo' essere negato: il rifiuto finiva in un <code>catch</code> che <b>non scriveva niente</b>. Misurato su questa macchina otto giorni e quattro installazioni dopo il cambio di nome: <code>it.aidefender.host</code> ancora presente per Chrome, Edge e Firefox, tutte e tre verso <code>C:\Program Files\AIDefender\…</code> che non esiste piu', e zero righe nel registro delle installazioni. Ora la pulizia sta anche dove <b>puo'</b> riuscire — nel programma che gira come la persona a ogni avvio del cruscotto — e il ramo muto parla: si guarda prima in sola lettura, cosi' «negato» smette di essere indistinguibile da «li' non c'e' niente», e cio' che resta lo dice per nome.
BrowserBridge/NativeHostRegistration.cs eseguito sul registro vero: le tre voci sono sparite dalla macchina, e il test cade se si toglie la chiamata
Filtro di riservatezza
Toglie query e frammento prima che l'indirizzo lasci la pagina: passano solo schema, host e percorso. La stessa regola è riapplicata dal lato del ponte, perché un host non deve fidarsi di chi lo chiama, nemmeno di un chiamante scritto da noi.
browser-extension/ verde nei test
Riconoscimento del browser da chi ha avviato il ponte
Non da quello che l'estensione dichiara — è la cosa che stiamo verificando — e legge solo il <b>nome</b> del processo, mai il percorso o la riga di comando, che conterrebbe il profilo in uso. <b>Guardava il padre, e il padre non è il browser.</b> Misurato il 18 agosto mentre tutti e due i browser stavano proteggendo pagine: <code>cetrai-bridge.exe &lt;- cmd.exe &lt;- chrome.exe</code>, e identico con <code>msedge.exe</code>. Chromium avvia gli host nativi passando da una shell, quindi il padre è <code>cmd</code>, che non è un browser, quindi la risposta era nulla — e il cruscotto diceva <b>«collegato, mai sentito»</b> di un browser a cui aveva appena risposto tre volte, e lo avrebbe detto per sempre. Questa riga diceva «provato sul prodotto installato» e non lo era mai stato: il test che esisteva conteneva perfino la prova (<code>cmd</code> → nessuno) e la leggeva come comportamento corretto. Ora si risale la catena fino a quattro livelli, si salta chi non si riconosce, e vince il browser <b>più vicino</b>: uno aperto da un altro ne mette due in catena, e attribuire la protezione a quello sbagliato sarebbe dire a qualcuno che è coperto dove non lo è.
BrowserBridge/WhoStartedUs.cs · tests/WhoStartedUsTests.cs catena misurata sui processi vivi; la riga verde nel cruscotto si vede solo reinstallando
Pubblicazione negli store
Costruita e non pubblicata: serve un conto sviluppatore e un invio, che sono un tuo atto. Il pacchetto e le due motivazioni che la revisione guarderà per prime — l'accesso a ogni sito e il ponte nativo — sono pronti e scritti in docs/invii-esterni.md.
browser-extension/ · docs/invii-esterni.md da fare tu: creare i conti e premere invia

📦 Aggiornamenti

La chiave privata non sta su nessun server e lo strumento si rifiuta di scriverla nel repository.

Firma ECDSA P-256 staccata
Calcolata sui byte esatti serviti, mai su una riserializzazione. Il prodotto porta solo la metà pubblica.
Core/Update/ provata da fuori, in anonimo
Dieci rifiuti, e ognuno può solo dire di no
Prima di scaricare: spento, firma non valida, manifesto illeggibile, versione illeggibile, indirizzo non HTTPS, dimensione fuori scala, impronta malformata. Dopo aver scaricato: lunghezza diversa da quella del manifesto, lunghezza reale diversa da quella dichiarata, impronta diversa. Undicesimo caso, che non è un rifiuto e va detto per quello che è: una versione non più recente riceve «già aggiornato» — la difesa dal ritorno a una vecchia ferma l'installazione con un verdetto diverso, non negando.
Core/Update/UpdatePolicy.cs · Service/UpdateChecker.cs verde nei test; contati dal sorgente l'11 agosto 2026
Il rilascio è un comando solo, e finisce chiedendo a GitHub
Per dieci giorni ogni pacchetto è uscito <b>sordo</b>. La catena funzionava — c'è perfino una release che si chiama «prova dell'aggiornamento automatico» — poi si è fermata l'11 agosto 2026, il prodotto è stato rinominato il 13, e da lì chi costruiva scriveva <code>build.ps1 -Plan Premium</code> invece della riga con i due parametri. Il difetto non è la dimenticanza: un MSI senza aggiornamenti è <b>indistinguibile</b> da uno buono — stessa dimensione, stessa icona, si installa uguale — e la differenza si vede mesi dopo, quando una correzione non arriva. È la bugia lenta che il prodotto sorveglia al suo interno, arrivata dagli strumenti. Ora <code>tools\rilascia.ps1</code> ricava la metà pubblica dalla chiave che esiste, costruisce coi due parametri, firma, pubblica i tre allegati e chiude chiedendo a GitHub esattamente quello che chiederebbe il prodotto — riprovando, perché <code>latest</code> non si sposta ovunque nello stesso istante e la prima volta ha gridato «firma non valida» su un rilascio sano.
tools/rilascia.ps1 · tools/Firma/Program.cs · CLAUDE.md eseguito: 0.1.5587 pubblicata e riverificata dal vivo, pacchetto da 58,9 MB scaricato e impronta confermata
La chiave di firma è stata rigenerata una volta
La privata in <code>%USERPROFILE%\.cetrai-keys</code> è del 16 agosto e <b>non</b> verifica il manifesto pubblicato l'11: <code>Refuse, firma non valida</code>. Le copie ferme alla 0.1.5347 portano dentro la vecchia metà pubblica e rifiuteranno ogni manifesto firmato adesso — irraggiungibili per sempre, perché la chiave vecchia non torna. Qui è costato niente (anteprima privata, una manciata di macchine che vanno reinstallate a mano una volta), e con mille clienti si sarebbe pagato una volta sola e per intero. Perciò <code>Firma chiave</code> resta un comando che rifiuta di sovrascrivere, e accanto è nato <code>chiave-pubblica</code>: la metà pubblica va <b>ricavata</b>, e prima l'unico comando che la stampava era quello che ne generava una nuova.
tools/Firma/Program.cs misurato: la firma dell'11 agosto rifiutata dalla chiave del 16
Lo strumento riverifica quello che ha scritto
Con la stessa funzione che gira dal cliente, e pretende tre esiti: macchina vecchia → installa, macchina aggiornata → già aggiornata, un bit girato nella firma → rifiuta.
tools/Firma/ eseguito a ogni pubblicazione
Il pacchetto sa nascere con le due funzioni accese
Fino a ieri l'analisi approfondita era spenta <b>per costruzione</b>: il build non aveva un parametro per dirle dove sta il backend, quindi ogni pacchetto usciva senza, e la riga «spente» era una constatazione, non una scelta. Adesso <code>-Backend</code> e <code>-Licenza</code> la accendono, con la stessa disciplina dei due campi dell'aggiornamento: si passano insieme o non si passano — separati producono i due modi in cui tace, e da fuori sono indistinguibili da «il motore locale non aveva dubbi» — e in chiaro sono ammessi solo su questa macchina, perché il token di licenza viaggia nell'intestazione. Scritto e riletto: se la sostituzione non trova la sua forma, il build si ferma invece di consegnare un pacchetto che promette una capacità che non ha. Eseguito il 16 agosto su un pacchetto costruito con entrambe: il servizio del pacchetto ha interrogato da solo l'indirizzo degli aggiornamenti (404, perché lì non è ancora pubblicato niente) e il backend ha risposto alla licenza del pacchetto e ha rifiutato con 401 chi non ne aveva.
installer/build.ps1 · tests/CetrAI.Platform.Tests/PackagingSettingsTests.cs eseguito: catena backend 200/401, manifesto firmato e riverificato con la chiave del pacchetto
Un controllo caduto ritorna fra un minuto, non fra un giorno
Era un timer fisso di 24 ore, e il primo colpo cade quando parte il servizio — cioè <b>al boot</b>, nei secondi in cui la rete non risponde ancora. Misurato sulla macchina di sviluppo il 23 agosto 2026, alla prima installazione con gli aggiornamenti accesi: servizio su alle 11:09:04, controllo fallito 0,3 secondi dopo con «host sconosciuto», prossimo tentativo fra ventiquattro ore. Su un PC che si spegne la notte l'uptime non arriva mai a ventiquattro ore: quel controllo sarebbe fallito <b>a ogni avvio e non sarebbe riuscito mai</b>, e l'unico sintomo era il prodotto che dichiara correttamente il silenzio — una riga vera su cui però non può agire nessuno. È il difetto delle copie di sicurezza girato al contrario: quello si nascondeva sulle macchine che ripartono spesso, questo si vede solo lì. Ora 1, 5, 15 minuti e poi ogni ora finché il server non risponde; dopo un contatto riuscito si torna al giorno.
Service/UpdateChecker.cs · tests/CetrAI.Platform.Tests/UpdateRetryTests.cs difetto trovato leggendo il registro del prodotto installato; la regola è una funzione pura e il test cade se torna il timer fisso
Il silenzio si dichiara dopo sette giorni
Il cruscotto smette di dire «aggiornato» e dichiara il silenzio. L'ultimo contatto riuscito sta su disco, perché un contatore in memoria si azzera a ogni riavvio e non raggiungerebbe mai la scadenza.
Core/Update/ verde nei test
Il cambio di nome non perde niente
Due rinomini in dieci giorni: AIDefender &rarr; AIDike il 13 agosto 2026, AIDike &rarr; CetrAI il 23. Il nome era anche un percorso: <code>%ProgramData%\AIDefender</code> prima e <code>%ProgramData%\AIDike</code> poi tenevano la cronologia, la licenza e la cassaforte delle copie. Chi aggiorna non deve accorgersene, quindi il servizio adotta la vecchia cartella voce per voce prima di leggere qualsiasi cosa, e non scrive mai sopra ciò che l'installazione nuova ha già messo lì — ma solo quando gli è concesso, e chi glielo concede sta nella riga accanto. Senza, non si sarebbe rotto niente ad alta voce: il cruscotto avrebbe mostrato una cronologia vuota, identica a quella di un PC dove non è mai successo niente. Il ponte del browser toglie da solo la registrazione <code>it.aidefender.host</code>, che punterebbe a un manifesto in una cartella che l'aggiornamento non possiede più.
Core/ProductPaths.cs · Service/LegacyProduct.cs difetto trovato eseguendo, e il rimedio riprovato sulla stessa strada
Chi puo' adottare la cartella del nome precedente
La prima versione spostava sempre, e il 13 agosto ha portato via i dati di un'<b>installazione viva</b>: l'avvio di prova dentro build.ps1 lancia lo stesso eseguibile del servizio, da una cartella di lavoro e come utente normale, mentre la versione precedente girava. In mezzo secondo si è preso feed, cartella degli aggiornamenti, libro delle lezioni e identità dell'installazione; è rimasto indietro solo ciò che era bloccato — il database e le copie. Una migrazione che gira mentre il vecchio prodotto è vivo non migra, deruba. Ora due condizioni, e nessuna delle due si assume: <b>solo</b> se Windows ci ha avviati come servizio, e <b>solo</b> se il servizio del nome precedente non è più registrato. Se la domanda non è rispondibile, la risposta è no.
Service/LegacyProduct.cs · Service/Program.cs ricostruito il pacchetto sulla stessa macchina: prima 6 voci spostate, dopo 0
Firma del codice (certificato EV)
Senza, SmartScreen avvisa al primo avvio. Non è codice: è un acquisto di un certificato EV su token hardware. Il comando <code>signtool</code> per firmare l'MSI e il punto dove si aggancia nella build sono già scritti in docs/invii-esterni.md; l'EV, a differenza dell'OV, dà reputazione SmartScreen subito.
installer/build.ps1 · docs/invii-esterni.md da fare tu: comprare il certificato e la verifica d'identità

💳 Free e Premium

«Free protegge, Premium risolve.»

Free
Rilevamento truffe senza limiti, protezione in tempo reale, estensione browser, stato reale di Defender, avviso ransomware, controllo remoto, IBAN negli appunti.
Licensing/FeatureGate.cs provato sul prodotto installato
Se il piano non è leggibile, sceglie Free
Una build che non sa cosa è non deve regalare funzioni a pagamento.
Licensing/FeatureGate.cs verde nei test
Premium: copie dei file e ripristino
Le due funzioni Premium che esistono davvero e sono provate.
Service/RansomGuard.cs provato sul pacchetto Premium
Premium: analisi approfondita in cloud
La catena intera è stata eseguita su questa macchina, client vero contro backend vero su HTTP: licenza emessa, indirizzo dubbio (22/100) mandato al backend, risposta applicata — sospetto 40/100. E il passo negativo, che è quello che conta: con una licenza inventata il backend risponde «token sconosciuto», il prodotto tiene il verdetto locale e dice che l'indirizzo è comunque uscito. Una build di rilascio rifiuta il trasporto diretto per costruzione, non per configurazione. Quello che manca non è codice: è un indirizzo pubblico dove metterlo.
backend/, Intelligence/Cloud/BackendCloudTransport.cs eseguito su HTTP vero, licenza valida e licenza rifiutata
L'AI la porta l'utente
Una tendina accanto a SCANSIONA con le <b>destinazioni</b>, e una finestra dove si incolla la propria chiave: <b>solo su questo PC</b>, <b>un modello sul mio PC</b> (Ollama), <b>Claude · ChatGPT · DeepSeek · Qwen</b> con la chiave dell'utente, <b>abbonamento CetrAI</b>. Il predefinito di un'installazione nuova è «solo su questo PC», e vale anche se il file della scelta è illeggibile: niente esce da un computer finché qualcuno non dice dove deve andare. Un equivoco tolto subito nella finestra: <b>l'abbonamento alla chat non serve a un programma</b>, serve una chiave API, che è un conto a consumo diverso. Tre regole reggono il resto — la scelta <b>può solo restringere</b> (nominare una destinazione senza chiave non manda niente e non ripiega su un'altra), <b>nessuna richiesta può nominare un indirizzo</b> (gli indirizzi sono una tabella compilata dentro, altrimenti l'impostazione sarebbe il modo di far recapitare i messaggi di qualcun altro dove si vuole), e la chiave <b>viaggia solo in entrata</b>. ADR-0005 non è contraddetto: vietava <i>la nostra</i> chiave su un PC altrui, cioè una fattura illimitata a nome nostro. Due difetti veri trovati eseguendo, che sarebbero usciti rotti: il primo modello locale ha risposto con i campi <code>giudizio</code> e <code>motivazione</code> — solo Anthropic riceve uno schema, agli altri si chiede «un oggetto JSON», che promette la sintassi e non i nomi, e il prodotto avrebbe buttato via ogni risposta; e i tempi, <b>346 secondi a freddo e 137 a caldo</b> contro un timeout di 30, cioè la voce locale avrebbe fallito sempre e in silenzio. Arancione perché <b>quanti utenti non tecnici abbiano una chiave API non è misurato</b>.
Core/AiChoice.cs · Core/AiProviders.cs · Intelligence/Cloud/OpenAiCompatibleTransport.cs · Platform.Windows/ProtectedApiKeys.cs · Tray/AiSetupWindow.xaml · ADR-0018 provati dal vivo contro Ollama su questa macchina: protocollo, scelta del modello installato, forma della risposta e tempi. Il servizio nuovo <b>non partiva affatto</b> — <code>TimeProvider</code> non era registrato — e i 999 test verdi non potevano vederlo, perché costruiscono i loro oggetti a mano. Ora c'è un test che costruisce il contenitore vero, e la sua prima versione era inutile: passava anche con la riga tolta, perché <code>ValidateOnBuild</code> non guarda dentro i client HTTP tipizzati, che è dov'era il buco. Il terzo l'ha trovato il pacchetto, ed era il peggiore: <code>CloudAnalysis:Enabled</code> era <code>false</code> nella configurazione distribuita e nessuno lo guardava accanto alla chiave, quindi dopo averla incollata la finestra avrebbe detto <b>«Pronta»</b> e ogni caso sarebbe stato scartato un piano più sotto, in silenzio. Acceso di serie: quel campo dice solo che la funzione esiste, e l'interruttore vero è la scelta, che su un'installazione nuova vale «solo su questo PC»
Un indirizzo pubblico dove sta il backend
Le due funzioni che parlano fuori — analisi approfondita ed esperienza condivisa — girano da un capo all'altro su localhost e sono spente nel pacchetto solo perché non c'è un posto dove sta il server. Serve una decisione, non un'implementazione: hosting, HTTPS (il backend si rifiuta di partire in chiaro su un indirizzo pubblico, perché il token di licenza viaggia nell'intestazione) e la chiave del fornitore in una variabile d'ambiente di quel server.
backend/CetrAI.Backend/appsettings.json
ExtendedHistory, MultiDevice, IdentityMonitoring
Tolte. Ognuna aveva il suo messaggio di upgrade e nessuna riga che la applicasse. Due non possono esistere qui: una vuole un account e un server che questo prodotto non ha, l'altra i feed delle violazioni, che nessuno regala. La terza si costruiva in un pomeriggio, <b>e costruirla sarebbe stato peggio</b>: oggi non esiste nessuna finestra di conservazione, ogni analisi resta e il cruscotto mostra le ultime 50 — quindi «cronologia estesa» si vende solo cancellando prima quella di chi non paga. È il contrario di «Free protegge, Premium risolve», e toglierebbe a un utente Free truffato proprio il fascicolo per la denuncia, che si compone da quella cronologia. Restano tre nomi a pagamento, e accanto a ciascuno c'è il file che lo applica.
Licensing/FeatureGate.cs un test lega i nomi a pagamento al codice che li rifiuta

🚫 Spento apposta, e perché

La sezione che vale di più: sono decisioni misurate, non debiti.

Liste esterne di minacce
Misurate e spente. URLhaus è un elenco di pagine, non di siti: bloccarne i domini avrebbe tolto github.com a tutti. Vale 10 domini su 155.927.
tools/misura-esterna.ps1 misurato contro il milione Tranco
Trasporto cloud diretto in una build di rilascio
Rifiutato col tipo, non con un if: la capacità pericolosa su canale aperto non è esprimibile, non è disattivata.
Core/ verde nei test
Quello che guardi nel browser non esce mai
AllowedSources non contiene Browser. Non è un'impostazione da spuntare: è un elenco, e il navigatore non ci è dentro.
Core/ verde nei test

🌍 Fuori dal codice

Cose che nessuna riga di C# chiude.

Validazione da un laboratorio terzo
AV-Comparatives, AV-TEST. Chi valuta il prodotto lo chiederà. La misura che un laboratorio chiede — cosa fa, come lo sai, i numeri col denominatore, i limiti dichiarati — è già scritta e si rigenera da sola; il dossier e il punto onesto da metterci in cima (è un test anti-truffa, non anti-malware: quello è di Defender) sono in docs/invii-esterni.md.
docs/cosa-fa.md · docs/invii-esterni.md da fare tu: il contatto e l'invio
La causa del consumo di memoria
Trovata, e non leggendo il codice. Il primo pezzo era il giro dei programmi: 102 MB l'ora, il 75% del totale, sceso a 6,8 chiedendo a Windows i nomi invece di tutto. Restavano gigabyte che nessun lavoro pesato spiegava, e la diagnosi che li avrebbe nominati non partiva perché il ritmo era falso: si divideva per un orologio che conta il sonno mentre l'origine ne usava uno che non lo conta. L'11 agosto la riga diceva 98,2 MB l'ora mentre il totale allocato saliva di 3.949,8 MB in un'ora sveglia — un quarantesimo, sotto la soglia di 200. Corretto l'orologio, alle 13:44 il servizio installato ha scritto di che cosa era fatta: 23,9 MB di String, 8,7 di StringBuilder, 7,6 di char[] e — la firma che ha chiuso il caso — Arguments&lt;string, string, long, DateTimeOffset&gt; di System.Text.Json, che è il costruttore di SnapshotEntry e in questo prodotto non ce l'ha nient'altro. Il cruscotto chiede lo stato del ransomware, quello chiede quale copia userebbe un ripristino, e quello rileggeva e deserializzava per intero <b>ogni</b> manifesto delle copie — 367 voci l'uno — per ricavare tre numeri per copia. 2.836 MB l'ora, 846 KB per richiesta, una richiesta al secondo. Un manifesto non cambia mai dopo essere stato scritto: ora si conta una volta sola.
Storage/FileSnapshotStore.cs, Service/ChurnMeter.cs, Platform.Windows/RunningPrograms.cs causa letta sul prodotto installato; la prova fallisce se si rimette il difetto

💡 Idee nuove — proposte, non ancora decise

Ognuna porta la ragione, il costo e la misura da fare prima. Nessuna è lavoro promesso: finché non sono scelte non contano nella percentuale.

+
Defender spento mentre il controllo remoto è in corso
I due sensori esistono già e nessuno li mette insieme: il servizio sa quali programmi di controllo remoto sono partiti e legge otto proprietà di Defender, protezione in tempo reale compresa. Metterli insieme costa una classe. Ed è la prova categorica che il finto operatore da solo non ha: un tecnico onesto non spegne l'antivirus del cliente mentre è collegato — chi lo fa sta preparando l'installazione del «programma di diagnosi». Avvisa, non blocca, come già fa il controllo remoto.
aggancio: Service/RemoteControlWatch.cs + WmiDefenderBridge.cs da misurare prima: quante volte la protezione risulta spenta senza nessuno collegato
+
Il motore sui messaggi non ha una bocca
Sei segnali e sei lingue, e oggi il testo entra solo se qualcuno lo incolla nel riquadro o lo passa a «cetrai scan --text». Verificato leggendo chi costruisce AnalysisRequest: le uniche fonti sono la riga di comando, il cruscotto e il ponte del browser. Ma le truffe italiane arrivano per SMS e per posta, e un motore che aspetta un incolla è quasi spento — è la regola del prodotto rovesciata, qui è l'utente che deve fare tutto. Le due strade in locale sono «Collegamento a telefono» di Windows e il profilo di Thunderbird o Outlook. È la voce che vale di più, e anche quella con più domande aperte sulla riservatezza: si legge sul PC, non esce niente, come già per la cronologia.
aggancio: Detection/Signals/MessageContentDetector.cs (il motore c'è, manca l'ingresso) da misurare prima: quanti messaggi al giorno passano davvero da quelle due fonti su una macchina vera
+
Le estensioni del browser arrivate da poco
Stesso schema che ha funzionato per il finto operatore: non conta il permesso, conta quando è arrivata. Un'estensione installata ieri, che può leggere i dati di tutti i siti e non viene da uno store, è il dirottamento più comune del browser — e Defender non la guarda. <b>Misurata il 16 agosto su questa macchina, e il risultato cambia la regola prima ancora di scriverla.</b> Su <b>41 voci</b>, <b>27 sono il browser stesso</b> — Picture-in-Picture, Form Autofill, Chrome PDF Viewer, Microsoft Rewards. La prima misura non le separava e diceva «12 fuori store su 24»: letti i nomi, la regola avrebbe sparato <b>3 volte, tutte e tre il browser che accusa sé stesso</b>. Il discriminante però esiste ed è netto: in Chromium <code>location</code> vale 1 se l'ha messa la persona dallo store, <b>4 se ce l'ha messa un programma del PC</b>, 5/6/10 se è un pezzo del browser; in Firefox lo dicono <code>location</code> e <code>sourceURI</code>. Con quello: <b>12 installate dalla persona, 2 messe da un programma</b>, nessuna delle due legge ogni sito, nessuna recente — la regola <b>tacerebbe</b>, che è quello che deve fare su una macchina sana. Due dettagli che senza misura non si sarebbero saputi: il nome va risolto da <code>_locales</code> o all'utente si mostra «<code>__MSG_appName__</code>», e la data sta in <code>first_install_time</code> e non in <code>install_time</code> — col campo sbagliato 13 estensioni su 14 risultavano «senza data», che è indistinguibile da «la data non c'è».
aggancio: Platform.Windows/Browsing/ misurata: 41 voci su una macchina vera, 27 del browser · da decidere: il campione è una macchina sola, quindi la frequenza di «messa da un programma» resta ignota
+
Il file appena scaricato dal sito che il motore avrebbe bocciato
Il prodotto sa dare un verdetto su un dominio e sa leggere la cronologia, ma nessuno collega le due cose nel momento in cui un eseguibile compare in Download. La combinazione stretta è tripla: eseguibile, arrivato negli ultimi minuti, da un dominio che il motore chiama pericoloso. Da sola nessuna delle tre vale niente.
aggancio: Detection/ + Platform.Windows/Browsing/ da misurare prima: quanti eseguibili scarica in un mese una macchina normale
Il numero di telefono nella pagina che imita un marchio
Era un'idea, ed è stata costruita l'11 agosto: la regola che dice se una pagina è la schermata del finto supporto tecnico. Il timore scritto qui — «da sola la presenza di un numero non prova nulla» — era giusto, e infatti il numero è la più debole delle quattro prove e conta solo su una pagina corta. Il dettaglio sta nella riga «La finestra a schermo intero «chiama Microsoft»» più su.
browser-extension/content/support-scam.js 11/11 su 4 truffe e 7 pagine vere, dentro tools\verifica.ps1
+
Un familiare che riceve il riepilogo
Chi ha più bisogno di questo prodotto spesso non è chi lo compra: è il genitore anziano, e chi paga è il figlio. Mandare la riga mensile anche a un secondo destinatario cambia il prodotto da programma sul PC del nonno a servizio che la famiglia acquista. È l'idea che vale di più commercialmente e costa di più: serve un canale d'invio, quindi backend, consenso raccolto bene e dati personali veri — le prime tre idee si fanno tutte in locale, questa no.
aggancio: Core/MonthlyWord.cs + backend/ da decidere prima: dove finiscono i dati del secondo destinatario
Le truffe di gioco che arrivano a parole
MSG_SECRECY («non dirlo ai tuoi genitori») pesa 22 e non accusa da solo, perche' la stessa frase la scrivono un amico che prepara una sorpresa e un genitore che nasconde un regalo. MSG_FREE_CURRENCY (25), URL_FREE_CURRENCY_PROMISE (30) e il duplicatore di oggetti dentro uno scambio (25) invece accusano: i Robux si comprano, i generatori e i duplicatori non esistono, quindi nessun mittente onesto ne offre uno. <b>Il «7 su 7» misurava una parentela</b>: quelle sette truffe le aveva scritte la stessa mano delle regole. Allargato a dodici forme in cui la truffa arriva davvero — finto moderatore col ban, carta regalo, intermediario, finta beta — fa <b>11 su 19</b>. Otto persi, e sette lo restano <b>per scelta</b>: «manda tu per primo», «fammi entrare nel tuo account», «ti chiede la password» sono le frasi che scrivono anche il fratello, l'amico e l'avviso antitruffa del gioco. Una era presa a 45 ed e' stata lasciata andare, perche' quel 45 accusava il fratello.
Signals/MessageContentDetector.cs · Signals/UrlStructureDetector.cs 19 truffe e 16 messaggi veri scritti a mano: 11 prese, 0 amici accusati
+
Le truffe dentro i giochi: Roblox, Fortnite, i mondi VR
Il pubblico è quello che si fa truffare di più e che nessun antivirus difende: la truffa del «robux gratis» non è un virus, è una promessa. Su PC la metà fattibile è già a portata, perché l'esca passa comunque dal browser — e misurato oggi sul corpus: 35 domini di phishing citano Roblox, 12 Discord, 8 Fortnite, e nessuno di quei marchi è in catalogo (httpss-roblox.com, fortnitehub.live). È lo stesso buco trovato stamattina con le esche tedesche, e si chiude allo stesso modo. La metà che invece non si fa da qui è la chat dentro il gioco: non passa da nessuna interfaccia, e leggerla significherebbe entrare nel processo del gioco, cosa che ogni anticheat tratta — giustamente — come un attacco.
aggancio: Detection/Analysis/LinkFinder.cs · Data/WorldSuffixes.cs rimisurato il 16 agosto, e la diagnosi del 13 era sbagliata: non mancava il catalogo (Roblox, Discord e Steam c'erano già da agosto, ed Epic era stato provato e tolto su 1.155.927 casi). Mancava che il cercatore di link riconoscesse «.help» e «.win» come suffissi: senza, l'indirizzo non veniva visto affatto. Ora 1 su 4; per i tre restanti la misura da fare è nominata caso per caso
I messaggi privati dei social: Instagram, TikTok, LinkedIn
La domanda aperta era il consenso, non il codice, e la risposta è stata resa <b>inesprimibile</b> invece che scritta: il nome del posto è un elenco chiuso di tre valori — non una stringa — quindi in cronologia non può finire una frase né il nome di chi scrive; la richiesta nasce con le ricerche di rete spente, così nemmeno i link del messaggio escono; e <code>MayLeave</code> rifiuta questa sorgente <b>anche se qualcuno la aggiunge</b> all'elenco di quelle ammesse, che è il caso peggiore ed è il caso che il test prova. Il motore ha imparato tre segnali nuovi misurati su questi messaggi: pagare per lavorare (45, e nessun datore di lavoro onesto lo chiede), paga a giornata senza esperienza (22), uscita su WhatsApp (20). Quello che resta è la parte che non si può provare da qui: quali pezzi della pagina sono un messaggio ricevuto su Instagram, TikTok e LinkedIn — i selettori cambiano, e quando cambiano il prodotto non sbaglia, <b>smette di vedere</b>, che a schermo è identico a «nessuna truffa». Resta arancione finché non gira su un account vero.
browser-extension/content/social-dm.js · Core/AnalysisRequest.cs · Signals/MessageContentDetector.cs 10 truffe su 12 e 0 mittenti veri accusati su 8, dalla strada vera (ForPrivateMessage); le regole su quali pezzi di pagina leggere in tools\prova-messaggi-privati.mjs, dentro tools\verifica.ps1
+
Modalità Anziani (SilverMode)
Il segmento vero del prodotto, e insieme la domanda più scomoda che ci si possa fare: se serve una modalità per anziani, vuol dire che quella normale chiede troppo — e la prima regola qui è che l'utente non deve fare niente. Quindi tolti i caratteri grandi, che sono aspetto, restano due cose sole con sostanza: bloccare invece di avvisare, cioè prendere al posto suo la decisione che quella persona non vuole prendere, e un familiare che riceve quello che succede. La seconda è già un'idea qui sopra; la prima cambia il prodotto, perché un blocco sbagliato si sente e un avviso sbagliato no.
aggancio: Tray/ + Core/MonthlyWord.cs da misurare prima: quante volte in un mese il prodotto chiede qualcosa a chi lo usa — se è «mai», SilverMode è solo un nome
+
Quante volte il prodotto parla davvero, in un mese
La misura che decide l'ordine di tutte le altre. Su una macchina normale, in trenta giorni, quante volte CetrAI ha detto qualcosa? Se la risposta è zero, ogni funzione qui sopra è teoria: il prodotto è invisibile e viene disinstallato al primo rallentamento. Costa un contatore locale e la riga mensile che esiste già, e si risponde con una macchina e un mese di attesa — non con un'opinione.
aggancio: Core/MonthlyWord.cs è essa stessa la misura: va fatta prima delle altre sei

I numeri, col loro denominatore

Una percentuale senza il suo denominatore è più corta e vale meno di niente. Ogni riga porta il proprio, e la data della misura dove cambia qualcosa.

#
Falsi allarmi — 0,032%
324 su 1.000.000 di siti veri (Tranco), 11 agosto 2026. Il 324esimo e' freethevbucks.com, il cui nome promette V-Bucks gratis: Tranco ordina per traffico, non per onesta'
#
Conversazioni normali accusate — 0
4.827 messaggi veri
#
Phishing riconosciuto dove il catalogo conosce il marchio — 86,4%
corpus OpenPhish — era 78,3% prima dei cinque marchi aggiunti il 10 agosto
#
Phishing riconosciuto dove non lo conosce — 1,6%
lo stesso corpus — è questo il numero che definisce il prodotto, non l'86,4%: è il tetto di un motore a regole fuori dalla conoscenza che ha, e si alza solo allargando il catalogo
#
Phishing attivo, indirizzo intero — 14,0%
300 indirizzi OpenPhish — era 7,67% prima dei cinque marchi
#
Truffe di compravendita — 5 su 5
scritte a mano, con 5 legittimi somiglianti: 0 accusati
#
Truffe di gioco che arrivano a parole — 11 su 19
era 7 su 7 su un corpus di sette casi scritti dalla stessa mano delle regole. Con dodici forme vere in piu' scende qui, e i 16 messaggi veri che usano le stesse parole — il fratello che ti finisce la missione, l'avviso antitruffa di Roblox — restano 0 accusati. Sette degli otto persi sono persi per scelta: la frase e' identica a quella di un amico
#
Le stesse truffe con un link dentro — 1 su 4
era 0, e la spiegazione che avevo scritto — «mancano i marchi in catalogo» — era sbagliata: Roblox, Discord e Steam c'erano già, e roblox-support.help da solo prendeva 52. Dentro un messaggio prendeva zero perché il cercatore di link non riconosceva «.help» come suffisso, quindi non vedeva l'indirizzo affatto. I tre persi sono stati misurati uno per uno e restano persi per scelta: «rblx» fa 6 siti veri contro 1 di phishing (peggio del rapporto che ha tolto Epic), il refuso dentro un nome composto uscirebbe a 24 e resterebbe sotto la soglia comunque, e il terzo è a tre modifiche contro una soglia di due che non si alza — metà dei falsi allarmi veniva da lì
#
Truffe nei messaggi privati dei social — 10 su 12
scritte a mano, analizzate dalla strada vera — quella con le ricerche di rete spente — con 8 mittenti veri difficili: un recruiter che propone soldi e chiede una call, un brand che offre campioni, un cliente che paga. 0 accusati. I due persi sono il finto colloquio col file da eseguire e la truffa romantica: in un messaggio solo, un mittente onesto scrive le stesse parole
#
Messaggi italiani riconosciuti — 49 su 50
corpus di 124 messaggi scritto qui, non raccolto: la percentuale vale quanto la sua provenienza, e il suo valore vero è la lista dei mancati, che ha nominato sei conoscenze che al motore mancavano. Prima dei sei segnali nuovi era 33 su 50
#
Conversazioni italiane vere accusate — 1 su 74
lo stesso corpus, metà legittima scritta per essere difficile: fretta, soldi, link e le parole delle campagne. Era 2 prima, e la seconda era «ti mando l'IBAN per il regalo di Luca»
#
Chiedere a Windows chi tiene un file — 98 ms
mediana di 5 misure, 14 percorsi su una cartella con 40 documenti dentro: è il costo fisso di ogni tentativo di identificare il colpevole, e a 300 file/s vale 29 file
#
File persi nella risposta, a 300 file/s — da 448 a 111
tre giri di identificazione: prima 400 ms fissi di attesa fra i giri, ora il doppio del ritmo osservato. A 4 file/s — l'unica velocità mai provata davvero — il numero non cambia
#
Attesa alla certezza, a 300 file/s — da 98 a 25 ms
la domanda a Windows comincia quando l'attività è anomala e alla certezza si aspetta quella: 7,6 file invece di 29. A 50 file/s è già pronta e non si aspetta niente
#
File persi contro un ransomware a 300 file/s — circa 18
dieci per arrivare alla certezza più otto mentre si identifica il colpevole. Stamattina erano 25 + 29 nel caso migliore e 25 + 134 in quello peggiore. Contro un ransomware vero non è mai stato provato: questi sono i numeri del meccanismo, non di un attacco reale
#
Test automatici — 876
a ogni build, con gli avvisi trattati come errori — rieseguiti il 13 agosto 2026, dopo il cambio di nome
#
Tempo per verdetto — 0,041 ms
mediana, un thread
#
Memoria per verdetto — 4,7 KB
#
Memoria del servizio — 18-20 MB
all'avvio; il pacchetto non viene creato sopra i 24. Dopo 46 ore acceso, sulla copia installata: 30 MB, di cui 4-7 di oggetti vivi
#
Allocazione a riposo, per lavoro di sfondo — sotto 7 MB/h
ognuno pesato da solo sul cablaggio del prodotto: il controllo dei programmi era 102 MB/h e ora ne fa 6,8
#
Allocazione per richiesta di stato — 846 KB
sul servizio installato, col cruscotto aperto: 2.836 MB l'ora perché ogni richiesta rileggeva tutti i manifesti delle copie. Contati una volta sola, non si rileggono più
#
Memoria dell'icona nel vassoio — 37 MB
sul prodotto installato, e restano 37 anche dopo aver aperto e chiuso il cruscotto: prima diventavano 76 per sempre. La finestra costa altri 62 MB finché è aperta, in un processo che esce quando la si chiude