Das Erste, was kaputt ging, als ich GeminiOmni veröffentlichte

Apr. 29, 2026

Ich habe die erste öffentliche Version von GeminiOmni an einem Mittwochnachmittag veröffentlicht. Es war eine abgespeckte Landingpage mit einem einzigen funktionierenden Tool – einer frühen Version des Nano Banana 2-Bildeditors – und einem Button mit der Aufschrift „Kostenlos testen, ohne Anmeldung."

Die Seite ging um 14:42 Uhr Berliner Zeit online. Um 15:05 Uhr schrie mein Google Cloud-Abrechnungsdashboard.

Dieser Beitrag ist die vollständige Aufschlüsselung dessen, was schiefgelaufen ist, was es gekostet hat und was ich noch vor Ende desselben Arbeitstages geändert habe. Wenn du etwas entwickelst, das eine kostenpflichtige KI-API berührt, betrachte dies als kostenlose Lektion – die meisten Leute schreiben nicht über die peinlichen Teile.

Der tatsächliche Ablauf

Hier ist der Zeitplan aus meinem eigenen Vorfallsprotokoll (ja, ich führe eines – kann ich nur empfehlen):

  • 14:42 Deployment erfolgreich. Seite live unter geminiomni-ai.com. Habe eine kurze Demo auf einer kleinen Mastodon-Instanz gepostet und bin einen Kaffee holen gegangen.
  • 14:58 Zurückgekommen und eine Slack-Benachrichtigung von Google Cloud gesehen: „Ihre Rechnung hat $5 für den aktuellen Zyklus überschritten." Das war alarmierend, da der Zyklus seit 16 Minuten lief.
  • 15:05 In der Gemini-API-Konsole eingeloggt. 412 Bildgenerierungsanfragen in den letzten 20 Minuten gesehen, von 38 verschiedenen IPs aus drei Kontinenten.
  • 15:08 Seite offline genommen. API-Schlüssel deaktiviert. Einen neuen generiert, den ich noch nicht verwenden würde.
  • 15:42 Mit dem Umschreiben der Architektur begonnen.
  • 18:30 V2 mit dem Fix ausgerollt. Seite wieder online gebracht.
  • 23:00 Gesamtrechnung für das vierstündige Missgeschick: 84,30 $.

Zur Einordnung: Ich hatte für den gesamten ersten Monat 200 $ für API-Kosten budgetiert. Ich habe 42 % davon in siebzehn Minuten verbrannt, wegen eines Fehlers, den ich hätte besser wissen müssen.

Was ich getan hatte

Die erste Version des Bildeditors war wie folgt verdrahtet: eine Next.js-Seite mit einer React-Komponente, die die Eingabeaufforderung des Benutzers und das hochgeladene Bild entgegennahm, dann direkt aus dem Browser die Google Gemini Image API mit dem @google/genai-Client und einem API-Schlüssel aufrief, der in NEXT_PUBLIC_GEMINI_API_KEY eingebettet war.

Ja. Ich habe einen kostenpflichtigen API-Schlüssel in NEXT_PUBLIC_* gesetzt. Den Next.js brav in das Client-JavaScript einbaut. Das jeder sehen kann, der die DevTools öffnet.

Zu meiner Verteidigung – und diese Verteidigung ist nicht sehr gut – der ursprüngliche Prototyp war ein privates Localhost-Experiment. Ich hatte den Schlüssel als clientseitige Umgebungsvariable eingebunden, weil ich schnell iterierte und mir die Mühe sparen wollte, eine API-Route einzurichten. Als ich das öffentliche Deployment vorbereitete, habe ich ungefähr vierzig Dinge geändert und die Position des Schlüssels war nicht dabei.

Der Fehler war nicht einzigartig für mich. Ein halbes Dutzend Leute, die ich respektiere, haben 2024-2025 Variationen davon gemacht. Es ist der häufigste vermeidbare KI-Kosten-Vorfall, den ich gesehen habe.

Wie er so schnell ausgelesen wurde

Das Detail, das mich überraschte, war, wie schnell die Anfragen eintrafen. Ich hatte auf einer Mastodon-Instanz mit vielleicht 600 Followern gepostet, von denen niemand dies böswillig getan hätte. Der Traffic musste von woanders herkommen.

Hier ist, was ich aus den Anfragenprotokollen herausgefunden habe:

  1. Innerhalb von fünf Minuten nach dem Livegang traf ein automatisierter Crawler auf die Seite, extrahierte den gebündelten NEXT_PUBLIC_GEMINI_API_KEY aus dem JavaScript und veröffentlichte ihn auf einem Schlüsselhandels-Kanal, von dem ich nicht wusste, dass er existiert.
  2. Innerhalb von zehn Minuten wurde dieser Schlüssel von ungefähr 38 verschiedenen IPs verwendet, um Bilder zu generieren, die nichts mit meinem Produkt zu tun hatten. Die meisten der Eingabeaufforderungen, die ich in den Protokollen durchgesehen habe, waren generisch („ein rotes Sportauto", „Anime-Mädchen im Wald"). Einige testeten die Grenzen des Modells mit adversarialen Eingabeaufforderungen.
  3. Nach Minute 15 führte jemand eine enge Schleife aus, die Bilder so schnell generierte, wie Google es zuließ.

Das ist der Teil, den ich unabhängigen Entwicklern verständlich machen möchte: Es gibt Crawler, deren einzige Aufgabe es ist, neue Websites nach API-Schlüsseln zu durchsuchen. Sie überwachen die Ausstellung neuer SSL-Zertifikate, besuchen neue Domains, parsen die JavaScript-Bündel und veröffentlichen entdeckte Schlüssel innerhalb von Minuten. Du musst nicht berühmt sein. Du musst nicht in einem beliebten Subreddit sein. Du musst nur online sein mit einem durchgesickerten Schlüssel.

Die Architektur, die ich an diesem Nachmittag ausgerollt habe

Der Fix war strukturell, nicht kosmetisch. Ich habe den Datenfluss neu geschrieben, sodass nie ein API-Schlüssel an den Browser gesendet wird, und die Architektur ist jetzt das, was wir heute verwenden:

Browser (niemals Schlüssel)
   ↓ POST /api/ai/generate { prompt, imageFile }
Next.js-API-Route (serverseitig)
   ↓ envConfigs.gemini_api_key (bleibt auf dem Server)
Google Gemini API

Drei konkrete Änderungen:

1. Den API-Schlüssel in eine reine Server-Umgebungsvariable verschieben. NEXT_PUBLIC_GEMINI_API_KEY in GEMINI_API_KEY umbenannt. Next.js weigert sich standardmäßig, reine Server-Umgebungsvariablen an den Client auszuliefern. Doppelt gemoppelt: Ich habe eine Startprüfung hinzugefügt, die die App abstürzen lässt, wenn ein Umgebungsvariablenname, der „API_KEY" oder „SECRET" enthält, mit NEXT_PUBLIC_ beginnt.

2. Einen /api/ai/*-Proxy erstellen. Jeder Modellaufruf erfolgt über einen einzigen serverseitigen Endpunkt. Der Browser sendet die Eingabeaufforderung und alle vom Benutzer hochgeladenen Dateien; der Server fügt den API-Schlüssel hinzu, führt den eigentlichen Gemini-API-Aufruf durch und gibt nur das Ergebnis zurück. Das klingt offensichtlich, ist aber der gesamte Fix.

3. Ein Pro-IP-Ratenlimit auf dem Proxy hinzufügen. Selbst wenn der Schlüssel sicher ist, wollte ich nicht, dass ein Benutzer die Free-Tier-Generierungen spammt, um Guthaben zu verbrauchen. Der Proxy erzwingt 10 Anfragen pro IP pro Minute auf dem Free-Tier und 60 pro Minute auf Pro+. Das hätte den ursprünglichen Vorfall nicht verhindert – die Angreifer rotierten IPs – aber es macht die nächste Klasse von Missbrauch viel schwieriger.

Die gesamte Codeänderung betrug etwa 180 hinzugefügte und 90 entfernte Zeilen. Es hat 2 Stunden und 48 Minuten gedauert, von „Seite offline" bis „Seite wieder live mit neuer Architektur." Nicht großartig, aber nicht katastrophal.

Was ich beim nächsten Mal anders machen würde

Die ehrliche Antwort ist: Veröffentliche niemals eine öffentliche KI-App mit einem clientseitigen API-Aufruf an einen kostenpflichtigen Dienst. Nicht für „nur einen Prototypen." Nicht für „MVP-Tests." Nicht für „eine schnelle Demo für Freunde." Das Bedrohungsmodell sind nicht böswillige Benutzer. Es ist die automatisierte Infrastruktur, die bereits für genau dieses Szenario existiert.

Ein paar weitere Lektionen, die aus dem Vorfall hervorgegangen sind:

Überprüfe das Bundle vor dem Deployment. Führe vor dem Veröffentlichen grep -r "NEXT_PUBLIC_" .next/static/ aus und lies, was darin steht. Wenn etwas wie eine Anmeldeinformation aussieht, behebe es, bevor du live gehst. Ich habe dies jetzt als Pre-Deploy-Git-Hook.

Setze ein hartes tägliches Limit. Google Cloud ermöglicht es dir, deine Gemini-API auf einen täglichen Dollarbetrag zu begrenzen. Ich habe es für den ersten Monat auf 50 $ und danach auf 200 $ gesetzt. Wenn das Limit erreicht ist, gibt die API Fehler zurück und ich bekomme eine E-Mail – viel besser, als es in einer einzigen schlimmen Nacht auf 5.000 $ laufen zu lassen.

Verwende das günstigste Modell, das funktioniert. Ich habe 0,151 $ pro Nano Banana 2 4K-Bearbeitung auf einer Free-Tier-Oberfläche verbrannt. Selbst vor dem Angriff waren meine Stückkosten fragil. Ich leite Free-Tier-Generierungen jetzt durch Nano Banana 2K zu 0,045 $ pro Bearbeitung und behalte 4K für Pro+. Die Kostenreduktion um den Faktor 3,4 hätte die Rechnung von 84 $ auf etwa 25 $ gedrückt.

Begrenze die Länge der Eingabeaufforderung. Einer der Missbraucher schickte riesige Eingabeaufforderungen mit eingebetteten Bilddaten, was Gemini pro Token abrechnet. Der Proxy begrenzt jetzt die eingehende Größe von Eingabeaufforderungen hart auf 50KB. Ein legitimer Benutzer ist noch nie dagegen gestoßen; ein Missbraucher trifft es mit der ersten Anfrage.

Die Belege

Für jeden, der überprüfen möchte, dass ich mir das nicht ausdenke: Meine Gemini-API-Konsole vom 28. April zeigt 411 Anfragen von 14:42 bis 15:08, wobei der Ausgabenbericht 83,96 $ für Bildgenerierungsgebühren und 0,34 $ für Eingabe-Token zeigt. Ich habe an diesem Abend den Google Cloud-Support kontaktiert, und sie lehnten eine Rückerstattung ab – fair genug, der Schlüssel war legitimerweise meiner und ich hatte seine Verwendung autorisiert. Sie schlugen genau die Architektur vor, die ich bereits ausgerollt hatte.

Die wichtigste Erkenntnis, groß genug geschrieben, dass ich sie von der anderen Seite des Raumes lesen kann:

KI-API-Schlüssel sind Inhaber-Anmeldeinformationen. Sie gehören auf den Server. Sie gehören nirgendwo anders hin.

Wenn du eine Sache aus diesem Beitrag mitnimmst, dann diese.

Weiterlesen

— Lena

Lena Hoffmann

Lena Hoffmann

Das Erste, was kaputt ging, als ich GeminiOmni veröffentlichte | Blog