
O Tencent BrowserSkill só verificava se um ID de extensão parecia real — qualquer extensão poderia fornecer ao agente páginas forjadas
- OrcaNOVOOrcaCyber: Qwen3.8 Flash Next Abliterated2026-10-26$0.80 / $1.60 por 1M de tokens · 98 tok/s
- OrcaNOVOOrcaCyber: MiMo V2.6 Flash Abliterated2026-10-26$0.80 / $1.60 por 1M de tokens · 115 tok/s
- MoonshotNOVOMoonshotAI: Kimi K3.1 Pro2026-10-2455Inteligência
- OrcaNOVOOrcaCyber: DeepSeek V4.1 Flash Abliterated2026-10-23$0.80 / $1.60 por 1M de tokens · 138 tok/s
- minimaxNOVOMiniMax: M3.1 Flash2026-10-1943Inteligência
- OrcaNOVOOrca: OrcaCyber Ultra 1.02026-10-17$5.00 / $10.00 por 1M de tokens · 43 tok/s
- deepseekNOVODeepSeek: DeepSeek V4.1 Flash 10172026-10-1745Inteligência
- DeepSeekNOVODeepSeek: DeepSeek V4.1 Flash2026-10-1740Inteligência
- OrcaOrca: OrcaCyber Zero 1.52026-10-10$3.00 / $7.50 por 1M de tokens · 111 tok/s
- openaiOpenAI: GPT-6.1 Sol2026-09-2952Inteligência
- anthropicAnthropic: Claude Sonnet 5.52026-09-2856Inteligência
- typesafeTypeSafe: Jev 1.132026-09-24$0.04 / $0.00 por 1M de tokens · 698 tok/s
- OpenAIOpenAI: GPT-6 Luna2026-09-2238Inteligência
- OpenAIOpenAI: GPT-6 Sol2026-09-2248Inteligência
- AnthropicAnthropic: Claude Opus 5.52026-09-2258Inteligência
- xiaomiXiaomi: MiMo-V2.6-Flash2026-09-21$0.14 / $0.28 por 1M de tokens · 45 tok/s
- xiaomiXiaomi: MiMo-V2.6-Pro2026-09-21$0.43 / $0.87 por 1M de tokens · 50 tok/s
- xAIGrok 4.72026-09-2146Inteligência
- OrcaOrca: OrcaCyber Zero 1.02026-09-17$3.00 / $7.50 por 1M de tokens · 231 tok/s
- OrcaOrca: OrcaVerify Text 1.02026-09-16$2.00 / $0.00 por 1M de tokens · 3445 tok/s
Em 17 de setembro de 2026, um usuário do GitHub com o nome carfeii abriu a issue #273 no projeto de código aberto BrowserSkill da Tencent com uma alegação específica: o daemon local que conecta a extensão do navegador a um agente de IA não verificava qual extensão se conectava, apenas se a conexão se parecia com uma extensão. Três dias depois, em 20 de setembro, a VulnCheck publicou a descoberta como CVE-2026-94111, descrevendo um daemon que "aceita qualquer origem chrome-extension com 32 caracteres no intervalo a-p", classificando-a como CWE-346 (erro de validação de origem) e creditando George Chen. O aviso atribui a ela CVSS 4.0 6,9, médio, com impacto de integridade avaliado como alto e confidencialidade e disponibilidade baixas. Nada no registro sugere que a falha tenha sido usada: o arquivo não registra exploração e classifica a confiança da entrada como A, com real_harm falso. Este é um registro em o arquivo de incidentes de IA, onde cada entrada traz suas próprias fontes, gravidade, grau de confiança e sinalizador de disputa.
Uma verificação de formato que nunca verificou a identidade
O código no centro do registro é pequeno. Em crates/bsk-cli/src/daemon/ws.rs, a função origin_allowed() recebe o cabeçalho Origin do handshake WebSocket, remove a string chrome-extension://, e retorna true se o que resta tiver exatamente 32 caracteres e cada caractere estiver entre a e p. Esse é o teste completo. Ele é executado uma vez, dentro do callback de upgrade HTTP, e uma falha retorna um 403 cuja mensagem diz "Origin not in chrome-extension allow-list" — embora, conforme publicado, não houvesse lista na qual estar.
O padrão não é arbitrário. Os IDs de extensão do Manifest V3 do Chrome têm 32 caracteres retirados exatamente dessas dezesseis letras, então a verificação reconhece corretamente o formato de uma origem de extensão real. O defeito é que toda extensão tem esse formato. A verificação pergunta se o chamador parece uma extensão de navegador, nunca se é a extensão de navegador deste projeto, e o identificador com o qual ela deveria ter comparado já era público: o README do projeto tem o link da listagem na Chrome Web Store, cujo ID é hhcmgoofomhgciiibhipgmgkgnoenaoi, e o ID do Edge Add-ons ao lado. Nenhuma das duas strings aparece em lugar algum na verificação.
O daemon escuta em uma porta local fixa, 52800, declarada como DEFAULT_WS_PORT na CLI e usada sem variação no caminho de conexão local. A porta é documentada, constante e acessível por qualquer coisa que já esteja em execução no perfil do navegador do usuário. A localização é o motivo pelo qual o vetor do aviso começa em AV:L — o atacante precisa de um ponto de apoio na máquina, e PR:L registra que um de baixo privilégio é suficiente. Uma extensão instalada no mesmo perfil é exatamente esse tipo de ponto de apoio.
Quanto vale o assento, e quanto disso já está estabelecido
A frase de impacto do aviso é ampla: um atacante que registra uma extensão maliciosa como cliente de navegador pode "interceptar e manipular conteúdo de página, DOM e capturas de tela retornadas ao agente de IA". Essa é a descrição que o CVE, o registro de aviso do GitHub GHSA-x6f2-qp26-2xrh e o arquivo trazem, e explica a classificação de integridade alta no CVSS. É também um resumo escrito pela parte que atribuiu o CVE, não um relato de um ataque demonstrado.
Um relato mais cuidadoso chegou na mesma semana, na própria thread de issues. Em 20 de setembro, um comentarista que publicou como bb6894 relatou ter reverificado o código em relação à main no commit fa953dc6 (18 de setembro) e rastreou o que um cliente externo consegue realmente alcançar após o handshake. A maioria dos métodos de ferramentas de entrada, segundo o comentário, retorna UnknownMethod para um par WebSocket; as solicitações de auditoria ficam restritas aos próprios registros do cliente; e ações entre sessões, como window_closed, user_interrupt e update_interaction, são protegidas contra sessões pertencentes a outro navegador. O que sobrevive a esse filtro é mais restrito e, para um agente, possivelmente pior do que a interceptação: uma extensão externa pode ocupar uma vaga de navegador sob um instance_id escolhido pelo atacante e, se for o único navegador registrado — em uma inicialização a frio ou após reinício do daemon —, recebe as solicitações de ferramentas do agente e responde a elas com conteúdo de página, DOM ou capturas de tela fabricados. O comentarista chama isso de "falsificação de resultados em direção ao agente" e "um canal para a percepção do agente". Um segundo efeito é uma negação de serviço: com um navegador genuíno também on-line e sem seletor, a inicialização da sessão pode falhar com MultipleBrowsersOnline.
Nenhuma das duas versões foi demonstrada publicamente. O repórter descreveu uma prova de conceito como "disponível mediante solicitação"; ninguém publicou uma, e não há registro de exploração. Portanto, a diferença entre as duas versões é uma diferença entre duas leituras do mesmo arquivo-fonte, não entre uma teoria e um exploit funcional — e o texto reporta ambas em vez de escolher. O que se pode afirmar sem ressalvas é que nunca houve uma segunda verificação de identidade após o handshake, de modo que tudo o que o gate admitiu permaneceu admitido durante toda a duração da conexão.
O código já sabia
O documento mais desconfortável neste registro não é o aviso. É o comentário diretamente acima da função, incluído na versão marcada à qual o aviso se refere. Ele marca a lacuna como TODO(M10/M12), nomeia a lista de permissões que pretende criar — um conjunto DaemonConfig::allowed_extension_ids populado a partir de um arquivo de configuração ou fluxo de emparelhamento — e então declara o motivo de ter sido adiado: "lacuna aceitável de defesa em profundidade por enquanto, porque o emparelhamento acontece pelo popup, mas uma extensão carregada lateralmente na mesma máquina atualmente passa pela verificação."
Lido sem rodeios, os mantenedores sabiam qual chamador o gate deixava passar, registraram que sabiam disso e lançaram. Isso não torna a exposição maior do que o aviso diz; torna-a menos surpreendente e desloca a pergunta de “como isso passou pela revisão” para “o que teria tornado a correção adiada urgente”. A suposição de projeto mitigadora é real e também documentada: a conexão local é opt-in. Segundo o README, o usuário instala a extensão, abre o popup dela e habilita a conexão local, e o daemon precisa estar em execução para que qualquer parte disso seja alcançável. Um perfil com a extensão instalada, mas com o toggle desligado, ou sem nenhum daemon bsk em execução, não é um alvo de escuta.
Cinco semanas depois, o portão continua inalterado.

O intervalo afetado do registro é "até 0.3.0", e esse é o intervalo atribuído pela CNA. Não é o fim da história no repositório. A versão 0.3.0 da CLI foi marcada com tag em 17 de setembro às 02:22 UTC; a issue foi registrada no mesmo dia às 15:14 UTC, cerca de treze horas depois. Três outras versões da CLI foram lançadas desde então — 0.3.1 em 23 de setembro, 0.3.2 em 30 de setembro, e 0.3.3 em 15 de outubro — e a função origin_allowed() em cada uma dessas tags é a mesma verificação descrita acima, com o TODO ainda acima dela. O branch main também a contém em 27 de outubro.
Existe uma correção, mas apenas como proposta. Em 28 de setembro, um colaborador que publica como dangzitouabriu o pull request #363 a partir de um fork pessoal, intitulado "fix(daemon): pin WS origin gate to BrowserSkill's own extension ids". Ele substitui o teste de formato por uma comparação com os dois IDs da loja e adiciona BSK_ALLOWED_EXTENSION_IDS como um caminho de admissão explícito para builds carregados lateralmente e de desenvolvimento, cujos IDs não empacotados são derivados do caminho de instalação. O corpo do pull request afirma que ele fecha tanto o caminho de falsificação quanto a negação de serviço do MultipleBrowsersOnline. Em 27 de outubro, ele ainda está aberto e não foi mesclado, e a issue permanece aberta sem nenhuma declaração do fornecedor anexada a ela.
A consequência prática é que não há nenhuma versão para a qual atualizar que contenha a correção. Quem aconselha "atualizar para além da 0.3.0" está aconselhando um passo que ainda não existe: as versões posteriores são posteriores, não corrigidas. O intervalo do registro deve ser lido como o intervalo que o CNA avaliou em 20 de setembro, e não como uma afirmação de que a 0.3.1 e as seguintes estão limpas.
O que está estabelecido e o que não está
• Estabelecido: o código-fonte publicado na tag cli-v0.3.0 contém uma verificação de origem que aceita qualquer origem chrome-extension de 32 caracteres de a–p. O relator, o CNA e o próprio arquivo concordam, e o código é público.
• Estabelecido: o gate era executado uma vez, na atualização do WebSocket, sem verificação de identidade posterior, em uma porta local fixa 52800.
• Estabelecido: o próprio comentário no código-fonte do projeto reconhecia que uma extensão instalada por sideload passaria, e adiou a lista de permissões.
• Estabelecido: CVSS 4.0 6.9 e CVSS 3.1 6.6 são ambas pontuações da VulnCheck, registradas pelo NVD como secundárias. O status do próprio NVD para a entrada é Deferred, o que significa que ele publicou os dados da CNA sem adicionar uma análise de autoria do NVD.
• Estabelecido: A avaliação SSVC da CISA, datada de 21 de setembro, registra a exploração como nenhuma, a automatização como não e o impacto técnico como parcial. O EPSS da FIRST coloca a probabilidade de exploração nos próximos trinta dias em 0,00135, o 2,9º percentil, em 26 de outubro.
• Não estabelecido: qualquer uso no mundo real. Nenhuma exploração, nenhuma prova de conceito publicada, nenhuma contagem de instalações afetadas. As métricas do repositório do projeto não são uma contagem de instalações, e ninguém publicou uma.
• Não estabelecido: qual conta de impacto se aplica. O "interceptar e manipular" da CNA e a "falsificação de resultados mais negação de serviço" da thread descrevem tetos diferentes, e nenhum foi demonstrado fora da leitura de código.
• Não estabelecido: que a falha termina na 0.3.0. A string de versão é a avaliação da CNA; o código não foi alterado nas três versões lançadas depois dela, e nenhuma declaração do fornecedor as isenta.
• Contraditado, não resolvido: um agregador, o DevGuard, exibe um sinal de "foram detectadas tentativas de exploração" para este CVE sem nomear uma fonte, IOC ou provedor de telemetria. Isso contrasta com a avaliação registrada da CISA de ausência de exploração e com a ausência de qualquer relatório público; o arquivo também não registra exploração. Trate o sinalizador do agregador como não comprovado, e não como um segundo ponto de dados.

Por que o transporte é o alvo interessante
A maioria das orientações sobre injeção de prompt traça a mesma fronteira: tratar o texto de página recuperado como não confiável e tratar o mecanismo que o entrega como confiável. Presume-se que uma ferramenta que lê uma página web está lendo a página; a questão é o que a página diz. Este registro inverte isso. O que o agente recebe como conteúdo da página, DOM e capturas de tela é o que o cliente na outra ponta de um socket local decidir enviar, e o único controle nesse socket fazia uma pergunta que qualquer candidato conseguia responder corretamente. Se o cliente for externo, “verificar o que a página diz” não tem mais nada contra o que verificar.
É também por isso que a gravidade fica onde fica, e não mais alta. O ataque é local, pressupõe uma extensão já instalada no perfil ou outro código local, e exige que o daemon esteja em execução com a conexão local habilitada. Essas condições são comuns para os usuários a que a ferramenta se destina e incomuns para todos os demais. A gravidade média do arquivo e a ausência de danos registrada são consistentes com esse formato: um verdadeiro alargamento da confiança exatamente na fronteira que o design deveria policiar, sem evidência de que alguém a tenha atravessado.
O conselho prático e restrito que se segue não é uma mitigação que alguém tenha publicado, mas apenas o limite que o código deixa de pé. Como a admissão é decidida uma única vez no handshake em uma porta publicada, a superfície alcançável é definida por quais extensões estão instaladas no perfil que executa o daemon e por se esse daemon e a conexão local da extensão estão ativados no momento. Até que uma lista de permissões de IDs de extensão seja disponibilizada, esses dois fatos são todo o controle.

A CVE-2026-94111 envelhecerá de uma de duas maneiras. Ou o pull request é mesclado e o registro se torna uma entrada curta sobre uma lacuna conhecida que levou um tempo para ser corrigida, ou a mesma verificação de forma ainda estará na árvore daqui a um ano e a entrada será citada como um exemplo inicial da classe à qual pertence: não uma página que carrega uma instrução hostil, mas o pipe que decide qual página o agente está lendo.
