1.In the next hour: stop the spending
Do these four steps first. They take minutes, and the spend limit protects you whatever the cause turns out to be.
- Turn off the key. At OpenAI, the safety guide says to revoke a compromised key promptly and replace it with a new one; your security settings show all your API keys and let you revoke them. At Anthropic, open the API keys page in the Claude Console: Disable can be undone later, Delete is permanent (Anthropic’s authentication docs). Not sure which key leaked? Turn off every key you cannot account for.
- Make a new key and keep it on the server. Anthropic’s help page on compromised keys says to create the replacement with Create key, store it in a secrets manager and keep it out of version control (the saved history of your code, such as a GitHub repository). Put the new key only in your backend’s secret settings, never in the code of your app’s pages.
- Set a spend limit. At OpenAI, open the Limits page, choose Edit spend limit in the Spend section, enter a monthly amount, turn on Enforce a hard limit and select Save. A spend alert alone only sends a notice, and traffic continues. OpenAI also says enforcement is not instant, so recorded spend can go slightly over the limit (OpenAI spend limits). At Anthropic, open the Billing page and click Set limit or Adjust limit in the Spend limits section. When usage reaches your limit, the API refuses requests until access resumes or you raise the limit (Anthropic rate limits).
- Find when it started. Open OpenAI’s usage dashboard, or Anthropic’s Usage page and Logs page, which Anthropic’s key safety page tells you to review regularly. Write down the day and hour the spending jumped, and compare it with the last time you published your app or changed its AI feature. That date often points to the cause.
If the spending continues after you turn off the key, the old key is probably not the only cause. Another key may still be active, or your own app may be making the calls through an open AI helper, which now uses your new key. Keep the spend limit on until you find it. Anthropic’s help page says to contact its Support team if suspicious activity continues.
2.Find the cause: how the bill grows
In apps built with AI tools, the bill usually grows in one of two ways. You can check both on your own app.
The secret key is in the browser code
Your app’s pages run in each visitor’s browser, so every visitor downloads that code and can read it. OpenAI’s API reference says never to expose your key in client-side code such as browsers or apps, and to load it on the server. Anthropic’s TypeScript SDK (its code library) blocks browser use by default for the same reason: anyone with access to the browser could inspect, extract and misuse the key.
A common way in: many apps are built with Vite, a build tool (look for a vite.config file in your project). Vite puts every setting whose name starts with VITE_ into the browser code, and Vite’s docs say these settings should not hold API keys.
To check your own app, open it in your browser, open the developer tools, and search all loaded files for the first characters of your key. Anthropic keys start with sk-ant-api (Anthropic’s authentication docs). If your code is in a public GitHub repository, GitHub tells Anthropic when it finds a Claude key there, and Anthropic deactivates the key and emails you (Anthropic’s key safety page).
Your AI helper answers anyone
Many apps keep the key on the server, in a server function or an edge function: a small piece of code that runs on the server and calls the AI for the page. But if the function answers every request, with no sign-in and no limit, a bot can call it thousands of times, and your key pays for every call. A new key does not help here, because the function uses the new key too.
Here is a real example. LidTight’s deep check on Tidybook, our demo app built with Lovable, on 31 October 2026, called the AI helper as a stranger, without signing in: “5 calls to the AI server function in 3 s, all answered, none refused.” The same run found no secret keys in the code: “Looking for secret keys: none found.” So no key was in the browser code, and a stranger could still run up the AI bill. Five calls is a short test: it shows only that nothing stopped a stranger at that pace.
To check your own app, sign out, open the app in a private window and use the AI feature. If it answers, anyone can use it. Then ask your AI tool where the function checks the user and where it counts calls. If it cannot point to both, your AI helper probably has no limit.
3.Fix it for good
- Keep keys only on the server. OpenAI’s API reference says to load keys from an environment variable or a key management service on the server. If your backend is Supabase, add the key on the Edge Function Secrets page and read it in the function with Deno.env.get (Supabase docs). Remove the key from every VITE_ setting and from the page code, then publish again.
- Require sign-in for the AI helper. The function must check on the server that a signed-in user sent the request, and refuse everyone else. OpenAI’s safety guide says users should generally need to register and log in to use your service. Sign-in helps only if bots cannot create endless accounts: Tidybook also let anyone sign up without confirming an email (what that means).
- Limit each user per hour. Count AI calls per user in your database, and refuse calls above a number that fits real use. OpenAI’s rate limits guide recommends a usage limit for individual users over a set time, and a hard cap or a manual review for users who go over it. An hourly limit stops a bot within the hour, not at the end of the month. Also cap the length of the user’s text and of the answer: OpenAI’s safety guide says limiting output tokens (the length of the answer) reduces the chance of misuse.
- Keep a monthly budget at the provider. Leave the hard spend limit on, a little above your normal month. At OpenAI, add a spend alert too: it stays active with a hard limit, so you get a warning before traffic stops (OpenAI spend limits). Use separate keys for testing and for the live app, as Anthropic recommends, so you can turn off one without breaking the other. Give each new key an expiration date: OpenAI strongly recommends it, and Anthropic says it limits how long a leaked key works.
If you build with Lovable, its own Deep scan looks for leaked secrets and for functions that anyone can trigger, and its docs say to keep API keys in Secrets and call the AI from server-side code (Lovable security overview). If you build with an AI tool, you can paste this request. Read the changes before you publish.
My app calls an AI model. Make these changes and show me each one in the code:
1. Remove every AI key from browser code and from any VITE_ setting.
Store it as a server secret, read only by the function that calls the AI.
2. In that function, check on the server that a signed-in user sent the
request. Refuse all other requests.
3. Count AI calls per user in the database. Refuse with status 429 after
20 calls in one hour.
4. Limit the length of the user text and of the AI answer.4.What LidTight checks, and what it cannot see
LidTight’s free check reads the code every visitor downloads and looks for secret keys, with rules for OpenAI and Anthropic keys among others. Its deep checks, also free, run when you tick the box under the app link. They call your AI helper up to 5 times as a stranger and report it when every call is answered and none is refused.
It tests your app from outside, as a visitor and as test users. It cannot see your provider’s usage page, your spend limit, your server code, or a key that leaked outside your app, for example in a chat or a screenshot. The deep checks need a Supabase backend (Lovable Cloud is one), and they test only an AI helper they find in the code.
For the rest of your launch checks, see Before you go live: a security checklist and What can a stranger see in your app?.