A página web chamada localhost
Em 17 de agosto, a CISA adicionou a CVE-2025-62593 do Ray ao seu catálogo de Vulnerabilidades Exploradas Conhecidas. É execução remota de código na própria máquina do desenvolvedor, entregue por uma página web que ele visitou, alcançando um serviço que só escutava em 127.0.0.1. Agentes de código vêm enchendo essa interface de servidores sem autenticação o ano inteiro. O Bromure Agentic Coding coloca esses servidores onde nenhuma aba de navegador consegue discar.
Seu servidor de desenvolvimento, seu notebook e seu painel local cada um
ligam uma porta sem autenticação a 127.0.0.1, no raciocínio de que só quem
está ao teclado consegue alcançá-la. Uma página web também consegue. A
política de navegador que está no caminho se desfaz em uns sessenta segundos.
Em 17 de agosto, a CISA adicionou uma vulnerabilidade ao seu catálogo de Vulnerabilidades Exploradas Conhecidas e deu às agências federais até 20 de agosto para tratá-la. O The Hacker News escreveu sobre isso na manhã seguinte. A entrada é a CVE-2025-62593, uma falha de injeção de código no Ray, o framework de computação distribuída que boa parte da indústria usa para treinar e servir modelos.
O código roda no laptop do próprio desenvolvedor. Alguém tinha o Ray rodando localmente para o seu trabalho, abriu uma página web, e a página executou um comando por ele.
Três fatos comuns, mal arranjados
O aviso dá nota 9,4 e descreve uma cadeia sem nenhum passo exótico dentro.
A API de Jobs do Ray recebe um comando de shell. Esse é o produto: você faz
POST em /api/jobs/ com um entrypoint e o cluster roda o comando. O painel
escuta na porta 8265, e nem ele nem os endpoints de jobs exigem autenticação.
Foi uma decisão deliberada dos mantenedores, cuja posição é que
segurança e isolamento precisam ser impostos fora do cluster Ray.
Você o coloca em algum lugar que só chamadores confiáveis alcançam, e a
interface de loopback de um laptop soa como um lugar assim.
O Ray até tinha uma guarda contra navegadores. Ele checava se o cabeçalho
User-Agent começava com Mozilla e recusava essas requisições, na suposição
de que um navegador não pode mentir sobre o próprio User-Agent. No Firefox e
no Safari, a API Fetch deixa a página definir esse cabeçalho como bem entender.
Sobra a política de mesma origem, o único controle entre uma página na internet
e um serviço na sua máquina. O DNS rebinding a desmonta. O atacante serve a
página a partir de um domínio cujos registros DNS ele controla, com um
time-to-live muito curto. A página carrega e então resolve de novo esse mesmo
domínio para 127.0.0.1. O navegador continua tratando como a mesma origem,
mesmo hostname e mesma porta, enquanto toda requisição agora vai para a sua
máquina. A prova de conceito publicada usa
singularity, um framework de
rebinding que é público há anos.
Encadeie tudo isso e uma página maliciosa, ou um anúncio contaminado numa página
em que você confiava, posta um job na sua instância Ray com um comando de shell
dentro. O Chrome está protegido por um bug sem relação; o Firefox e o Safari
não. Avi Lumelsky, da Oligo, teorizou o bypass do User-Agent; Jonathan
Leitschuh, então na Socket, construiu a cadeia de rebinding e a divulgação. O
Ray 2.52.0 corrige a falha e adiciona autenticação por token opcional,
desligada por padrão.
Os atacantes chegaram antes do aviso. A botnet RondoDox pegou a falha dois dias antes da divulgação pública, e a pesquisa ShadowRay 2.0 da Oligo acompanha uma campanha que transforma implantações do Ray em uma botnet autopropagante: clusters comprometidos escaneiam em busca de mais instâncias Ray e as infectam, um cron job puxa novas cargas de repositórios controlados pelo atacante a cada quinze minutos, e a carga minera Monero, abre shells reversos e leva o que encontrar. A Oligo contou mais de 230.000 servidores Ray expostos, um aumento de dez vezes desde o primeiro relatório em 2024. Um único cluster comprometido entregou 240 GB de código-fonte, modelos e conjuntos de dados.
O que está escutando na sua máquina
Deixe o Ray de lado e conte outra coisa: os servidores HTTP sem autenticação ligados à sua interface de loopback neste momento, e quantos deles você conseguiria nomear sem olhar.
Rode lsof -iTCP -sTCP:LISTEN -P depois de uma semana de trabalho e a lista sai
mais longa do que você imagina. Vite na 5173. Um serviço FastAPI sob
uvicorn --reload na 8000. Jupyter na 8888, mlflow ui na 5000, a porta
publicada de um contêiner Postgres, um servidor MCP na 3000, uma porta de debug
deixada aberta por um teste que quebrou. Nenhum deles pergunta quem é você. Os
autores fizeram a mesma suposição que os mantenedores do Ray fizeram, e ela se
sustenta até uma aba em outra janela começar a fazer requisições.
Os agentes mudaram o volume. Um agente trabalhando num ticket sobe serviços como parte natural do ofício. Ele roda o servidor de desenvolvimento para conferir a própria mudança, sobe um banco de dados para rodar a migração, inicia o notebook para olhar os dados, lança a API para bater num endpoint. Faz isso várias vezes por tarde, em vários workspaces, e não limpa nada, porque nada manda limpar. Os processos sobrevivem à tarefa. Na quinta-feira a interface carrega uma dúzia de serviços que você não iniciou e não conseguiria listar de memória, cada um se ligando sem autenticação porque o guia de início rápido do framework diz que em localhost está tudo bem.
A posição do Ray se lê de outro jeito numa máquina rodando um agente de código: segurança e isolamento precisam ser impostos fora da coisa que você iniciou. Num laptop onde o agente e o navegador dividem um único kernel, “fora” não tem onde ficar.
Num workspace Bromure, a 8265 não está no seu Mac
O Bromure Agentic Coding roda cada workspace na sua própria VM Ubuntu sobre o framework Virtualization da Apple. Essa é a resposta inteira a esse ataque, e ela se sustenta sem ninguém aplicar patch nenhum.
Quando o agente roda ray start --head, o painel se liga a 127.0.0.1:8265
dentro da VM. A interface de loopback do seu Mac é outra interface. Um fetch()
com rebinding a partir do Safari no host resolve evil.example para
127.0.0.1, conecta no loopback do macOS e não obtém nada, porque o serviço que
a página veio procurar está um kernel adiante. A cadeia publicada mira
127.0.0.1, o endereço para o qual o singularity faz rebinding e o endereço
que o aviso nomeia, e num workspace Bromure esse endereço não tem nada nele.
Vale o mesmo para a segunda metade do aviso, a parte sobre usar um navegador como intermediário para alcançar instâncias Ray dentro de uma rede corporativa que ninguém colocou na internet. Workspaces rodam em modo NAT por padrão, e o manual é específico sobre o que isso compra: as VMs são alcançáveis a partir do seu Mac mas não ficam expostas na sua LAN física, e conexões de entrada vindas de outro lugar não são possíveis a menos que você publique um serviço de propósito. Publicar é um túnel rápido da Cloudflare por serviço, que você inicia apertando um botão.
E você ganha o inventário. O cartão Portas em escuta do painel do workspace
consulta ss -tulnpH dentro do guest e lista cada socket alcançável de fora
como o IP-da-VM:porta ao qual você se conectaria, com o nome do processo que o
segura. O cartão esconde sockets só de loopback, já que nada fora da VM os
alcança. A mesma lista sai de bromure-cli vm <id> -L. Essa lista é o censo das
sobras do agente, e o macOS não mantém lista nenhuma para você.
O salto depois do primeiro
O ShadowRay 2.0 vale a leitura pelo que um nó comprometido faz em seguida, porque é dessa parte que o isolamento tem de dar conta. Ele escaneia em busca de outras instâncias Ray e as infecta. Ele instala um cron job que busca novas instruções a cada quinze minutos. Ele avança sobre quaisquer credenciais e conjuntos de dados que estejam na máquina.
Cada uma dessas coisas é uma conexão de saída, e um workspace Bromure confronta conexões de saída com regras que você escreveu. O editor Conexões de saída no painel Guardrails guarda um conjunto de regras no estilo pf: permitir ou negar, por host, IP ou CIDR, protocolo e porta, avaliado de cima para baixo com a primeira correspondência vencendo, mais um controle para o tráfego que não casa com nada.
allow web api.github.com:443
allow tcp registry.npmjs.org:443
deny any 10.0.0.0/8
deny any 192.168.0.0/16
default deny
Duas camadas aplicam esse mesmo conjunto de regras. O switch virtual avalia cada
fluxo pelo IP de destino e pelos hostnames que aprendeu bisbilhotando as
respostas de DNS do próprio guest, de modo que uma regra escrita contra um nome
continua casando quando o endereço se move por baixo dela. O proxy MITM avalia
as mesmas regras por SNI do TLS, e para regras web por método HTTP, então você
pode escrever allow web api.example.com GET,HEAD. O Bromure injeta um reset
numa conexão TCP negada, então o connect falha em vez de ficar pendurado.
Toda essa aplicação roda no seu Mac, fora da VM. A interceptação transparente
vem ligada por padrão e desvia o HTTP e o HTTPS do guest para o Bromure mesmo se
algo lá dentro apagar HTTP_PROXY e HTTPS_PROXY. Um agente que leu a página
web errada, ou uma carga que entrou junto com um pacote, fica do lado errado das
regras que precisaria editar. O Bromure escreve cada decisão em Janela → Linha
do Tempo de Segurança como uma linha de Firewall: host, porta, permitido ou
bloqueado, numa única tabela cronológica ao lado das decisões de credencial,
cadeia de suprimentos e injeção de prompt.
O cron de quinze minutos tem o mesmo problema na direção oposta. Um workspace
são três camadas de armazenamento, e duas delas são suas para descartar:
Apagar home… devolve /home/ubuntu ao estado logo após o clone,
Redefinir para a base… reclona o disco de sistema do workspace a partir da
imagem base, e a imagem base fica somente leitura em tempo de execução. Uma
crontab no diretório home não sobrevive a nenhuma das duas.
localhost era uma convenção
Os mantenedores do Ray não foram descuidados. Eles escreveram um framework de computação que roda comandos, disseram isso na documentação, e mandaram você colocar uma fronteira em volta. As pessoas que o rodam num laptop tomaram a interface de loopback como essa fronteira, que é a conclusão para a qual servidores de desenvolvimento, notebooks e painéis locais vêm convidando há vinte anos. Aquilo era uma convenção, não um controle. Sustentava-se enquanto as únicas coisas na sua máquina eram coisas que você mesmo iniciou, e deixou de se sustentar quando os navegadores ganharam um motor de script.
Um agente alarga a fresta toda tarde, um npm run dev de cada vez. Cuidado não
a fecha, porque cuidado exige saber o que está escutando, e a lista muda a cada
comando que o agente roda.
Pare de deixar os dois dividirem uma interface. Ponha o trabalho do agente na
sua própria máquina, onde as portas que ele abre respondem ao seu Mac e a mais
ninguém, onde os sockets alcançáveis são uma lista que você lê em vez de uma
suposição que você herdou, e onde as conexões que saem são confrontadas com
regras que o workspace não consegue editar. Uma página que faz rebinding para
127.0.0.1 então encontra uma interface vazia e leva uma recusa.
Fontes: CISA, “CISA Adds One Known Exploited Vulnerability to Catalog” (17 de agosto de 2026) · The Hacker News, “CISA Flags Actively Exploited Ray Flaw That Can Trigger Browser-Based RCE” (18 de agosto de 2026) · Aviso do GitHub GHSA-q279-jhrf-cc6v (CVE-2025-62593) · Oligo Security, “ShadowRay 2.0”