Scan free

OpenAI API Key Leaked? Revoke It, Then Check Usage and Limits

OpenAI API key leaked? Revoke it in the OpenAI dashboard now, before you clean up git or the code. Anyone who copied the key can send requests that are billed to you until it stops working, and OpenAI says revocations take effect within a few seconds. Then create a replacement that lives only on a server, check usage and costs for traffic you didn't cause, set a hard spend limit, and fix whatever exposed the key so the new one doesn't follow it.

OpenAI API key leaked: what to do first

An OpenAI key is a bearer credential. The API reference puts it plainly: "Remember that your API key is a secret." Unless you've set up an IP allowlist (Step 3), whoever holds the string can use it.

Here is the order. Each step is covered below.

  1. Revoke the leaked key and create a new one.
  2. Check usage and costs for activity that wasn't you.
  3. Set a hard spend limit and spend alerts.
  4. Give the new key only the permissions it needs.
  5. Contact OpenAI support if there's usage you didn't cause.
  6. Close the leak: the commit, the frontend bundle, the chat message.

Why was my OpenAI API key disabled?

Sometimes you hear about the leak from OpenAI before you notice it yourself. GitHub runs a secret scanning partner program: when it detects a partner's secret in a public repository or a public npm package, "an alert is sent directly to the provider." OpenAI is on GitHub's list of partners for the openai_api_key type. GitHub says the provider then "validates the string and then decides whether they should revoke the secret," and may issue a new one or contact you directly.

So a key that suddenly returns 401 shortly after a push to a public repo has very likely been caught that way. OpenAI's error codes guide lists "You are using a revoked API key" and "an API key that has been deleted or deactivated" as causes of 401 errors.

A disabled key is still a leaked key, and the program only covers places GitHub scans. Do the rest of the steps anyway, starting with the usage check, because someone may have used the key before it was switched off. A private repository, a deployed JavaScript bundle or a Discord message isn't part of that program, so don't count on anyone disabling those keys for you.

Step 1: How to revoke an OpenAI API key and rotate it

OpenAI's safety guide says that if a key "has been exposed, misused, or otherwise compromised," you should "revoke it promptly and replace it with a new key."

Where you do that depends on the kind of key:

  • Project API keys are managed on the API keys page of the platform dashboard. They belong to a project, and they're owned either by a user or by a service account.
  • Legacy user API keys are the older kind, which the API reference mentions separately from project keys. The safety guide points to the Security settings page in your profile "to view all API keys and revoke any compromised keys."

Not sure which kind leaked? Check both pages, and revoke anything you don't recognize.

Then rotate. OpenAI's production guide describes the planned version: create a replacement, update your applications, then revoke the old key. For a leaked key, revoke first and accept a few minutes of downtime, because every minute the old key works is a minute someone else can bill to you.

When you create the replacement:

  • Set an expiration date. OpenAI says "We strongly recommend setting an expiration date when you create a project API key."
  • Put it only where server code reads it: your host's environment variables, CI secrets, or a secrets manager. Never in a variable that starts with NEXT_PUBLIC_, VITE_ or EXPO_PUBLIC_.
  • Redeploy, then confirm the old key is dead. A request with the old key should return 401:
bash
curl -s -o /dev/null -w "%{http_code}\n" https://api.openai.com/v1/models \
  -H "Authorization: Bearer $OLD_OPENAI_KEY"

If it prints 200, you revoked the wrong key.

If the key also sat in a .env file alongside other secrets, rotate all of them. The .env cleanup guide has a table of where each common key is rotated.

Step 2: Check OpenAI API key usage for activity you didn't cause

Open the usage dashboard and look at the days since the key was exposed. Signs it wasn't you: models your app doesn't call, request volume at hours your users are asleep, or spend that jumps on the day of the leak.

Per-key numbers depend on tracking. The production guide says "API key usage can be monitored on the Usage page once tracking is enabled," and that keys created before December 20, 2023 may not have it turned on; older usage shows up as Untracked. You can enable tracking for those keys from the API keys page, but it only applies from then on.

If you use several projects, check each one. A key belongs to a project, so the project tells you which key to blame.

Pull costs per key with the Usage API

For a precise answer, the Usage API returns costs grouped by api_key_id or project_id. It needs an Admin API key, which you create on the Admin keys page; OpenAI's Admin APIs guide notes that "Admin API keys cannot be used for non-administration endpoints."

bash
START=$(( $(date +%s) - 30*86400 ))
curl -s "https://api.openai.com/v1/organization/costs?start_time=$START&group_by=api_key_id&limit=30" \
  -H "Authorization: Bearer $OPENAI_ADMIN_KEY"

The response is a list of daily buckets. Each result has an amount with a value and currency, and an api_key_id because you grouped by it. The costs endpoint only supports daily buckets, and limit goes up to 180 days. Swap costs for usage/completions to see token counts instead, which also accepts group_by=model.

Treat the Admin key with more care than the one that leaked: it can manage your organization's users, projects and API keys. Delete it when you're done if you don't need it.

Step 3: Set an OpenAI spend limit and alerts

A spend limit is damage control for the next leak. OpenAI's spend limits guide separates two controls:

ControlWhat it doesWhere
Spend alertNotifies you at a dollar threshold. "Spend alerts do not enforce a cap."The limits page
Organization hard limitStops API traffic "across all projects in the organization" when tracked spend reaches itOrganization limits, Spend, Edit spend limit, turn on Enforce a hard limit
Project hard limitStops traffic "billed to that project" onlyProject settings, Limits, Spend, Edit spend limit

When a hard limit is reached, requests fail with a 429 and the code organization_spend_limit_exceeded or project_spend_limit_exceeded. Two caveats from the guide: "Enforcement is not instantaneous, so recorded spend can slightly exceed the configured amount," and "Hard spend limits can interrupt production traffic." A project limit set a little above your normal month is a reasonable middle ground: a stolen key can't run up an open-ended bill, and the rest of your organization keeps working.

OpenAI also supports an IP allowlist for a project or organization. Requests from other addresses get a 401 "IP not authorized." It only fits if your server calls OpenAI from fixed addresses, which many serverless hosts don't have.

Step 4: Restrict OpenAI API key permissions

A key doesn't have to be able to do everything. Project API keys can carry scope restrictions: the project API keys reference describes ["api.all.read"] for read-only access and specific scopes such as ["api.files.read"] for restricted access. An empty scope list means all permissions, so the default is the widest one.

A restricted key won't stop someone from spending your money on the endpoints it does allow. What it does is limit the rest: a key scoped to what your app actually calls can't be used for everything else in the project, such as your stored files. Give the new key the narrowest permissions your app works with, and use separate projects for staging and production, which the production guide also recommends.

Step 5: OpenAI API key compromised? Contact support

If the usage check shows traffic you didn't cause, contact OpenAI. The error codes guide points to "our support team via chat" at help.openai.com. Have these ready:

  • The project and the key's name or ID (OpenAI's API shows keys in a redacted form such as sk-abc...def).
  • When and where the key was exposed, and when you revoked it.
  • The dates, models and amounts that weren't yours, from Step 2.
  • What you've already done: revoked, rotated, spend limit set.

What OpenAI does about charges is up to OpenAI. Nothing in its developer docs promises a refund for usage on a leaked key, so don't plan around one.

How OpenAI API keys get exposed, and the fix for each

Revoking the key is half the job. If you don't close the path it leaked through, the new key goes the same way.

OpenAI key leaked on GitHub

A common path: the key was hardcoded in a source file, a committed .env, a notebook cell, or a test script. Deleting it in a later commit doesn't remove it from history. This lists every commit that added or removed something shaped like an OpenAI key:

bash
git log --all --oneline -E -G 'sk-[A-Za-z0-9_-]{20,}'

Once the key is revoked, the string in history is worthless, so a history rewrite is optional. If you want one anyway, plus push protection and a pre-commit hook so it doesn't happen again, the .env file guide covers git-filter-repo and its limits step by step. Public forks and clones made before the rewrite keep the old commits either way.

OpenAI API key exposed in the frontend

If your app calls OpenAI from the browser, the key is in your JavaScript bundle, readable by anyone who opens developer tools. The usual signs are a variable named NEXT_PUBLIC_OPENAI_API_KEY or VITE_OPENAI_API_KEY, or a client created with dangerouslyAllowBrowser: true. The openai-node README says browser support is "disabled by default to avoid exposing your secret API credentials."

This path matters most for the rotation order. Putting the new key in the same variable and redeploying leaks it again within minutes. Revoke the old key, move the OpenAI call to a server route that holds the key and checks the caller, and only then deploy the new key. The guide to hiding an API key in the frontend has the Next.js route handler and Supabase Edge Function code for that.

To check a build before you deploy it, search the output folder:

bash
grep -rEo 'sk-[A-Za-z0-9_-]{20,}' dist/ .next/static/ 2>/dev/null | head

Any match means a key is in files that ship to the browser. Use whichever folder your framework builds to.

Pasted into a chat, forum, issue or screenshot

Discord help channels, GitHub issues, forum questions, shared AI chat links, terminal screenshots. Deleting the message doesn't help, because you can't know who already read it. Revoke the key, and next time replace the value with sk-... before you paste.

Logs, CI output and shared notebooks

A build log that echoes environment variables, an error tracker that captures request headers, or a notebook shared with its outputs can all carry the key. After rotating, remove whatever printed it, then clear the old outputs or logs where the tool allows.

Leaked OpenAI key checklist

  • Old key revoked, and a request with it returns 401.
  • Both the project API keys page and the legacy Security settings page checked for keys you don't recognize.
  • New key has an expiration date, the narrowest scopes your app needs, and lives only in server-side environment variables.
  • Usage and costs reviewed per key or per project since the leak.
  • Hard spend limit on the project and spend alerts on the organization.
  • Support contacted, with dates and amounts, if there was usage you didn't cause.
  • Leak path closed: no sk- string in the code or the build output, no NEXT_PUBLIC_ or VITE_ OpenAI variable, no dangerouslyAllowBrowser: true with a real key.
  • Push protection or a pre-commit secret scan turned on. The vibe coding security checklist covers the rest of the prelaunch pass.

Check your repository for a leaked OpenAI key

A free Tuvio scan needs no account. It flags OpenAI API keys in your code and in git history (the full history where it can, else the last 12 months, else the latest commit, and the report says which), so a key you deleted in a later commit is still flagged. It also flags an LLM SDK client running in the browser with dangerouslyAllowBrowser: true and its key read from a public variable such as NEXT_PUBLIC_ or VITE_.

It reads the repository as pushed to GitHub. It doesn't see keys pasted into chats, keys set in your host's dashboard, or a deployed bundle that isn't in the repo. It flags; it doesn't rotate keys or touch your OpenAI account, so Step 1 is still yours. The example report shows what a finding looks like.

Tuvio: a second look at the app you didn't entirely write.

© 2026 CodexMotive Digital Solutions. Scanning reads your files; it never runs them.

Human supported: people write and test the checks, and a person answers info@tuvio.dev.