API-key gelekt of onverwacht hoge rekening: dit doe je nu

Trek de key vandaag nog in en maak een nieuwe, ook als je niet zeker weet of hij misbruikt is. Zet daarna een uitgavenlimiet, haal de key uit je code en je git-geschiedenis, en vraag de provider om naar de rekening te kijken. Een gelekte key blijft geldig tot jij hem intrekt, dus de volgorde doet ertoe.

Damian Madronal Munoz, oprichter

6 min leestijd

Een gelekte API-key is geen ramp als je snel bent. Het geld dat al weg is, krijg je misschien niet terug. Het geld dat er morgen bij komt wel: dat houd je tegen door de key in te trekken. Hieronder eerst hoe je het merkt, dan waarom het gebeurt, dan de stappen.

Herken je dit?

  • Een rekening van OpenAI of Anthropic die tien keer hoger is dan normaal, terwijl je app niet drukker werd.
  • Een mail van GitHub dat er een secret in je repository staat, of een mail van de provider dat je key is uitgeschakeld.
  • In het verbruiksoverzicht staan aanroepen naar modellen die jouw app niet gebruikt, of verkeer midden in de nacht.
  • In Stripe staan klanten, refunds of betalingen die niemand van jullie heeft gemaakt.
  • Je opent de broncode van je eigen site in de browser en ziet daar een regel die begint met sk-.

Eén van die vijf is genoeg om de stappen hieronder te doorlopen.

Hoe een key uitlekt

Bijna altijd op een van drie manieren. De eerste: de key staat in de frontend. Een AI-builder die een chatfunctie of betaling inbouwt, zet de aanroep naar OpenAI of Stripe vaak rechtstreeks in de browsercode, omdat dat in de preview meteen werkt. Alles wat de browser krijgt, kan iedere bezoeker lezen.

De tweede: de key staat in een omgevingsvariabele die naar de browser gaat. In Vite gaat alles met VITE_ ervoor mee in de build, in Next.js alles met NEXT_PUBLIC_. Een key in VITE_OPENAI_API_KEY is dus geen geheim, ook al staat hij in een .env-bestand.

De derde: de key staat in de git-geschiedenis. Iemand zette hem ooit in een bestand, haalde hem er later weer uit, en pushte naar een openbare repository. De laatste versie is schoon, de commit van drie weken geleden niet. Bots scannen openbare repositories continu op die patronen, en een key is soms binnen minuten na de push in gebruik.

Zo los je het op, in vijf stappen

1. Trek de key in en maak een nieuwe

Dit eerst, vóór je gaat zoeken hoe het kwam. Elke provider heeft er een pagina voor:

  • OpenAI: in het dashboard onder API keys de key verwijderen en een nieuwe maken, bij voorkeur per project.
  • Anthropic: in de Console onder API keys de key uitschakelen en een nieuwe maken.
  • Stripe: in het Dashboard onder Developers › API keys de secret key laten roteren. Stripe kan de oude een tijdje laten doorwerken; kies hier voor direct.
  • Supabase: een uitgelekte service_role-key of secret key vervangen in de API-instellingen van je project. Gebruik je nog de oude JWT-keys, dan betekent vervangen dat je het JWT-secret vernieuwt, en dan worden ook alle ingelogde gebruikers uitgelogd. Doe het toch.

Zet de nieuwe key alleen op de server: in de omgevingsvariabelen van je hosting, zonder VITE_- of NEXT_PUBLIC_-voorvoegsel.

2. Zet een limiet op wat de key kan kosten

Bij OpenAI en Anthropic stel je per project of werkruimte een budget en een melding in. Zet dat budget op wat je app in een normale maand verbruikt, met wat ruimte. Een limiet voorkomt niet dat een key uitlekt, wel dat een uitgelekte key je een maand huur kost.

Bij Stripe werkt het anders: daar beperk je wat een key mag. Een restricted key die alleen betalingen mag aanmaken, kan geen klanten opvragen en geen refunds doen.

3. Zoek waar de key nog meer staat

Zoek in je eigen code en in de build die online staat. Een key van OpenAI begint met sk-, van Anthropic met sk-ant-, een live secret key van Stripe met sk_live_.

grep -rn "sk-\|sk_live_\|service_role" src/ dist/
Zoeken in de code en in de map met de build (dist, build of .next).

Zoek daarna in de hele geschiedenis van je repository, niet alleen in de laatste versie. Gitleaks is een gratis scanner die precies dat doet.

gitleaks git --verbose .
Doorzoekt elke commit, ook de commits waarin de key alweer verwijderd was.

4. Haal de key uit de git-geschiedenis

Met git filter-repo vervang je de key in elke commit door een vaste tekst. Daarna moet je force-pushen, en moet iedereen die de repository heeft opnieuw clonen.

# vervangen.txt
sk-proj-oude-key-hier==>VERWIJDERD

git filter-repo --replace-text vervangen.txt
git push --force --all
In vervangen.txt staat één regel: de oude key, ==>, en de tekst die ervoor in de plaats komt.

Weet wat dit wel en niet doet. Het haalt de key uit je repository, maar niet uit de forks en clones die al bestaan. Daarom is stap 1 de echte oplossing en is deze stap opruimen.

5. Vraag de provider om naar de rekening te kijken

Schrijf de support van OpenAI, Anthropic of Stripe aan met wat je weet: sinds wanneer de key openstond, wanneer je hem introk, en welk verbruik niet van jou is. Voeg het verbruiksoverzicht toe. Of je iets terugkrijgt, beslist de provider. Een duidelijke tijdlijn en een key die al is ingetrokken helpen.

Waar het daarna nog misgaat

  1. De nieuwe key komt op dezelfde plek. De oude is ingetrokken, de nieuwe staat weer in VITE_OPENAI_API_KEY. Binnen een week begint het opnieuw. De aanroep naar de AI-provider moet via je eigen server of een serverless functie lopen.
  2. Alleen de laatste commit opschonen. De key staat er niet meer in, maar wel in de geschiedenis. Zolang de key niet is ingetrokken, is hij nog steeds bruikbaar.
  3. De service_role-key als oplossing. Een app die “toegang geweigerd” geeft, krijgt de service_role-key in de frontend en werkt dan wel. Dat is geen oplossing: daarmee vervalt elke regel in je database. Lees eerst hoe Row Level Security werkt.
  4. Eén key voor alles. Dezelfde key in de preview, op je laptop en in productie betekent dat je bij een lek alles tegelijk moet vervangen. Een key per omgeving maakt de schade kleiner.

Wanneer je hulp nodig hebt

Weet je niet waar de key nog meer gebruikt wordt, staat de aanroep naar de AI-provider in de frontend en weet je niet hoe je hem naar een server verplaatst, of zit er klantdata achter de key? Dan is dit meer dan een key vervangen. Een gelekte database-key kan een datalek zijn dat je binnen 72 uur bij de Autoriteit Persoonsgegevens moet melden.

In onze securitycheck zoeken we uit waar je keys staan, wat ze kunnen, en wat er in je database openstaat. De andere problemen die we in AI-apps vaak zien, staan in je website is met AI gebouwd: dit gaat er waarschijnlijk mis, en alles over AI-apps staat bij apps afmaken en beveiligen.

Veelgestelde vragen⁠

Is de anon-key of publishable key van Supabase ook een lek?

Nee. Die is bedoeld voor de browser en mag in je frontend staan, zolang Row Level Security op elke tabel aanstaat. De service_role-key en een secret key zijn wel geheim: die negeren alle regels.

Ik heb de key uit mijn code gehaald. Is het dan opgelost?

Nee. Een key die ooit in een gepubliceerde build of een openbare repository stond, moet je als bekend beschouwen. Pas als je hem bij de provider intrekt, werkt hij niet meer.

Krijg ik mijn geld terug?

Dat beslist de provider, per geval. Vraag het wel, met de tijdlijn erbij: wanneer de key uitlekte, wanneer je hem introk en welk verbruik niet van jou is. Reken er niet op als je niets aan limieten had ingesteld.

Hoe voorkom ik dat het opnieuw gebeurt?

Roep de API van OpenAI, Anthropic of Stripe aan vanaf een server, nooit vanuit de browser. Zet een limiet op elke key, gebruik per omgeving een eigen key, en laat een scanner meekijken bij elke commit.

Verder lezen⁠

Een app die je met Lovable, Bolt, v0, Cursor of Claude bouwde: dichtzetten, afmaken en online houden.

Wij zoeken uit waar de key nog meer staat⁠

De kennismaking is gratis. We reageren binnen één werkdag.