Privacidade Por Equipe DevBras

Capa do artigo: Extensões do Chrome sequestram a busca: como checar

Extensões do Chrome sequestram a busca: como checar

319 extensões do Chrome trocam seu buscador e mandam cada pesquisa a terceiros. Veja como checar perfis, achar IDs no disco e bloquear com política na empresa.

A Socket publicou em 29/10/2026 a lista de 319 extensões do Chrome, somando cerca de 13,4 milhões de instalações, que trocam o buscador padrão do navegador e fazem cada pesquisa passar por um servidor dos operadores antes de chegar ao Yahoo ou ao Bing. Para saber se você ou alguém da sua empresa tem uma delas, três conferências bastam: a lista em chrome://extensions, o buscador padrão nas configurações e uma varredura dos arquivos manifest.json no perfil do navegador procurando a chave chrome_settings_overrides. Este guia mostra as três, traz um script testado que lista as extensões de todos os perfis e marca as que trocam a busca, e termina com as políticas do Chrome Enterprise que impedem o problema na empresa.

O que a pesquisa encontrou

O relatório Searchjacked, do pesquisador John Tuckner, amplia um levantamento de abril de 2025 que tinha achado 57 extensões com 6 milhões de usuários. Agora são mais 264 extensões e 8,7 milhões de usuários, e a mais antiga é de 2016. O BleepingComputer repercutiu o caso no mesmo dia. Os pontos que importam para quem vai checar:

  • Os disfarces: conversor de PDF, localizador de manuais, "busca segura" e busca com IA. A onda chamada SecuryBrowse usou nomes de segurança, como Fire Shield, Securify, Protecto e WatchTower.
  • Escondidas na loja: a maioria está como "não listada" na Chrome Web Store. A página existe, mas não aparece na busca da loja; só chega nela quem tem o link.
  • Chegam por anúncio: pop-ups e pop-unders em sites de baixa qualidade, comprados no Google Ads, na Bidbrain e em outras redes, levam a uma página com um botão de instalar.
  • Os maiores grupos: SecuryBrowse, com 58 extensões e cerca de 4,9 milhões de usuários; Bing-Search, com 37 extensões e 2,2 milhões; e a Intango LTD, com 111 extensões e cerca de 2,19 milhões.
  • Remoção parcial: segundo o BleepingComputer, a maior parte já tinha saído da loja quando o relatório saiu, mas outras continuam surgindo. O site pediu um posicionamento ao Google e não teve resposta até a publicação.

Por que uma extensão sem permissão nenhuma é o problema

O Chrome tem um recurso oficial para extensões trocarem a página inicial, as páginas de abertura e o buscador: a chave chrome_settings_overrides do manifesto, descrita na documentação de extensões do Chrome. Ela não precisa de código. Uma das extensões analisadas pela Socket tinha só o manifest.json e três ícones, sem permissões, sem service worker e sem script de página. Quem revisa extensões olhando só as permissões pedidas conclui que ela é inofensiva, e é exatamente esse o erro que o relatório aponta.

O ganho do operador vem dos programas de distribuição de busca do Yahoo e da Microsoft, que pagam parte da receita de anúncios a quem traz a pesquisa. O parceiro é identificado na URL: hspart= e hsimp= no Yahoo, PC= e PTAG= no Bing. Se fosse só isso, a extensão poderia mandar a busca direto para o Yahoo com a tag. Ela passa antes pelo servidor do operador, que fica com o histórico completo de pesquisas e escolhe, pedido a pedido, para onde mandar você.

O desenho abaixo resume o caminho de uma busca com a Predator Search, a extensão que a Socket usou como exemplo.

O que vimos no código da Predator Search

A Predator Search (ID odkcfoohjiicbelloepgcomekdknchjh) está no relatório com 50 mil usuários. Nos testes da Socket, seis buscas iguais terminaram em quatro lugares: no Yahoo com a tag hspart=sz&hsimp=yhs-026, numa página em searchlio.net, num salto por searchtosearch.com e mcftink.com antes do Yahoo, e numa página de erro da Cloudflare. A extensão não mudou entre uma busca e outra; quem decidiu foi o servidor.

Às 23h58 de 29/10/2026 (horário de Brasília), a página dela na Chrome Web Store ainda estava no ar, com 50.000 usuários, versão 1.0.2 e atualização de 20/05/2024. Baixamos o pacote dessa versão do servidor de atualização do Chrome e abrimos os arquivos sem instalar. Ao contrário do exemplo minimalista do relatório, esta tem código, e o código mostra como as buscas ficam ligadas a uma pessoa:

  • No primeiro uso, o bgrd.js sorteia um identificador de 32 caracteres, guarda no armazenamento da extensão e avisa o servidor em /start?session=.
  • Com a permissão declarativeNetRequest, cria uma regra que acrescenta session= com esse identificador a toda busca enviada para predatorwallpaper.com/search.
  • Registra uma URL de desinstalação com o mesmo identificador, então o servidor também fica sabendo quando a extensão é removida.

Na prática, todas as pesquisas daquele navegador chegam ao operador com a mesma etiqueta. É o que a Socket descreve como histórico de busca "muitas vezes ligado a um identificador único".

Confira em dois minutos pelo navegador

  1. Abra chrome://extensions e ligue o Modo do desenvolvedor no canto superior direito. Cada extensão passa a mostrar o ID de 32 letras, que é o que você compara com a lista do relatório. Desconfie de nomes como "PDF", "Manual", "Safe Search" ou "AI Search" que você não lembra de ter instalado.
  2. Abra chrome://settings/search. Se o buscador foi trocado por uma extensão, o Chrome diz qual extensão controla a configuração, e o seletor fica travado até você desativá-la. A ajuda do Chrome sobre o mecanismo de pesquisa padrão mostra onde fica cada opção.
  3. Faça uma busca pela barra de endereço e olhe a URL da página de resultados. Parâmetros como hspart=, hsimp=, PC= ou PTAG= num buscador que você não escolheu indicam que a pesquisa foi monetizada por um parceiro.

A documentação do Chrome informa que a troca de configurações pelo manifesto está disponível no Windows e no Mac. Quem usa Linux tem menos exposição a esse truque específico, mas a conferência pelos arquivos, logo abaixo, continua valendo para o inventário das extensões.

Onde as extensões ficam no disco

Cada perfil do navegador guarda as extensões instaladas pela loja numa pasta Extensions, com uma subpasta por ID e, dentro dela, uma por versão, onde está o manifest.json:

  • Windows: %LOCALAPPDATA%\Google\Chrome\User Data\<perfil>\Extensions\ (Edge em Microsoft\Edge\User Data, Brave em BraveSoftware\Brave-Browser\User Data).
  • macOS: ~/Library/Application Support/Google/Chrome/<perfil>/Extensions/.
  • Linux: ~/.config/google-chrome/<perfil>/Extensions/ (Chromium em ~/.config/chromium, ou ~/snap/chromium/common/chromium no Ubuntu com snap).

O primeiro perfil se chama Default; os outros, Profile 1, Profile 2 e assim por diante. Feche o navegador antes de mexer em qualquer coisa ali dentro. Para só procurar, no macOS ou no Linux, um grep resolve:

cd ~/.config/google-chrome   # no macOS: cd ~/Library/Application\ Support/Google/Chrome
grep -l '"search_provider"' */Extensions/*/*/manifest.json

No Windows, este trecho de PowerShell lista as extensões que trocam a busca em todos os perfis do Chrome. Testamos com o PowerShell 7.6.9, passando uma pasta de teste em -Base; sem o parâmetro, ele usa a pasta padrão do Chrome:

param([string]$Base = "$env:LOCALAPPDATA\Google\Chrome\User Data")
Get-ChildItem -Path $Base -Filter manifest.json -Recurse -Depth 4 |
  Where-Object { $_.FullName -match '[\\/]Extensions[\\/][a-p]{32}[\\/]' } |
  ForEach-Object {
    $m = Get-Content $_.FullName -Raw -Encoding UTF8 | ConvertFrom-Json
    $partes = $_.FullName -split '[\\/]'
    [pscustomobject]@{
      Perfil = $partes[-5]
      Id     = $partes[-3]
      Nome   = $m.name
      Busca  = $m.chrome_settings_overrides.search_provider.search_url
    }
  } | Where-Object Busca | Format-List

Na pasta de teste, a saída foi:

Perfil : Profile 1
Id     : bkdgflcldnnnapblkhphbgpggdiikppg
Nome   : __MSG_appName__
Busca  : https://duckduckgo.com/?q={searchTerms}

Perfil : Default
Id     : odkcfoohjiicbelloepgcomekdknchjh
Nome   : Predator Search
Busca  : https://predatorwallpaper.com/search?q={searchTerms}

O __MSG_appName__ é um nome traduzido: o texto real fica na pasta _locales da extensão. O script em Python a seguir já resolve isso.

Um script que varre todos os perfis

O checar_extensoes.py roda com Python 3 no Windows, no macOS e no Linux, sem dependências. Sem argumentos, ele procura as pastas do Chrome, do Edge, do Brave e do Chromium do usuário. Para cada extensão, mostra perfil, ID, nome e versão, e marca [TROCA A BUSCA] quando o manifesto define search_provider e [TROCA INICIO] quando troca a página inicial ou a de abertura. Com --ioc arquivo.txt, compara os IDs com uma lista e sai com código 2 se encontrar algum, o que serve para rodar em lote por uma ferramenta de gestão de máquinas.

#!/usr/bin/env python3
"""Lista extensões instaladas no Chrome, Edge, Brave e Chromium e marca as que trocam a busca."""
import json, os, re, sys
from pathlib import Path

ID_RE = re.compile(r"^[a-p]{32}$")

def pastas_padrao():
    h = Path.home()
    if sys.platform.startswith("win"):
        base = Path(os.environ.get("LOCALAPPDATA", h / "AppData/Local"))
        rel = ["Google/Chrome/User Data", "Microsoft/Edge/User Data",
               "BraveSoftware/Brave-Browser/User Data", "Chromium/User Data"]
    elif sys.platform == "darwin":
        base = h / "Library/Application Support"
        rel = ["Google/Chrome", "Microsoft Edge", "BraveSoftware/Brave-Browser", "Chromium"]
    else:
        base = h
        rel = [".config/google-chrome", ".config/microsoft-edge",
               ".config/BraveSoftware/Brave-Browser", ".config/chromium",
               "snap/chromium/common/chromium"]
    return [base / r for r in rel if (base / r).is_dir()]

def ler_json(p):
    with open(p, encoding="utf-8-sig") as f:
        return json.load(f)

def traduzir(texto, pasta, manifest):
    m = re.fullmatch(r"__MSG_(\w+)__", texto or "")
    if not m:
        return texto
    loc = manifest.get("default_locale", "en")
    try:
        msgs = {k.lower(): v for k, v in ler_json(pasta / "_locales" / loc / "messages.json").items()}
        return msgs[m.group(1).lower()]["message"]
    except (OSError, KeyError, ValueError):
        return texto

def carregar_ioc(arq):
    ids = set()
    for linha in open(arq, encoding="utf-8"):
        tok = linha.split("#", 1)[0].strip().split()
        if tok and ID_RE.match(tok[0]):
            ids.add(tok[0])
    return ids

def varrer(user_data, ioc):
    nomes = {}
    try:
        nomes = {k: v.get("name", k) for k, v in
                 ler_json(user_data / "Local State")["profile"]["info_cache"].items()}
    except (OSError, KeyError, ValueError):
        pass
    for ext_dir in sorted(user_data.glob("*/Extensions")):
        perfil = ext_dir.parent.name
        for pasta_id in sorted(ext_dir.iterdir()):
            if not ID_RE.match(pasta_id.name):
                continue
            versoes = sorted(p for p in pasta_id.iterdir() if (p / "manifest.json").is_file())
            if not versoes:
                continue
            pasta = max(versoes, key=lambda p: p.stat().st_mtime)
            man = ler_json(pasta / "manifest.json")
            ov = man.get("chrome_settings_overrides", {})
            busca = ov.get("search_provider", {}).get("search_url", "")
            alertas = []
            if busca:
                alertas.append("TROCA A BUSCA")
            if ov.get("homepage") or ov.get("startup_pages"):
                alertas.append("TROCA INICIO")
            if pasta_id.name in ioc:
                alertas.append("NA LISTA IOC")
            yield {"perfil": f"{perfil} ({nomes.get(perfil, '?')})", "id": pasta_id.name,
                   "nome": traduzir(man.get("name"), pasta, man), "versao": man.get("version"),
                   "busca": busca, "alertas": alertas}

def main():
    args = sys.argv[1:]
    ioc = set()
    if "--ioc" in args:
        i = args.index("--ioc"); ioc = carregar_ioc(args[i + 1]); del args[i:i + 2]
        print(f"lista IoC: {len(ioc)} IDs")
    pastas = [Path(a) for a in args] or pastas_padrao()
    achou_ioc = False
    for ud in pastas:
        print(f"\n== {ud}")
        for e in varrer(ud, ioc):
            marca = " ".join(f"[{a}]" for a in e["alertas"])
            print(f"{e['perfil']:<22} {e['id']}  {e['nome']} {e['versao']} {marca}")
            if e["busca"]:
                print(f"{'':<22} busca vai para: {e['busca']}")
            achou_ioc |= "NA LISTA IOC" in e["alertas"]
    sys.exit(2 if achou_ioc else 0)

if __name__ == "__main__":
    main()

Para testar sem depender de uma máquina infectada, montamos uma cópia de perfil com dois perfis e três extensões reais, baixadas do servidor de atualização do Chrome em 29/10/2026: a Predator Search, o uBlock Origin Lite e a extensão oficial do DuckDuckGo. O arquivo ids-socket.txt tinha só o ID da Predator Search. Saída com Python 3.13.5:

$ python3 checar_extensoes.py --ioc ids-socket.txt google-chrome
lista IoC: 1 IDs

== google-chrome
Default (Pessoal)      ddkjiahejlhfcafbddmgiahcphecmpfh  uBlock Origin Lite 2026.1026.1812 
Default (Pessoal)      odkcfoohjiicbelloepgcomekdknchjh  Predator Search 1.0.2 [TROCA A BUSCA] [NA LISTA IOC]
                       busca vai para: https://predatorwallpaper.com/search?q={searchTerms}
Profile 1 (Trabalho)   bkdgflcldnnnapblkhphbgpggdiikppg  DuckDuckGo Search & Tracker Protection 2026.10.6 [TROCA A BUSCA]
                       busca vai para: https://duckduckgo.com/?q={searchTerms}

Repare que a extensão do DuckDuckGo também aparece com [TROCA A BUSCA]. Trocar o buscador é um recurso legítimo, e é para isso que ela existe. A marca não é veredito: ela separa as poucas extensões que merecem olhar com calma. Para cada uma, confira se o endereço em "busca vai para" é do buscador que você escolheu, quem publica a extensão e se você se lembra de ter instalado.

Comparar com a lista do relatório

A lista completa das 319 extensões fica no fim do relatório da Socket, carregada na própria página. Copie os IDs para um arquivo texto, um por linha (linhas com # são ignoradas), e rode o script com --ioc. Sem Python, o comm do macOS e do Linux cruza as duas listas:

cd ~/.config/google-chrome
ls */Extensions/ | grep -E '^[a-p]{32}$' | sort -u > /tmp/instaladas.txt
grep -oE '^[a-p]{32}' ids-socket.txt | sort -u > /tmp/ioc.txt
comm -12 /tmp/instaladas.txt /tmp/ioc.txt

Na pasta de teste, a única linha impressa foi odkcfoohjiicbelloepgcomekdknchjh. Quem quer uma lista mais ampla pode usar também a base comunitária chrome-mal-ids, que reúne IDs de extensões maliciosas de várias campanhas. A versão gerada às 17h20 de 29/10 (horário de Brasília) tinha 8.710 IDs e já incluía a Predator Search; o script lê o current-list.txt dela sem ajuste. É uma base mantida por voluntários, então trate um acerto ali como motivo para investigar, não como prova.

Achou uma: o que fazer

  1. Remova a extensão em chrome://extensions, em todos os perfis em que ela aparecer. Se a sincronização do Chrome estiver ligada, confira os outros computadores da mesma conta.
  2. Volte o buscador em chrome://settings/search e apague, na lista de mecanismos de pesquisa, o que a extensão criou. Se a página inicial também mudou, a ajuda do Chrome para remover pop-ups e programas indesejados explica como redefinir as configurações.
  3. Passe um antivírus completo, como recomenda o BleepingComputer. A extensão chegou por um anúncio, e a mesma página pode ter oferecido outros downloads.
  4. Considere vazado o que foi pesquisado pela barra de endereço. O operador recebeu tudo com o mesmo identificador. Se alguém da empresa digitou ali nomes de clientes, endereços internos, números de pedido ou, por engano, um token ou senha, troque o segredo primeiro, como no guia sobre segredo que vazou no Git, e avise quem precisa saber. O raciocínio é o mesmo do nosso guia sobre dado sensível que vaza pelos logs: o que saiu não volta.

Até aqui, a Socket registrou desvios para páginas de resultados, para a página inicial do Google e para páginas de erro. O alerta do relatório é que o destino é decidido no servidor e pode virar phishing ou download malicioso sem nenhuma atualização da extensão. Por isso vale remover mesmo que "a busca esteja funcionando".

Na empresa: bloquear com política do Chrome

Remover à mão não escala, e a próxima leva de extensões vai ter outros IDs. O Chrome Enterprise resolve isso de outro jeito: só entra o que foi aprovado, e o buscador fica fixo. As políticas estão na lista oficial de políticas do Chrome Enterprise:

Um ponto de partida que bloqueia tudo, libera o uBlock Origin Lite como exemplo de extensão aprovada, remove a Predator Search de onde já estiver e prende o buscador no Google:

{
  "ExtensionSettings": {
    "*": {
      "installation_mode": "blocked",
      "blocked_install_message": "Extensões precisam de aprovação da TI. Abra um chamado."
    },
    "ddkjiahejlhfcafbddmgiahcphecmpfh": { "installation_mode": "allowed" },
    "odkcfoohjiicbelloepgcomekdknchjh": { "installation_mode": "removed" }
  },
  "DefaultSearchProviderEnabled": true,
  "DefaultSearchProviderName": "Google",
  "DefaultSearchProviderSearchURL": "{google:baseURL}search?q={searchTerms}"
}

No Linux, esse arquivo vai em /etc/opt/chrome/policies/managed/, sem permissão de escrita para usuários comuns, como manda o guia de políticas do Chrome no Linux. No Windows, pela Política de Grupo, o valor de ExtensionSettings precisa ser colado numa linha só. Este comando gera a versão compacta a partir do arquivo acima:

python3 -c "import json;d=json.load(open('politica-chrome.json'));print(json.dumps(d['ExtensionSettings'],ensure_ascii=False,separators=(',',':')))"
{"*":{"installation_mode":"blocked","blocked_install_message":"Extensões precisam de aprovação da TI. Abra um chamado."},"ddkjiahejlhfcafbddmgiahcphecmpfh":{"installation_mode":"allowed"},"odkcfoohjiicbelloepgcomekdknchjh":{"installation_mode":"removed"}}

Com o Chrome gerenciado em nuvem, as mesmas regras ficam no Admin Console, e a página Gerenciar extensões na sua empresa explica como montar o processo de pedido e aprovação. Depois de aplicar, abra chrome://policy numa máquina da empresa e confira se as quatro políticas aparecem com status OK. O JSON acima foi validado e compactado no nosso ambiente, mas não o aplicamos num Chrome gerenciado. Teste primeiro num grupo pequeno de máquinas, porque o "*": blocked desativa na hora tudo o que não estiver liberado.

Pense no navegador como pensa nas dependências do projeto: o que roda ali precisa estar inventariado e travado, do mesmo jeito que o lockfile garante que a versão testada é a que vai para produção. Uma lista de extensões aprovadas é o lockfile do Chrome da empresa.

Em poucas linhas

  • As 319 extensões não pedem permissão para trocar a busca; o manifesto basta. Por isso, procure chrome_settings_overrides, não permissões.
  • chrome://extensions com o modo do desenvolvedor mostra os IDs; chrome://settings/search mostra se uma extensão controla o buscador.
  • O script deste guia varre todos os perfis e navegadores e compara com a lista da Socket.
  • Na empresa, ExtensionSettings com "*": blocked e o buscador fixo por política cortam o problema antes da próxima leva.


Avalie este artigo