{"slug": "openai-api-key-exposed-in-the-browser-next-public-vite-and", "title": "OpenAI API key exposed in the browser: NEXT_PUBLIC_, VITE_ and dangerouslyAllowBrowser", "summary": "A developer released BrowserKey, a free MIT-licensed VS Code extension that detects OpenAI, Anthropic, Gemini, Groq, xAI and OpenRouter API keys leaking into browser bundles across Next.js, Vite, CRA, Expo, Nuxt, Gatsby, SvelteKit and Astro projects. The extension ships six rules that flag NEXT_PUBLIC_ and VITE_ prefixed secrets, dangerouslyAllowBrowser: true usage, and hardcoded keys in client code, offering a Quick Fix to rename them to server-only variables, with keys always masked and no network, telemetry or child processes. The write-up recommends calling providers from a server route and rotating any key that was ever deployed, since old builds and caches retain it.", "body_md": "The client said `undefined`, so the key got a prefix. Then the SDK refused to run in the browser, so it got a flag:\n\n``` js\n\"use client\";\nconst openai = new OpenAI({\n  apiKey: process.env.NEXT_PUBLIC_OPENAI_API_KEY,\n  dangerouslyAllowBrowser: true,\n});\n```\n\nIt works. And the OpenAI API key is now in plain text in a JavaScript file every visitor downloads. (A made-up example, but a very common one.)\n\n`NEXT_PUBLIC_` values \"into any JavaScript sent to the browser\".\nThe OpenAI and Anthropic JS SDKs block browsers by default \"to avoid exposing your secret API credentials\". `dangerouslyAllowBrowser: true` switches that guard off.\n\n`.env`, CI, Dockerfile)` dangerouslyAllowBrowser: true``\"use client\"` file (and the \"fix\" of adding a prefix)`define`, webpack `DefinePlugin`, `next.config` `env`\nPlus a key pasted into a component \"just to test\".\n\n**Fix:** call the provider from a server route with a server-only variable, have the page call that route, and rotate any key that was ever deployed. Deleting it from the code is not enough: old builds and caches still have it. In a Vite app with no server, a small serverless or edge function does the same job.\n\nI built **[BrowserKey](https://marketplace.visualstudio.com/items?itemName=jaytankdev.browserkey)**, a free VS Code extension that catches all of these for Next.js, Vite, CRA, Expo, Nuxt, Gatsby, SvelteKit and Astro, and for OpenAI, Anthropic, Gemini, Groq, xAI, OpenRouter and more. Six rules, a Quick Fix to rename to a server-only variable, and an activity bar panel:\n\n```\nNEXT_PUBLIC_OPENAI_API_KEY in .env.local is bundled into the browser\nnew OpenAI({ dangerouslyAllowBrowser: true }) exposes the API key\nhardcoded OpenAI key sk-proj-**** in browser code\n```\n\nKeys are always masked. No network, no telemetry, no child processes.\n\n```\ncode --install-extension jaytankdev.browserkey\n```\n\nSource (MIT): [github.com/jay-tank/browserkey](https://github.com/jay-tank/browserkey)\n\n**Full write-up** (framework docs, the server route fix, all six rules, FAQ): [OpenAI API key exposed in the browser](https://jaytank.hashnode.dev/browserkey-openai-api-key-exposed-next-public-vite)", "url": "https://wpnews.pro/news/openai-api-key-exposed-in-the-browser-next-public-vite-and", "canonical_source": "https://dev.to/jaytank/openai-api-key-exposed-in-the-browser-nextpublic-vite-and-dangerouslyallowbrowser-2ib0", "published_at": "2026-10-28 03:35:00+00:00", "updated_at": "2026-10-28 03:41:15.270549+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "ai-safety"], "entities": ["BrowserKey", "OpenAI", "Anthropic", "Gemini", "Groq", "xAI", "OpenRouter", "Visual Studio Code"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/openai-api-key-exposed-in-the-browser-next-public-vite-and", "markdown": "https://wpnews.pro/news/openai-api-key-exposed-in-the-browser-next-public-vite-and.md", "text": "https://wpnews.pro/news/openai-api-key-exposed-in-the-browser-next-public-vite-and.txt", "jsonld": "https://wpnews.pro/news/openai-api-key-exposed-in-the-browser-next-public-vite-and.jsonld"}}