Un'illustrazione astratta generata su un campo blu navy scuro: il contorno di una finestra del browser a sinistra invia un nastro di forme chiare simili a glifi attraverso una stretta presa luminosa fino a un pannello del terminale a destra. Un secondo nastro, più scuro, si unisce alla stessa presa dal basso e i suoi glifi arrivano nel terminale indistinguibili dal primo. Non compaiono testo, persone o loghi di organizzazioni. Il logo OrcaRouter è collocato nella fascia bianca del piè di pagina in basso a destra.
AI Safety Incidents

Tencent BrowserSkill verificava solo che un ID di estensione sembrasse reale — qualsiasi estensione poteva fornire all'agente pagine falsificate

Autore

Rowan Sterling

Data di pubblicazione

Ultimi modelli · 20Vedi tutti i modelli →
Benchmark: Artificial Analysis · aggiornato ogni giorno
Torna a tutti gli articoli

Il 17 settembre 2026, un utente GitHub che scrive come carfeii ha aperto la issue #273 contro il progetto open source BrowserSkill di Tencent con un'affermazione limitata: il daemon locale che collega l'estensione del browser a un agente AI non verificava quale estensione si fosse connessa, ma solo che la connessione somigliasse a un'estensione. Tre giorni dopo, il 20 settembre, VulnCheck ha pubblicato la scoperta come CVE-2026-94111, descrivendo un daemon che "accetta qualsiasi origine chrome-extension con 32 caratteri nell'intervallo a-p" e lo classifica come CWE-346 (errore di validazione dell'origine) e attribuisce il merito a George Chen. L'advisory lo valuta CVSS 4.0 6.9, medio, con impatto sull'integrità valutato alto e riservatezza e disponibilità basse. Nulla nella voce suggerisce che la falla sia stata sfruttata: l'archivio non registra alcuno sfruttamento e assegna alla voce una confidenza A, con real_harm false. Questo è un record in l'archivio degli incidenti AI, in cui ogni voce riporta le proprie fonti, gravità, grado di confidenza e flag di contestazione.

Un controllo del formato che non ha mai verificato l'identità

Il codice al centro del record è piccolo. In crates/bsk-cli/src/daemon/ws.rs, la funzione origin_allowed() prende l'header Origin dell'handshake WebSocket, rimuove la stringa chrome-extension://, e restituisce true se ciò che rimane è lungo esattamente 32 caratteri e ogni carattere è compreso tra a e p. Questo è il test completo. Viene eseguito una volta, all'interno del callback di upgrade HTTP, e un fallimento restituisce un 403 il cui messaggio recita "Origin not in chrome-extension allow-list" — anche se, così come pubblicato, non c'era alcuna lista in cui rientrare.

Il pattern non è arbitrario. Gli ID delle estensioni Chrome Manifest V3 sono composti da 32 caratteri presi esattamente da quelle sedici lettere, quindi il controllo riconosce correttamente la forma di un'origine di estensione reale. Il difetto è che ogni estensione ha quella forma. Il controllo chiede se il chiamante sembra un'estensione browser, mai se è l'estensione browser di questo progetto, e l'identificatore con cui avrebbe dovuto confrontarlo era già pubblico: il README del progetto collega la scheda del Chrome Web Store, il cui ID è hhcmgoofomhgciiibhipgmgkgnoenaoi, e l'ID di Edge Add-ons accanto ad essa. Nessuna delle due stringhe compare in alcun punto del controllo.

Il daemon è in ascolto su una porta locale fissa, 52800, dichiarata come DEFAULT_WS_PORT nella CLI e usata senza variazioni nel percorso di connessione locale. La porta è documentata, costante e raggiungibile da qualsiasi cosa sia già in esecuzione nel profilo del browser dell'utente. È per questo che il vettore dell'advisory inizia con AV:L: l'attaccante necessita di un punto d'appoggio sulla macchina, e PR:L registra che ne basta uno con privilegi bassi. Un'estensione installata nello stesso profilo è esattamente quel tipo di punto d'appoggio.

Quanto vale il seggio e quanto ne è già stabilito

La frase sull'impatto dell'advisory è ampia: un attaccante che registra un'estensione malevola come client browser può "intercettare e manipolare il contenuto della pagina, il DOM e gli screenshot restituiti all'agente AI". Questa è la descrizione riportata dal CVE, dal record dell'advisory GitHub GHSA-x6f2-qp26-2xrh e dall'archivio, e spiega la valutazione di integrità CVSS pari ad alta. È anche un riepilogo scritto dalla parte che ha assegnato il CVE, non un resoconto di un attacco dimostrato.

Un resoconto più accurato giunse la stessa settimana, proprio nel thread stesso dell'issue. Il 20 settembre, un commentatore che scrive come bb6894 ha riferito di aver ricontrollato il codice rispetto a main al commit fa953dc6 (18 settembre) e ha tracciato ciò che un client esterno può effettivamente raggiungere dopo l'handshake. La maggior parte dei metodi degli strumenti in entrata, afferma il commento, restituisce UnknownMethod a un peer WebSocket; le richieste di audit sono limitate ai record del client stesso; e le azioni tra sessioni come window_closed, user_interrupt e update_interaction sono protette contro sessioni di proprietà di un altro browser. Ciò che sopravvive a quel filtro è più ristretto e, per un agente, probabilmente peggiore dell'intercettazione: un'estensione esterna può occupare uno slot browser con un instance_id scelto dall'attaccante e, se è l'unico browser registrato — un avvio a freddo o un riavvio del daemon — riceve le richieste degli strumenti dell'agente e vi risponde con contenuti di pagina, DOM o screenshot falsificati. Il commentatore la definisce "falsificazione dei risultati verso l'agente" e "un canale nella percezione dell'agente". Un secondo effetto è un denial of service: con anche un browser autentico online e nessun selettore, l'avvio della sessione può fallire con MultipleBrowsersOnline.

Nessuna delle due versioni è stata dimostrata pubblicamente. Il reporter ha descritto una proof of concept come «disponibile su richiesta»; nessuno ne ha pubblicata una e non è registrato alcun sfruttamento. La differenza tra le due versioni è quindi una differenza tra due letture dello stesso file sorgente, non tra una teoria e un exploit funzionante — e l'articolo riporta entrambe anziché scegliere. Ciò che si può affermare senza riserve è che non vi fu mai un secondo controllo d'identità dopo l'handshake, per cui qualunque cosa il gate abbia ammesso è rimasta ammessa per tutta la durata della connessione.

Il codice lo sapeva già

Il documento più scomodo in questo registro non è l'advisory. È il commento direttamente sopra la funzione, distribuito nella release taggata a cui l'advisory fa riferimento. Contrassegna la lacuna come TODO(M10/M12), indica la lista di autorizzazione che intende creare — un DaemonConfig::allowed_extension_ids set popolato da un file di configurazione o da un flusso di pairing — e poi dichiara il motivo per cui è stato rimandato: "lacuna di difesa in profondità accettabile per ora perché il pairing avviene tramite il popup, ma un'estensione side-loaded sulla stessa macchina attualmente supera il controllo."

Letto senza giri di parole, i manutentori sapevano quale chiamante il controllo lasciava passare, hanno messo per iscritto che lo sapevano e hanno rilasciato. Ciò non rende l'esposizione più ampia di quanto dica l'avviso; la rende meno sorprendente e sposta la domanda da "come ha fatto a superare la revisione" a "cosa avrebbe reso urgente la correzione rinviata". L'assunzione progettuale mitigante è reale e anche documentata: la connessione locale è opt-in. Secondo il README, l'utente installa l'estensione, apre il suo popup e abilita la connessione locale, e il daemon deve essere in esecuzione perché qualcosa di tutto questo sia raggiungibile. Un profilo con l'estensione installata ma l'interruttore disattivato, o senza alcun daemon bsk in esecuzione, non è un bersaglio in ascolto.

Cinque settimane dopo, il cancello è invariato.

An HTML timeline card titled 'From a filed issue to an unmerged patch', subtitled 'Nine dated entries in the BrowserSkill daemon origin-check record', listing: 16 September 2026 BrowserSkill extension 0.3.0 tagged; 17 September the bsk CLI 0.3.0 release, and issue #273 filed the same day at 15:14 UTC; 20 September CVE-2026-94111 published by VulnCheck and listed by NVD and GitHub, with a narrower impact analysis posted in the thread; 21 September CISA's SSVC assessment records exploitation none and automatable no; 23 September CLI 0.3.1 released with the same origin check; 28 September pull request #363 opened from a fork to pin the store extension IDs; 30 September CLI 0.3.2, same check; 15 October CLI 0.3.3, same check; 27 October issue still open and the patch still unmerged. A footer cites the GitHub issue, the VulnCheck advisory, NVD and the project's release tags, with the OrcaRouter logo in a white strip at the bottom right.

L'intervallo interessato del record è "fino alla 0.3.0", e quello è l'intervallo assegnato dal CNA. Non è la fine della storia nel repository. La release 0.3.0 della CLI è stata taggata il 17 settembre alle 02:22 UTC; la segnalazione è stata aperta lo stesso giorno alle 15:14 UTC, circa tredici ore dopo. Da allora sono state pubblicate altre tre release della CLI — 0.3.1 il 23 settembre, 0.3.2 il 30 settembre e 0.3.3 il 15 ottobre — e la funzione origin_allowed() a ciascuno di quei tag è lo stesso controllo descritto sopra, con il TODO ancora al di sopra. Anche il branch main la contiene, al 27 ottobre.

Una correzione esiste, ma solo come proposta. Il 28 settembre, un contributore che scrive come dangzitou ha aperto la pull request #363 da un fork personale, intitolata "fix(daemon): pin WS origin gate to BrowserSkill's own extension ids." Sostituisce il test sulla forma con un confronto con i due ID dello store e aggiunge BSK_ALLOWED_EXTENSION_IDS come percorso di ammissione esplicito per build sideloaded e di sviluppo, i cui ID non pacchettizzati derivano dal percorso di installazione. Il corpo della pull request afferma che chiude sia il percorso di falsificazione sia il denial of service MultipleBrowsersOnline. Al 27 ottobre è ancora aperta e non unita, e la issue rimane aperta senza alcuna dichiarazione del fornitore a essa allegata.

La conseguenza pratica è che non esiste alcuna versione a cui aggiornare che contenga la correzione. Chi consiglia di "aggiornare oltre la 0.3.0" consiglia un passo che ancora non esiste: le versioni successive sono più recenti, non corrette. L'intervallo indicato nel record va letto come l'intervallo valutato dal CNA il 20 settembre, non come un'affermazione che la 0.3.1 e le successive siano esenti da problemi.

Che cosa è stabilito e che cosa non lo è

• Accertato: il sorgente rilasciato al tag cli-v0.3.0 contiene un controllo sull'origine che accetta qualsiasi origine chrome-extension di 32 caratteri da a a p. Il segnalatore, il CNA e il file stesso concordano, e il codice è pubblico.

• Stabilito: il gate veniva eseguito una sola volta, durante l'upgrade WebSocket, senza successivi controlli dell'identità, su una porta locale fissa 52800.

• Accertato: il commento al codice sorgente del progetto stesso riconosceva che un'estensione installata manualmente sarebbe passata, e rinviava l'allow-list.

• Stabilito: CVSS 4.0 6.9 e CVSS 3.1 6.6 sono entrambi punteggi di VulnCheck, registrati da NVD come secondari. Lo stato di NVD per la voce è Deferred, il che significa che ha pubblicato i dati della CNA senza aggiungere un'analisi redatta da NVD.

• Stabilito: La valutazione SSVC della CISA, datata 21 settembre, registra lo sfruttamento come nessuno, automatizzabile come no e l'impatto tecnico come parziale. L'EPSS di FIRST colloca la probabilità di sfruttamento nei prossimi trenta giorni a 0,00135, il 2,9° percentile, al 26 ottobre.

• Non stabilito: alcun uso nel mondo reale. Nessuno sfruttamento, nessuna proof of concept pubblicata, nessun conteggio delle installazioni interessate. Le metriche del repository del progetto non sono un conteggio delle installazioni e nessuno ne ha pubblicato uno.

• Non stabilito:quale resoconto dell’impatto sia quello valido. L’"intercettare e manipolare" della CNA e la "falsificazione dei risultati più negazione del servizio" del thread descrivono livelli massimi diversi, e nessuno dei due è stato dimostrato al di fuori della lettura del codice.

• Non è stabilito: che il difetto si fermi alla 0.3.0. La stringa di versione è la valutazione della CNA; il codice è invariato nelle tre versioni successive, e nessuna dichiarazione del fornitore le scagiona.

• Contraddetto, irrisolto: un aggregatore, DevGuard, mostra un segnale "sono stati rilevati tentativi di sfruttamento" per questa CVE senza indicare una fonte, un IOC o un fornitore di telemetria. Ciò contrasta con la valutazione registrata da CISA di nessuno sfruttamento e con l'assenza di qualsiasi rapporto pubblico; anche l'archivio non registra alcuno sfruttamento. Considera la segnalazione dell'aggregatore come non comprovata anziché come un secondo dato.

An HTML card titled 'Established, and not', split into two columns. The left column, headed 'Established', lists: an origin gate that accepts any 32-character a-p chrome-extension origin, in the released cli-v0.3.0 source; checked once at the WebSocket upgrade on local port 52800; the project's own comment conceded sideloaded extensions pass; CVSS 4.0 6.9 and 3.1 6.6 are VulnCheck's scores, NVD status Deferred; CISA SSVC records exploitation none and automatable no; EPSS 0.00135 as of 26 October. The right column, headed 'Not established', lists: any real-world use or published proof of concept; which impact account holds, interception or result forgery; that the flaw stops at 0.3.0, since 0.3.1 to 0.3.3 carry the same check; an installation count; an unsourced aggregator claim of exploitation attempts. A footer cites VulnCheck, NVD, CISA, FIRST and the GitHub issue, with the OrcaRouter logo in a white strip at the bottom right.

Perché il trasporto è il bersaglio interessante

La maggior parte delle linee guida sul prompt injection traccia lo stesso confine: considera non attendibile il testo recuperato dalla pagina e attendibile il meccanismo che lo fornisce. Si presume che uno strumento che legge una pagina web stia leggendo la pagina; la questione è ciò che dice la pagina. Questo caso inverte tale impostazione. Ciò che l'agente riceve come contenuto della pagina, DOM e screenshot è qualunque cosa il client all'altro capo di un socket locale scelga di inviare, e l'unico controllo su quel socket poneva una domanda a cui ogni candidato poteva rispondere correttamente. Se il client è estraneo, "verificare ciò che dice la pagina" non ha più nulla rispetto a cui verificare.

È anche per questo che la gravità si colloca dove si colloca anziché più in alto. L'attacco è locale, presuppone un'estensione già installata nel profilo o altro codice locale e richiede che il daemon sia in esecuzione con la connessione locale abilitata. Tali condizioni sono normali per gli utenti a cui lo strumento è destinato e insolite per tutti gli altri. La gravità media dell'archivio e l'assenza di danni registrata sono coerenti con questa forma: un reale ampliamento della fiducia esattamente al confine che il design avrebbe dovuto sorvegliare, senza alcuna prova che qualcuno lo abbia attraversato.

Il ristretto consiglio pratico che segue non è una mitigazione che qualcuno abbia pubblicato, ma solo il confine che il codice lascia in piedi. Poiché l'ammissione viene decisa una sola volta durante l'handshake su una porta pubblicata, la superficie raggiungibile è determinata da quali estensioni sono installate nel profilo che esegue il daemon e dal fatto che quel daemon e la connessione locale dell'estensione siano attivi in quel momento. Finché non viene distribuita una allow-list di ID delle estensioni, questi due fatti costituiscono l'intero controllo.

A generated abstract illustration on a dark navy field: two identical hexagonal tokens of the same size and colour approach a narrow blue aperture from opposite sides; both pass through, and beyond it their outputs merge into a single stream of pale glyph shapes entering a terminal panel. A faint dotted outline of a browser window sits above. No text, people or organisation logos appear. The OrcaRouter logo is set in the white footer strip at the bottom right.

CVE-2026-94111 invecchierà in uno di due modi. O la pull request viene unita e il record diventa una breve voce su una lacuna nota che ha richiesto tempo, oppure lo stesso controllo di forma è ancora nel codice tra un anno e la voce viene citata come esempio precoce della classe a cui appartiene: non una pagina che veicola un'istruzione ostile, ma la pipe che decide quale pagina l'agente sta leggendo.