How I Would Fix exposed API keys and missing auth in a Vercel AI SDK and OpenAI internal admin app Using Launch Ready.
If I saw exposed API keys and missing auth in a Vercel AI SDK and OpenAI internal admin app, I would treat it as a production security incident, not a...
Opening
If I saw exposed API keys and missing auth in a Vercel AI SDK and OpenAI internal admin app, I would treat it as a production security incident, not a cleanup task. The business risk is immediate: unauthorized model usage, data exposure, surprise OpenAI bills, broken trust with internal users, and possible leakage of customer or company data.
The most likely root cause is that the app was built fast with client-side calls to OpenAI or Vercel AI SDK helpers, then shipped without a real server-side auth gate. The first thing I would inspect is the deployed app surface: public routes, build output, environment variables in Vercel, and whether any secrets were ever bundled into browser code or exposed through logs.
Triage in the First Hour
1. Check the live app in an incognito window.
- Confirm whether the admin UI loads without login.
- Try common public routes like `/admin`, `/dashboard`, `/api/*`, and any preview URLs.
2. Inspect browser source and network calls.
- Look for `OPENAI_API_KEY`, Vercel env names, or any direct calls to OpenAI endpoints from the client.
- Verify whether requests are going through your own backend or straight from the browser.
3. Review Vercel deployment settings.
- Confirm which environment variables are set in Production, Preview, and Development.
- Check whether any secret was copied into a public env var by mistake.
4. Audit recent commits and builds.
- Find the commit that introduced the missing auth or exposed key.
- Check if preview deployments were indexed or shared externally.
5. Inspect logs and usage spikes.
- Look at Vercel function logs for unusual request volume.
- Check OpenAI usage for spikes in tokens, unusual IPs if available, and unexpected model calls.
6. Review access control on supporting systems.
- Email inboxes tied to password reset.
- DNS provider, Cloudflare, GitHub repo permissions, Vercel team access.
- Any admin accounts that may have been over-shared.
7. Freeze risky changes.
- Pause deployments if needed.
- Rotate exposed keys before doing anything else if there is credible exposure.
A quick diagnostic command I often run during triage is:
grep -R "OPENAI_API_KEY\|Authorization\|Bearer\|apiKey" . --exclude-dir=node_modules --exclude-dir=.next
That tells me fast whether secrets are hardcoded, referenced in client code, or accidentally committed.
Root Causes
1. Secret placed in client-side code
- Confirmation: search the repository for API key strings or direct `OpenAI` initialization inside React components.
- What usually happened: someone wanted to make the demo work quickly and skipped a server route.
2. Missing authentication on admin routes
- Confirmation: open the admin URL in a private browser session and see if it renders data without login.
- What usually happened: route protection was planned but never wired into middleware or session checks.
3. Public API route with no authorization checks
- Confirmation: inspect `/api/*` handlers for missing session validation or role checks before data access or AI actions.
- What usually happened: the endpoint was built for one trusted user and never hardened for multi-user access.
4. Preview deployment exposed to search engines or shared links
- Confirmation: check robots settings, public previews, Slack shares, email forwards, and indexed pages.
- What usually happened: staging looked "private enough" but was actually reachable by anyone with the URL.
5. Misconfigured environment variables in Vercel
- Confirmation: compare Production vs Preview vs Development env vars in Vercel dashboard.
- What usually happened: a secret was added as `NEXT_PUBLIC_*` or copied into a frontend-readable config file.
6. Weak account model for internal admins
- Confirmation: review how users are created and whether roles exist at all.
- What usually happened: internal access relied on "knowing the link" instead of actual authentication and authorization.
The Fix Plan
I would fix this in layers so we stop exposure first, then repair access control properly.
1. Rotate every exposed secret immediately.
- Revoke old OpenAI keys and create new ones.
- Rotate any related service tokens used by Vercel functions, database access, email services, or analytics tools.
- Assume anything previously exposed is compromised until proven otherwise.
2. Remove secrets from all client code paths.
- OpenAI calls must move behind server-side routes only.
- If using Vercel AI SDK, keep provider keys on the server and expose only safe responses to the browser.
- Never ship secret values in `NEXT_PUBLIC_*` variables or frontend bundles.
3. Add real authentication before any admin content loads. Recommended path:
- Use one auth provider consistently for sessions.
- Protect every admin route with middleware plus server-side checks.
- Require authentication on both page render and API access.
4. Add authorization checks by role or permission.
- Do not rely on "logged in" alone if there are different admin levels.
- Gate sensitive actions like deleting records, exporting data, regenerating prompts, or sending messages to customers.
5. Move AI operations behind controlled server endpoints.
- Validate input before sending it to OpenAI.
Example controls:
- max prompt length
- allowed file types
- rate limits per user
- deny unknown tool calls
- strip secrets from prompt context
- Log request IDs and outcomes without logging raw sensitive prompts unless necessary.
6. Lock down deployment surfaces in Vercel and Cloudflare.
- Disable public indexing for internal admin routes where possible.
Use Cloudflare Access or equivalent if this is truly an internal app with a small team. Keep preview environments restricted and clearly labeled as non-production.
7. Add security headers and least-privilege defaults. Enforce: * strict CORS rules * no wildcard origins for authenticated APIs * secure cookies * short-lived sessions * CSRF protection where needed
8. Sanitize logs and error handling . Do not print secrets , tokens , raw request bodies , or full stack traces containing credentials . Return generic errors to users , detailed errors only to protected logs .
9 . Verify database permissions . Make sure the app's DB user can only do what it needs . If an attacker reaches one endpoint , they should not get broad database access .
10 . Ship behind monitoring . Set alerts for auth failures , unusual token usage , 4xx / 5xx spikes , and sudden cost jumps . For an internal admin app , I want p95 API latency under 300 ms for normal CRUD routes , even if AI actions take longer asynchronously .
My preferred order is simple: rotate first , block access second , refactor third . That sequence reduces risk without turning a security fix into a rewrite .
Regression Tests Before Redeploy
I would not redeploy until these checks pass .
1 . Authentication tests
- Anonymous user cannot load admin pages .
- Anonymous user cannot call protected APIs .
- Expired session gets redirected to login .
- Unauthorized role gets 403 on restricted actions .
2 . Secret exposure tests
- Search production build output for key names .
- Confirm no secret appears in browser devtools network responses .
- Confirm no secret exists in rendered HTML , JS bundles , source maps , or logs .
3 . AI request tests
- Server route can call OpenAI successfully using server env vars only .
- Client cannot directly reach OpenAI with credentials .
- Rate limiting blocks abuse after defined thresholds .
4 . Security edge cases
- Invalid tokens return safe errors .
- Oversized prompts are rejected .
- Malformed JSON does not crash the route .
- Unexpected tool requests are denied .
5 . Deployment checks
- Production env vars are correct .
- Preview deployments do not reuse production secrets unless intended .
- SSL is active , redirects work , custom domain resolves correctly .
6 . Acceptance criteria I would use
- Zero public routes expose admin data without login .
- Zero secrets found in frontend bundles or public logs .
- All protected endpoints return 401 or 403 when unauthenticated .
- No regression in core workflow after login .
- Support tickets related to access errors stay below 2 per week after release .
For QA coverage , I want at least 90 percent of critical auth paths tested manually plus automated checks on every deploy . For an internal app , that matters more than pixel-perfect UI polish because one broken permission check can expose everything .
Prevention
The fix is not complete unless recurrence becomes hard .
1 . Security review checklist on every change
- Is this route public ?
- Does this endpoint need auth ?
- Are we logging sensitive data ?
- Is any secret going to the browser ?
- Can this action be abused at scale ?
2 . Add CI gates
- Fail builds if `NEXT_PUBLIC_` contains anything sensitive .
- Fail builds if protected routes lack middleware coverage .
- Run dependency scans on every merge .
3 . Use monitoring that catches abuse early
- Alert on token spend anomalies .
- Alert on repeated 401 / 403 bursts .
- Alert when new deployments change auth-related files .
4 . Reduce blast radius with architecture choices
- Keep AI calls server-side only .
- Separate read-only dashboards from write actions .
- Put destructive actions behind confirmation flows plus role checks .
5 . Improve UX so people do not bypass security out of frustration
- Clear login state handling .
- Helpful error messages when sessions expire .
- Empty states that explain what access is missing instead of exposing internals .
6 . Performance guardrails still matter here
- Keep auth middleware lightweight so it does not slow every page load .
- Cache safe public assets aggressively while keeping private data uncached .
- Watch p95 latency after adding security layers so you do not trade safety for unusable dashboards .
When to Use Launch Ready
Use Launch Ready when you need this fixed fast without turning it into a long engineering project .
This sprint fits best when:
- you already have a working internal app ,
- you need production-safe deployment now ,
- you suspect secrets are exposed ,
- you want proper DNS / SSL / redirects / subdomains cleaned up ,
- you need monitoring before more staff start using it .
What I need from you before I start: 1 . Vercel access with deploy permissions . 2 . Repo access plus recent commit history . 3 . OpenAI account access to rotate keys safely . 4 . Domain registrar and Cloudflare access if already connected . 5 . A short list of who should have admin access on day one .
If I take this on as Launch Ready , my goal is simple : get your app back under control within 48 hours so nobody outside your team can hit sensitive endpoints , no secret lives in the browser , and you have a clean handover checklist instead of another fire drill later .
References
1 . Roadmap.sh Cyber Security Best Practices https://roadmap.sh/cyber-security
2 . Roadmap.sh API Security Best Practices https://roadmap.sh/api-security-best-practices
3 . Vercel Environment Variables Documentation https://vercel.com/docs/projects/environment-variable-management
4 . OpenAI API Security Best Practices https://platform.openai.com/docs/guides/safety-best-practices
5 . Next.js Authentication Documentation https://nextjs.org/docs/app/building-your-application/authentication
---
Take the next step
If this is a problem in your product right now, here is what to do next:
- [Use the free Cyprian tools](/tools) - estimate cost, score app risk, check launch readiness, or pick the right service sprint.
- [Book a discovery call](/contact) - I will tell you honestly whether you need a sprint or if you can DIY the next step.
*Written by Cyprian Tinashe Aarons - senior full-stack and AI engineer helping founders rescue, launch, automate, and scale AI-built products.*
Cyprian Tinashe Aarons — Senior Full Stack & AI Engineer
Cyprian helps founders rescue, secure, deploy, and automate AI-built apps with production-grade engineering, launch systems, and AI integration.