OpenAI API key security: best practices and leak response

Where to keep OpenAI API keys, how to limit what each one can do, how to spot a leaked key in your usage data, and what to do when one gets out.

Braid7-minute read

Keep OpenAI API keys on your own servers, in environment variables or a secret manager, and give each deployment its own service-account key with only the permissions it needs. Put a monthly spend limit on every project so a stolen key has a ceiling. If a key leaks, delete it, deploy a replacement, check usage by API key to see what it was used for, and find out how it got out before you issue the next one.

Keep keys out of browsers, mobile apps and public repos

Anything you ship to a user's device can be read by that user. A key in a JavaScript bundle shows up in the browser's developer tools, and a key compiled into a mobile app can be extracted from the package. So the client never talks to OpenAI directly. It calls an endpoint on your own backend, and the backend calls OpenAI with a key the client never sees. The backend is also where you check who is asking and rate-limit each user.

// server.js: the browser posts to /api/summarize, and only the server holds the key
import express from "express";
import OpenAI from "openai";

const app = express();
const openai = new OpenAI(); // reads OPENAI_API_KEY from the environment

app.post("/api/summarize", express.json(), async (req, res) => {
  // check the user's session here before spending money on their request
  const response = await openai.responses.create({
    model: "gpt-5-mini",
    input: `Summarize in three sentences:\n\n${req.body.text}`,
  });
  res.json({ summary: response.output_text });
});

Frontend frameworks make one mistake easy. Vite exposes variables starting with VITE_ to client code, Next.js inlines NEXT_PUBLIC_ variables into the browser bundle, and Expo does the same with EXPO_PUBLIC_. A key stored under one of those names is public. If an AI coding tool or app builder wrote your app, run grep -r "sk-proj-" dist/ on a production build (or whatever your build folder is called). It should find nothing.

A key committed to a public repository is compromised even if the next commit deletes it, because it stays in the history and in every fork. Keep .env in .gitignore and turn on a secret scanner, such as GitHub's push protection.

Store keys in environment variables or a secret manager

OpenAI's SDKs read OPENAI_API_KEY from the environment automatically, so new OpenAI() in Node or OpenAI() in Python needs no key in the source. On a laptop, set it in a .env file that git ignores, using a key from a development project. In production, use your host's encrypted environment variables, your CI system's secrets, or a secret manager such as AWS Secrets Manager, Google Cloud Secret Manager or HashiCorp Vault.

Since September 2026, project keys can be created with an expiration date, and administrators can enforce a maximum key lifetime. OpenAI's key safety guidance recommends both expiring keys and regular rotation. Rotate in the same order every time: create the replacement, deploy it, confirm traffic has moved to it, then revoke the old key.

On supported platforms, such as AWS, Google Cloud, Kubernetes and GitHub Actions, workload identity federation swaps the stored key for short-lived tokens.

Give each deployment its own restricted key

A user-owned key acts with its owner's access and stops working when that person leaves the project. For anything that runs unattended, create a service account in the project (Organization settings, select the project, then Members and + Service account) and use its key. Create one per deployment, meaning per service and environment, so a leak means revoking one key and redeploying one service, and usage by key points at something specific. The layout is covered in how to organize OpenAI projects and API keys.

Restrict each key's permissions

Keys can have All, Restricted or Read Only permissions. Restricted sets each resource or endpoint to None, Read or Write, so a service that only generates text doesn't get access to files, fine-tuning or assistants. A new service-account key can read and write everything in its project by default, and the creation dialog doesn't offer permission controls for it, so restrict it afterwards in the project's API Keys settings.

Limit who can create keys

Project members can create keys in their projects by default. Since September 15, 2026, organizations and projects can allow only service-account keys, only user-owned keys, or no new keys. Existing keys aren't affected, so review them when you turn this on.

Admin keys can't call models, but one with write permissions can create keys that can. Only organization owners create them, so keep the owner list short and give reporting tools a read-only Admin key.

Set spend limits and an IP allowlist

A spend limit caps what a leak can cost. Set a monthly limit in each project's Limits settings and turn on Enforce a hard limit. Once tracked spend reaches it, the project's requests fail with a 429 error, project_spend_limit_exceeded, though OpenAI says enforcement isn't instantaneous and spend can go slightly over. Leave headroom over a normal month. The guide to spend alerts and limits covers each setting.

If your servers send requests from fixed IP addresses, an IP allowlist makes a stolen key fail anywhere else. It's under Settings, then Security, then IP allowlist, for the organization or a single project, with up to 50 addresses or CIDR ranges. Requests from other addresses get a 401 ip_not_authorized error even with a valid key. Changes can take up to 15 minutes to apply, so start with one project.

How to spot a leaked key in your usage data

A leaked key usually shows up as spend that doesn't match anything you run. Open the usage dashboard, group by API key, and look back two to four weeks. Dates there are in UTC.

SignWhat to look for
An unfamiliar keySpend on a key nobody can name, or one called "test" in a production project
Spend on a key nothing runsUsage on keys for retired services, old deployments or a former employee's laptop
Odd hoursSteady usage when your own traffic is flat, such as overnight for your users
Odd modelsA key that runs one small model suddenly calling a large model, image generation or audio
More requests than you sentOpenAI's request count for a key well above your own log of calls to OpenAI

With an Admin key, the Usage API gives the same view. This asks for seven days of completions usage in hourly buckets, split by key and model (GNU date; on macOS use date -v-7d +%s):

curl "https://api.openai.com/v1/organization/usage/completions?start_time=$(date -d '7 days ago' +%s)&bucket_width=1h&limit=168&group_by=api_key_id&group_by=model" \
  -H "Authorization: Bearer $OPENAI_ADMIN_KEY"

Each result carries api_key_id, model, token counts and num_model_requests. To match a key ID to its name, owner and last-used time, call GET /v1/organization/projects/{project_id}/api_keys. The Usage and Costs API guide covers the other endpoints and pagination.

What to do when an OpenAI API key leaks

  1. Revoke and rotate the key in the project's API Keys settings. If it was public, assume it has been copied: delete it at once and accept the downtime. If the exposure was contained, such as a key in an internal ticket, deploy the replacement first.
  2. Check usage by key from the day of the exposure: which models, how many requests, at what hours, and the cost. Save what you find. If an owner's account or a write-enabled Admin key leaked, also check the audit log for new keys and members, if an owner has turned audit logging on.
  3. Set or lower a hard spend limit on the affected project while you investigate.
  4. Find out how it leaked. Search the git history (git log -p -S "sk-proj-" lists commits that added or removed the string), built frontend bundles, CI logs, error reports, and anywhere the key was pasted.
  5. If you see usage you didn't make, contact OpenAI Support through the chat on any help center page, with the details from step 2.

What OpenAI does with leaked keys

OpenAI's help center says that when it detects an API key on the public internet, or inside an app in an app store, it disables the key immediately. A key in a private repository, a log file or a shared document won't be found that way. If a key stops working and nobody on your team revoked it, treat it as leaked and work through the steps above.

Common questions

Is it safe to store an OpenAI API key in a .env file?

For local development, yes, as long as the file is in .gitignore and none of its variables are ones your frontend build copies into client code. In production, use your host's encrypted environment variables or a secret manager.

Can someone use a leaked OpenAI API key to read my data?

A project key works only inside its project. Depending on its permissions, it can read and change that project's stored resources, such as uploaded files, vector stores and assistants, as well as make requests billed to you. Restricted permissions limit what a leaked key can reach.

How often should I rotate OpenAI API keys?

OpenAI doesn't set an interval. We'd pick one the team will keep to, such as 90 days for production keys, use it as the keys' expiration date, and rotate straight away when someone with access to a key leaves.

Where Braid fits

Braid doesn't scan code for keys, revoke keys or block requests. It reads your OpenAI usage with a read-only Admin key and maps each project and API key to an Implementation, a use case your company names, with an owner. Spend from keys that aren't mapped to anything shows up as unmapped usage, and Braid flags unusual spend in the app and by email, with the affected Implementation and source details when the data supports them. It never reads prompts or responses and never changes your OpenAI account.

Try Braid with your team.

We're looking for teams to test Braid before launch. Get full access to all premium features for free. All we ask is for feedback on what works and what needs improvement.

  1. Request beta access.Tell us your name, role and company.
  2. Receive your invitation.If approved, you'll get an email inviting you to join.
  3. Set up your company.Connect your provider, map your AI use cases and invite your team.

Request beta access.

Justin, Braid's founder, reviews every request. If yours is approved, you'll get an invitation by email.

Free during beta. No credit card required.