A primeira coisa que quebrou quando lancei o GeminiOmni

abr 29, 2026

Lancei a primeira versão pública do GeminiOmni numa quarta-feira à tarde. Era uma página inicial enxuta com uma única ferramenta funcional — uma versão inicial do editor de imagens Nano Banana 2 — e um botão que dizia "Experimente grátis, sem cadastro."

O site foi ao ar às 14:42, horário de Berlim. Às 15:05, meu painel de faturamento do Google Cloud estava gritando.

Este post é a análise completa do que deu errado, quanto custou e o que mudei antes do fim do mesmo dia útil. Se você está construindo algo que toca uma API de IA paga, trate isso como uma lição gratuita — a maioria das pessoas não escreve sobre as partes constrangedoras.

A sequência real

Aqui está a linha do tempo do meu próprio registro de incidentes (sim, eu mantenho um — recomendo):

  • 14:42 Deploy bem-sucedido. Site no ar em geminiomni-ai.com. Postei uma demo rápida em uma pequena instância do Mastodon e fui fazer um café.
  • 14:58 Voltei e vi uma notificação do Slack do Google Cloud: "Sua fatura excedeu $5 no ciclo atual." Isso foi alarmante porque o ciclo estava ativo há apenas dezesseis minutos.
  • 15:05 Entrei no console da API Gemini. Vi 412 requisições de geração de imagem nos últimos 20 minutos, de 38 IPs distintos em três continentes.
  • 15:08 Tirei o site do ar. Invalidei a chave da API. Gerei uma nova que não usaria ainda.
  • 15:42 Comecei a reescrever a arquitetura.
  • 18:30 Lancei a v2 com a correção. Coloquei o site de volta no ar.
  • 23:00 Fatura total pelas quatro horas de desventura: $84,30.

Para contexto, eu havia orçado $200 para o primeiro mês inteiro de gastos com API. Queimei 42% disso em dezessete minutos por causa de um erro que eu deveria saber que não deveria cometer.

O que eu tinha feito

A primeira versão do editor de imagens estava conectada assim: uma página Next.js com um componente React que recebia o prompt do usuário e a imagem enviada, depois chamava a API Google Gemini Image diretamente do navegador usando o cliente @google/genai e uma chave de API embutida em NEXT_PUBLIC_GEMINI_API_KEY.

Sim. Coloquei uma chave de API paga em NEXT_PUBLIC_*. Que o Next.js obedientemente empacota no JavaScript do cliente. Que fica visível para qualquer um que abra o DevTools.

Em minha defesa — e esta defesa não é muito boa — o protótipo original era um experimento privado de localhost. Eu havia conectado a chave como uma variável de ambiente do lado do cliente porque estava iterando rápido e não queria me preocupar em configurar uma rota de API. Quando preparei o deploy público, mudei aproximadamente quarenta coisas e a localização da chave não foi uma delas.

O erro não foi exclusivo meu. Meia dúzia de pessoas que respeito fizeram variações disso em 2024-2025. É o incidente de custo de IA evitável mais comum que já vi.

Como foi raspado tão rápido

O detalhe que me surpreendeu foi a rapidez com que as requisições começaram a chegar. Eu havia postado em uma instância do Mastodon com talvez 600 seguidores, nenhum dos quais teria feito isso maliciosamente. O tráfego tinha que vir de outro lugar.

Aqui está o que descobri a partir dos logs de requisição:

  1. Em menos de cinco minutos de site no ar, um crawler automatizado acessou o site, extraiu a NEXT_PUBLIC_GEMINI_API_KEY empacotada do JavaScript e a publicou em um canal de negociação de chaves que eu nem sabia que existia.
  2. Em menos de dez minutos, essa chave estava sendo usada por aproximadamente 38 IPs diferentes para gerar imagens que não tinham nada a ver com meu produto. A maioria dos prompts que amostrei nos logs era genérica ("um carro esportivo vermelho", "garota anime em uma floresta"). Alguns estavam testando os limites do modelo com prompts adversariais.
  3. No minuto quinze, alguém estava executando um loop apertado gerando imagens o mais rápido que o Google permitia.

Esta é a parte que quero que os construtores independentes entendam: existem crawlers cujo trabalho inteiro é raspar novos sites em busca de chaves de API. Eles monitoram a emissão recente de certificados SSL, acessam novos domínios, analisam os pacotes JavaScript e publicam as chaves descobertas em minutos. Você não precisa ser famoso. Não precisa estar em um subreddit popular. Basta estar online com uma chave vazada.

A arquitetura que enviei naquela tarde

A correção foi estrutural, não cosmética. Reescrevi o fluxo de dados para que nenhuma chave de API seja enviada ao navegador, e a arquitetura é agora a que usamos hoje:

Navegador (sem chaves, nunca)
   ↓ POST /api/ai/generate { prompt, imageFile }
Rota da API Next.js (lado do servidor)
   ↓ envConfigs.gemini_api_key (mantida no servidor)
API Google Gemini

Três mudanças concretas:

1. Mover a chave da API para uma variável de ambiente apenas do servidor. Renomeei NEXT_PUBLIC_GEMINI_API_KEY para GEMINI_API_KEY. O Next.js se recusará a enviar variáveis de ambiente apenas do servidor para o cliente por padrão. Cinto e suspensórios: adicionei uma verificação de inicialização que trava o aplicativo se qualquer nome de variável de ambiente contendo "API_KEY" ou "SECRET" começar com NEXT_PUBLIC_.

2. Criar um proxy /api/ai/*. Toda chamada de modelo passa por um único endpoint do lado do servidor. O navegador envia o prompt e quaisquer arquivos enviados pelo usuário; o servidor anexa a chave da API, faz a chamada real à API Gemini e retorna apenas o resultado. Isso parece óbvio, mas é a correção completa.

3. Adicionar um limite de taxa por IP no proxy. Mesmo com a chave segura, eu não queria que um usuário spammeasse gerações do nível Gratuito para drenar créditos. O proxy impõe 10 requisições por IP por minuto no nível gratuito e 60 por minuto no Pro+. Isso não teria impedido o incidente original — os atacantes estavam rotacionando IPs — mas torna a próxima classe de abuso muito mais difícil.

A mudança total de código foi de cerca de 180 linhas adicionadas e 90 removidas. Levei 2 horas e 48 minutos de "site offline" para "site no ar novamente com nova arquitetura". Não é ótimo, mas não é catastrófico.

O que eu faria diferente da próxima vez

A resposta honesta é: nunca lance um aplicativo de IA público com uma chamada de API do lado do cliente para um serviço pago. Nem para "apenas um protótipo." Nem para "teste de MVP." Nem para "uma demo rápida para amigos." O modelo de ameaça não são usuários maliciosos. É uma infraestrutura automatizada que já existe exatamente para este cenário.

Mais algumas lições que surgiram do incidente:

Verifique o bundle antes de enviar. Antes de lançar, execute grep -r "NEXT_PUBLIC_" .next/static/ e leia o que está lá. Se algo parecer uma credencial, corrija antes de ir ao ar. Agora tenho isso como um hook de pré-deploy no git.

Defina um limite diário rígido. O Google Cloud permite limitar sua API Gemini a um valor diário em dólares. Eu defini para $50 no primeiro mês e $200 depois. Se o limite for atingido, a API retorna erros e recebo um e-mail — muito melhor do que deixar chegar a $5.000 em uma única noite ruim.

Use o modelo de menor custo que atenda. Eu estava queimando $0,151 por edição 4K do Nano Banana 2 em uma superfície do nível Gratuito. Mesmo antes do ataque, minha economia unitária era frágil. Agora roteio gerações do nível Gratuito através do Nano Banana 2K a $0,045 por edição e mantenho o 4K para Pro+. A redução de custo de 3,4x teria transformado a conta de $84 em cerca de $25.

Limite o tamanho do prompt. Um dos abusadores estava enviando prompts enormes com dados de imagem embutidos, que o Gemini fatura por token. O proxy agora limita rigidamente o tamanho do prompt de entrada a 50KB. Um usuário legítimo nunca esbarrou nisso; um abusador atinge no primeiro pedido.

Os comprovantes

Para quem quiser verificar que não estou inventando: meu console da API Gemini para 28 de abril mostra 411 requisições das 14:42 às 15:08, com o relatório de gastos mostrando $83,96 em cobranças de geração de imagem e $0,34 em tokens de entrada. Enviei um e-mail para o suporte do Google Cloud naquela noite e eles se recusaram a reembolsar — justo, a chave era legitimamente minha e eu havia autorizado seu uso. Eles sugeriram exatamente a arquitetura que eu já havia enviado.

A principal lição, escrita grande o suficiente para que eu possa ler do outro lado da sala:

Chaves de API de IA são credenciais de portador. Elas vão para o servidor. Nunca vão para nenhum outro lugar.

Se você levar uma coisa deste post, que seja esta.

Leia a seguir

— Lena

Lena Hoffmann

Lena Hoffmann