The fix, in one snippet
POST /api/chat -> your server -> LLM provider
LLM_API_KEY=stored-in-server-secret-manager
Illustrative values. Change the paths, hostnames and options to match your own site before using it.
The sections below explain what is tested, why it matters and the alternatives.
What we test
Scan.now fetches the page you entered, follows its same-origin JavaScript, explicitly referenced JavaScript or JSON chunks and linked source maps, then requests a fixed list of common .env, Git, backup, SQL/configuration and runtime-config paths. Exposure responses are verified by content so a custom 200 error page is not treated as a real file. Paid owners may provide a transient Authorization or Cookie header for the exact private URL. It is stripped before cross-origin redirects and never stored. The scanner looks for documented provider prefixes and for long credential values assigned to provider-specific names such as OPENAI_API_KEY or MISTRAL_API_KEY. Every request is a read-only GET: JavaScript is not executed, forms are not submitted and discovered values are not sent to providers. A match is redacted in memory before the result is built, so the raw credential is never written to a report or log. Prefix matches are high confidence; opaque values found only beside a provider label are label matches that should be confirmed in your own source. The Premium local-folder audit runs inside the visitor's browser without uploading files; its optional Python companion covers remote-server files and Git patch history that no website scanner can inspect.
Why it matters
An API key in a browser bundle is public even when the repository is private. A visitor can open developer tools, download the JavaScript file, inspect a source map or search the response body without bypassing any control. If the key authorises paid inference, anyone who copies it can run requests against your account, spend the quota, access provider features granted to the key and get the account suspended for traffic you did not send. Provider-side domain restrictions help where they are available, but they are not a substitute for keeping a bearer credential on the server: request headers can be reproduced outside a browser and not every LLM provider offers an enforceable origin restriction. Minification, Base64 encoding and splitting a string across variables only obscure the value; the browser must reconstruct it to use it. The wider exposed LLM API keys guide explains how secrets reach frontend builds and how to design the boundary correctly.
How to fix it
Revoke or rotate the exposed key first. Removing it from the current JavaScript bundle does not invalidate copies already downloaded, cached, committed or archived. Review the provider's usage logs, billing and key list for activity you do not recognise, then create a replacement with the smallest permissions and budget the application needs. Move all calls that require the credential behind a server-side endpoint:
browser --POST /api/chat--> your server --Authorization: Bearer $LLM_API_KEY--> provider
Store the replacement in the hosting platform's server-only secret manager, not in a variable exposed to the frontend build. Names such as NEXT_PUBLIC_*, VITE_*, REACT_APP_* and PUBLIC_* are designed to be embedded in browser code. Remove the key from source maps and build artefacts, invalidate the CDN cache, and search the repository history and deployment logs for the redacted prefix shown in the finding. Add secret scanning to pre-commit and CI, then re-run this scanner and the broader website vulnerability scanner. If the key was in a public .env or backup rather than a bundle, also follow the containment steps in Exposed Files and Directories.
The first few lines
You are a senior web engineer. I ran a security and SEO scanner against my site and it reported the finding below. Fix it properly rather than suppressing the symptom.
Finding: Exposed LLM API key in public client-side code (critical severity)
Scanner check id: exposed-llm-api-key
The rest of this prompt names the pages and line numbers we found the problem on, the configuration to change, and the constraints a good answer has to respect. It is free, it just needs an account so the work is not scraped wholesale.
Sign in with GoogleSigning in is free and takes one click. We store your email address and nothing else.
References
Related guides
9 min read · Updated Sep 20, 2026
Exposed LLM API Keys: How They Leak, How to Find Them and What to Do Next
An LLM API key in browser JavaScript is a public bearer credential. Learn how OpenAI, Anthropic, Gemini and other keys reach frontend...
Read the guide
9 min read · Updated Sep 12, 2026
Exposed Files: .git, .env, Backups and Debug Pages That Leak Your Site's Secrets
Many breaches start with a file that should never have been public: A .git folder, a .env with database credentials, a backup archive or...
Read the guide