Voltar para todas as publicações
Publicado em · por Renaud Deraison

O registro passava recadinhos entre sandboxes

A Check Point publicou em 8 de setembro uma pesquisa mostrando que dois contêineres de execução de código do ChatGPT, rodando sob duas contas diferentes e sem nenhum caminho de rede entre eles, conseguiam passar dados um para o outro pela instância interna do JFrog Artifactory que lhes servia pacotes. Nada cedeu na porta da frente. A credencial de leitura que esses contêineres tinham também podia escrever, então um campo de metadados em um pacote armazenado funcionou como caixa de correio. O Bromure Agentic Coding não dá ao convidado conta alguma no espelho e permite que você escreva read-only em uma regra que o fio aplica.

O isolamento se manteve, os conectores se comportaram como documentado, e o serviço no meio havia sido instalado por segurança, para começo de conversa. O e-mail da vítima ainda assim chegou à conta de um estranho, por um campo de metadados em um pacote armazenado.

Em junho, pesquisadores da Check Point escreveram uma propriedade em um arquivo dentro de um repositório de pacotes. A propriedade se chamava chatgpt_test_ts e seu valor era um carimbo de tempo. Eles a escreveram de dentro do sandbox que executa código para uma conversa do ChatGPT. Depois abriram uma conversa sob outra conta, em seu próprio contêiner, e leram a mesma propriedade de volta. O valor chegou intacto.

Esse carimbo de tempo é a descoberta inteira. A Check Point publicou o achado em 8 de setembro sob um título que vence qualquer resumo: The Shared Clipboard Inside the Sandbox. A OpenAI já havia desativado o serviço a essa altura. Os pesquisadores reportaram no fim de junho e ouviram que a instância interna do Artifactory tinha sido descomissionada, então não há correção a aplicar e nada a fazer do lado do usuário. A forma disso permanece.

O serviço no meio

Uma conversa do ChatGPT que executa código recebe seu próprio contêiner, isolado dos contêineres de outras conversas. Essa parte funcionou. Um contêiner rodando Python também precisa de pip install, e um time de plataforma cuidadoso não vai deixar um sandbox alcançar pypi.org por conta própria. Então o sandbox ganha um intermediário controlado: uma instância interna do JFrog Artifactory que se posiciona diante dos registros públicos e serve pacotes homologados para dentro.

Isso é bom projeto. Um banco coloca a mesma coisa diante do npm, e uma empresa de saúde regulada coloca diante do PyPI. O espelho existe para reduzir a exposição do sandbox, e é o que ele faz.

Ele também dá a cada contêiner uma conta no espelho.

A API REST do Artifactory inclui um grupo Item Management, acessível em /api/storage/{repoKey}/{itemPath}, que permite a um cliente anexar propriedades nomeadas de texto arbitrárias a um item armazenado e lê-las de volta: Set Item Properties e Get Storage Item Information. Definir uma propriedade exige a permissão Annotate. Ler uma, não. A Check Point descobriu que a credencial emitida para os contêineres do sandbox, pensada como leitora, carregava as duas coisas. Como o Cybersecurity News resumiu, “as credenciais de leitura entregues aos contêineres tinham permissão suficiente para escrever e ler essas propriedades”, e “essas propriedades não eram isoladas por conta”.

Valores de propriedade aceitam texto, ou Base64 para qualquer coisa binária, e uma carga grande demais para uma única propriedade se divide em várias e se remonta do outro lado. Dois contêineres pertencentes a clientes sem relação entre si, sem nenhum caminho de rede entre eles, passam a ter um canal bidirecional com um teto de banda que não vale a pena mencionar.

duas contas, nenhum caminho entre elas, um serviço de que ambas precisamconta do atacantecontêiner de execução de códigocredencial de leitura + Annotateconta da vítimacontêiner de execução de códigocredencial de leitura + Annotateo isolamento se mantémsem rede, sem disco compartilhadoJFrog Artifactory interno — o espelho de pacotes homologados/api/storage/{repoKey}/{itemPath}um pacote armazenado, uma propriedade nomeadachatgpt_test_ts = “…” · Base64, fatiado se grandeas propriedades não são separadas por contaSet Item PropertiesGet Storage Item Info
O canal encoberto. Duas conversas do ChatGPT sob contas diferentes recebem cada uma um contêiner isolado de execução de código, sem caminho de rede entre eles. Ambos os contêineres precisam alcançar a mesma instância interna do Artifactory para instalar pacotes, e a credencial de leitura que receberam também carregava a permissão Annotate. O contêiner A escreve uma propriedade nomeada em um item armazenado; o contêiner B a lê de volta. As propriedades não eram separadas por conta, de modo que o plano de metadados do espelho de pacotes funcionou como uma caixa de correio compartilhada.

Duas conversas no mesmo turno

As instruções do atacante chegam à vítima por rotas comuns: um prompt colado, um link de conversa compartilhada, ou um GPT personalizado cujas instruções de construção o usuário não vê. A vítima então manda uma mensagem normal, e esse é o gatilho inteiro.

No modo Thinking, o modelo processou dois fluxos independentes de trabalho em um único turno. Na prova de conceito da Check Point, a vítima fazia uma pergunta de culinária e recebia uma resposta correta, enquanto ao lado dessa resposta o modelo lia a conta do Gmail conectada da vítima e escrevia o que encontrava em uma propriedade do Artifactory, para o contêiner do atacante recolher. Pedro Drimel Neto, que lidera o time de análise de malware da Check Point, disse ao The Register: “Uma instrução construída podia fazer o ChatGPT processar um segundo fluxo de tarefas ao lado da conversa visível.” O Gmail foi a demonstração. Google Drive, Microsoft Teams e GitHub estavam ao mesmo alcance.

A vítima viu um único sinal, um pequeno rótulo “Talked to Gmail”, e ele apareceu depois do fato. Os conectores vêm por padrão na configuração Important actions, que aprova leituras de baixo risco sem perguntar; a mais estrita Always ask teria produzido um aviso. Essa configuração classifica a leitura de e-mail como baixo risco sem perguntar quem a pediu.

A descrição que a Check Point faz do modelo: ele “pode, portanto, agir como um insider coagido: não malicioso, mas persuadido a agir em nome do atacante”.

A parte que se generaliza

Tire o ChatGPT da história e ela passa a ser sobre um agente de código, porque a estrutura é idêntica.

Um sandbox de agente tem de instalar pacotes. Deixá-lo alcançar os registros públicos sem mediação é justamente o que você estava evitando, então você coloca um espelho na frente: Artifactory, Nexus, um proxy npm privado, o que sua organização padronizou. O sandbox agora se autentica nesse espelho, logo tem uma credencial, e alguém decidiu o que essa credencial podia fazer muito antes de este agente existir. Registros de pacotes aceitam uploads, tags, anotações e regras de retenção, o que faz de Annotate uma permissão pequena assentada sobre uma superfície ampla.

Pergunte, então, duas coisas à sua própria configuração, em vez de perguntar se o sandbox está isolado. Nomeie em que ele tem conta. Depois nomeie quais verbos funcionam nessa conta.

Dentro de um espaço de trabalho Bromure

O Bromure Agentic Coding executa cada agente de código em uma VM Linux virtualizada por hardware no seu Mac, e mantém os segredos reais do lado do host dessa linha. Passe os três ingredientes da Check Point por um espaço de trabalho.

Um serviço compartilhado. Não existe nenhum. Cada espaço de trabalho corresponde a uma VM, com seu próprio disco de sistema, sua própria imagem de home, seu próprio IP e seu próprio listener de proxy MITM no host. Dois espaços de trabalho não compartilham VM alguma, e a descrição que o manual dá de um par deles é que eles “nunca compartilham um byte”. Nenhum espelho de frota fica por baixo dos espaços de trabalho com um plano de metadados em que os dois possam escrever. O que fica por baixo de um espaço de trabalho é um processo no seu próprio Mac, um por espaço de trabalho.

Uma credencial no espelho. O agente não tem nenhuma. As instalações de pacotes em um espaço de trabalho Bromure saem por um socket virtio até o proxy do host, e é o proxy que fala com o registro. O Bromure mantém as chaves de API dos serviços de reputação do lado do host e não as exporta para VM alguma. O caminho do Depi é o caso mais nítido: o proxy anexa a sua chave de registro como cabeçalho Authorization: Bearer no host e remove, de passagem, qualquer cabeçalho Authorization que o convidado tenha enviado. Nenhuma credencial de leitura existe no convidado, então nenhuma pode carregar um verbo a mais.

Um verbo de escrita que sobreviveu ao seu motivo. Aqui é você quem escreve a restrição. O painel Guardrails de um espaço de trabalho carrega um firewall de saída ordenado, e as regras para o protocolo web aceitam uma coluna Methods. Sob allow, os métodos formam uma lista de permissão, e read-only é atalho para GET, HEAD e OPTIONS. O manual diz por que a coluna existe: a dimensão do método “é o que permite a um espaço de trabalho ler uma API que ele não tem permissão de escrever”, no fio, independentemente de qual ferramenta dentro da VM faz a requisição. Duas camadas aplicam isso. O switch de rede virtual compara cada fluxo por IP de destino e por nome de host capturado do DNS, e o proxy compara de novo por nome de servidor TLS e por método HTTP individual, de modo que um agente comprometido não tem rota para contornar nem um nem outro. As edições alcançam sessões em execução sem reboot, e cada veredito aparece como uma linha Firewall na Security Timeline.

a decisão tomada a montantecontêiner sandboxtoken leitor + Annotateescopo definido há muitoGET + PUTespelho compartilhado — uma instância, todos os inquilinospacotes no plano de artefatos, caixas de correio no plano de metadadoso que o token pode fazer nunca foi uma pergunta por sessãoa decisão tomada no fio, por espaço de trabalhoVM do espaço de trabalhosem credencial de registrosó iscas, brm-…nenhuma outra rota para a redevsock 8443proxy do host — um por espaço de trabalho, no seu Macremover Authorization do convidado · anexar a chave realallow web registry.npmjs.org read-onlycomparado por nome de servidor TLS e método HTTP, a cada requisição
O mesmo requisito, dois lugares para a decisão. Acima: o sandbox se autentica em um espelho compartilhado, e o que ele pode fazer ali foi decidido a montante, uma vez, em uma concessão de permissão que sobreviveu à pessoa que a fez. Abaixo: o convidado não tem credencial de registro nem rota para a rede além de um socket virtio até um proxy de host por espaço de trabalho, onde a chave é anexada, o cabeçalho Authorization do próprio convidado é removido, e uma regra ordenada decide quais métodos HTTP têm permissão de chegar ao host.

O segundo fluxo, e o caminho de volta para fora

O segundo fluxo de tarefas do atacante chegou como conteúdo que o modelo leu. Em um espaço de trabalho Bromure, tudo o que um agente ingere e devolve em fluxo ao modelo (conteúdo de arquivos, páginas web, saída de comandos, qualquer coisa que uma ferramenta retorne) viaja como spans tool_result pelo mesmo proxy do host. O detector de código-fonte pontua esses spans com um classificador PromptGuard local antes de o modelo agir sobre eles, e então registra o acerto, pausa para a sua decisão, ou bloqueia a requisição. O detector vem desligado e baixa um modelo de 298 MB na primeira vez que você o habilita, então habilite-o antes da sessão em que vai precisar dele.

A leitura de conector não aprovada tem aqui o seu inverso. Os tokens bearer de MCP de um espaço de trabalho Bromure aparecem dentro da VM como marcadores brm-mcp_. O token real fica fora do convidado, e o proxy o substitui no fio em direção ao único host para o qual aquele token foi emitido. Ligue Ask before use para uma credencial e o primeiro uso dela em uma sessão pausa para um diálogo do lado do host oferecendo uma concessão de 5 minutos, de 1 hora ou pelo resto da sessão. É o aviso que “Important actions” se recusou a mostrar, por credencial, na máquina em que você está sentado.

Se algo na VM levar um marcador para onde ele não pertence, o proxy recusa a requisição sem encaminhar um byte, pausa a VM e levanta um alerta nomeando a prévia do token, a credencial, o host para o qual ele foi emitido e o host para o qual estava indo. Sob esse fio de armadilha, o tracing em Activity only escreve uma linha de metadados por requisição: host, método, caminho, status, bytes, quais credenciais o proxy trocou, e um aviso de vazamento para qualquer token no estilo bearer que o Bromure não tenha emitido. Rode bromure-cli trace hostnames depois de uma sessão e cada host distinto que o agente contatou é impresso com uma contagem.

Se você opera um espelho para seus agentes

Verifique a identidade com que seus sandboxes se autenticam, antes do caminho de rede entre eles. No Artifactory, procure Annotate em um token que você considera leitor, e um alvo de permissão mais amplo que os repositórios de que o sandbox instala. A API de propriedades é um plano de metadados gravável; as regras de retenção, as tags e as informações de build são outros. Um leitor que pode anotar pode postar.

A regra que responde isso em uma linha

No painel Guardrails do espaço de trabalho, adicione uma regra de saída para o registro com o protocolo web e read-only na coluna Methods, depois ponha Unmatched traffic em Deny e liste o que o trabalho precisa. A exibição em formato pf no rodapé do painel imprime o que você construiu: allow web registry.npmjs.org read-only, allow web api.github.com, default deny. Vale para sessões em execução sem reiniciar.

Um serviço compartilhado transforma inquilinos em vizinhos

O instinto depois de uma história como esta é conferir as paredes. As paredes estavam bem. Dois contêineres sob duas contas não tinham rota um para o outro, e a Check Point não encontrou nenhuma. Encontraram um terceiro com quem os dois contêineres tinham direito de falar, e o usaram do jeito que as pessoas usam discos compartilhados e registros DNS TXT há trinta anos.

A Check Point enuncia a lição no relatório: “um serviço interno compartilhado, pensado puramente como infraestrutura, pode se tornar uma camada de comunicação não intencional entre ambientes que deveriam permanecer isolados”. A infraestrutura que você instala por segurança continua sendo infraestrutura, e seus inquilinos ficam a um salto de distância. Encolha o conjunto de coisas em que um sandbox tem conta, e mova a decisão sobre o que essas contas podem fazer para cada requisição, tirando-a de um ticket de provisionamento que alguém fechou dois anos atrás.

Um sandbox de agente que valha a pena rodar terá um caminho controlado até os pacotes de que precisa, porque a alternativa é pior. Trate esse caminho como uma relação com permissões anexadas, e trate essas permissões como o seu perímetro. Decida-as em algum lugar onde você ainda consiga vê-las. Instale o Bromure Agentic Coding e não dê ao seu agente nada com que fazer login.