How I Would Fix exposed API keys and missing auth in a Vercel AI SDK and OpenAI waitlist funnel Using Launch Ready.
The symptom is usually obvious: the waitlist page works, but the browser network tab shows OpenAI calls, API keys in client code, or a public endpoint...
How I Would Fix exposed API keys and missing auth in a Vercel AI SDK and OpenAI waitlist funnel Using Launch Ready
The symptom is usually obvious: the waitlist page works, but the browser network tab shows OpenAI calls, API keys in client code, or a public endpoint that anyone can hit to submit requests. The most likely root cause is that the app was built fast with the Vercel AI SDK, but the OpenAI call and the waitlist submission flow were never moved behind server-side auth or a protected backend boundary.
The first thing I would inspect is the live build on Vercel, then the route handlers, environment variables, and any client components making direct fetch calls. If I can reproduce the request from an incognito window without a session, rate limit, or server validation, I know this is not just a leak risk. It is also a cost risk, spam risk, and launch trust problem.
Triage in the First Hour
1. Check the live site in an incognito browser.
- Submit the waitlist form.
- Open DevTools and inspect Network.
- Confirm whether any OpenAI request leaves the browser directly.
2. Review Vercel deployment logs.
- Look for repeated 4xx and 5xx responses.
- Check for sudden spikes in function invocations.
- Note any requests coming from unknown user agents or repeated IPs.
3. Inspect environment variables in Vercel.
- Confirm `OPENAI_API_KEY` is not exposed to client-side code.
- Verify only public-safe variables use `NEXT_PUBLIC_`.
- Check whether secrets were added to preview builds by mistake.
4. Review source files for client leakage.
- Search for `process.env.OPENAI_API_KEY`.
- Search for direct OpenAI SDK usage inside client components.
- Search for hardcoded keys, test tokens, or copied `.env` values.
5. Inspect auth and submission flow.
- Confirm there is any server-side gate at all.
- Check if CSRF protection, rate limits, or bot protection exist.
- Verify whether duplicate submissions are blocked.
6. Review analytics and email tooling.
- Check if fake signups are inflating conversion numbers.
- Confirm SPF, DKIM, and DMARC are configured before sending confirmation emails.
- Make sure no alerting is tied to broken data.
7. Freeze changes until you know the blast radius.
- Rotate exposed keys if they were committed or shipped.
- Pause paid traffic if bots are generating spend.
- Capture screenshots and logs before editing anything.
## Quick search for likely leaks grep -R "OPENAI_API_KEY\|openai\|Bearer " . grep -R "NEXT_PUBLIC_" .
Root Causes
| Likely cause | What it looks like | How I confirm it | | --- | --- | --- | | OpenAI call made from client code | Browser network tab shows direct request to OpenAI or SDK wrapper | Inspect React components and browser requests | | Secret stored as public env var | Key appears in bundled JS or accessible runtime config | Check `.env`, Vercel vars, and built assets | | Missing server route boundary | Form posts directly to external API without backend validation | Trace request path from UI to handler | | No auth or anti-bot controls | Anyone can submit unlimited entries or trigger expensive actions | Test from logged out session and repeated requests | | Weak deployment hygiene | Preview and production share unsafe config or stale secrets | Compare Vercel env scopes and recent deploy history | | No input validation | Bad payloads reach AI calls or database writes | Submit empty, oversized, malformed, and scripted inputs |
The most common pattern I see is this: a founder used a client component because it was faster to ship. That works until someone opens DevTools and sees the key path, or until bots hammer the form and burn through credits.
The Fix Plan
First, I move every OpenAI call behind a server-only route handler or server action. The browser should send only sanitized user input to your own backend, never to OpenAI directly.
Second, I remove all secrets from client-accessible code paths. In practice that means no `NEXT_PUBLIC_OPENAI_API_KEY`, no hardcoded tokens in frontend files, and no debug logs that print headers or full payloads.
Third, I add basic auth or gating appropriate to a waitlist funnel. For most funnels I recommend one of these:
- Email magic link before accessing AI features.
- Signed token after waitlist submission.
- Server-side rate limit plus CAPTCHA for anonymous forms.
My preferred fix path is simple: keep the marketing page public, but protect every expensive action behind a server route with validation and rate limiting. That reduces abuse without hurting conversion as much as forcing full login too early.
Fourth, I add input validation on both the waitlist form and any AI prompt fields. Use strict schema checks so empty names, malformed emails, long prompts, script tags, and repeated submissions get rejected before they reach downstream services.
Fifth, I rotate any exposed keys immediately after confirming exposure. If a key ever touched frontend code or logs, assume it is compromised enough to replace it even if you have not seen abuse yet.
Sixth, I clean up deployment settings in Vercel:
- Production-only secrets in production scope.
- Preview-safe dummy values where needed.
- Build-time checks that fail if required secrets are missing.
- Separate monitoring alerts for production functions only.
A minimal safe pattern looks like this:
// app/api/waitlist/route.ts
import { NextResponse } from "next/server";
export async function POST(req: Request) {
const body = await req.json();
if (!body.email || typeof body.email !== "string") {
return NextResponse.json({ error: "Invalid email" }, { status: 400 });
}
// Server-only OpenAI call here
// Use process.env.OPENAI_API_KEY only on the server
return NextResponse.json({ ok: true });
}That does not solve everything by itself. It does establish one critical boundary: secrets stay on the server side where they belong.
Regression Tests Before Redeploy
I would not redeploy until these checks pass:
1. Secret exposure check
- No API key appears in browser source or bundled JS.
- No secret appears in logs after form submission.
- No `.env` file is committed.
2. Auth and access control check
- Anonymous users cannot trigger protected AI actions directly.
- Repeated submissions are rate limited.
- Invalid sessions are rejected with clear errors.
3. Input validation check
- Empty email fails cleanly.
- Malformed email fails cleanly.
- Oversized payloads fail cleanly.
- Script injection strings are treated as text only.
4. Functional funnel check
- Waitlist signup still works end to end.
- Confirmation email sends correctly if enabled.
- Redirects land on the right thank-you page.
5. Security behavior check
- OpenAI requests originate only from server routes.
- Error messages do not reveal internal stack traces or secrets.
- CORS does not allow uncontrolled cross-origin access.
6. Load and abuse check
- 20 rapid submissions do not break the function.
- Rate limits trigger before costs spike.
- p95 response time stays under 500 ms for non-AI steps.
7. Monitoring check
- Uptime alerts fire on failed deployments.
- Function error alerts fire on repeated 5xx responses.
- Email deliverability monitoring is active if confirmations go out.
My acceptance criteria would be:
- Zero exposed secrets in client bundles.
- Zero direct browser calls to OpenAI endpoints.
- All protected routes require valid server-side checks.
- Waitlist conversion remains within 5 percent of baseline after fix.
Prevention
I would put guardrails in place so this does not come back during another rushed launch sprint.
- Code review rules:
- Never approve client-side secret access.
- Reject direct third-party API calls from UI code unless they are truly public-safe.
- Require one reviewer to check network behavior in DevTools before release.
- Security controls:
- Rotate keys every time exposure is suspected.
- Use least privilege on service accounts where possible.
- Add rate limiting at Cloudflare or edge middleware level for public forms.
- Monitoring:
```text Alerts: Function errors > 2 percent over 15 min p95 latency > 500 ms over 15 min Signup spike > 3x normal baseline ```
- UX guardrails:
- Show clear loading states during form submit.
- Explain why email verification may be needed before AI access.
- Keep error copy human-readable so users do not resubmit blindly.
- Performance guardrails:
- Cache static marketing pages at the edge where possible.
- Keep third-party scripts minimal so funnel pages stay fast enough for ads traffic.
-.Monitor Core Web Vitals so lead capture does not suffer from slow pages.
When to Use Launch Ready
Use Launch Ready when you need this fixed fast without turning it into a month-long rebuild.
This sprint fits best when:
- The product already exists but feels risky to send traffic to it.
- You have an AI-built prototype that needs production boundaries now.
- You need one clean launch window instead of piecemeal fixes across several weeks.
What I need from you before kickoff:
- Vercel access with admin rights if possible。
- Domain registrar access。
- Cloudflare access if already connected。
- List of current env vars and third-party tools。
- Confirmation of what should be public versus gated。
- Any existing logs showing spam signups or cost spikes。
If you bring me a working funnel with exposed keys and missing auth, I will focus on reducing launch risk first. The goal is not perfect architecture on day one. The goal is stop leaks, stop abuse, keep conversion intact,and get you live without creating support debt next week。
Delivery Map
References
- https://roadmap.sh/api-security-best-practices
- https://roadmap.sh/code-review-best-practices
- https://roadmap.sh/qa
- https://platform.openai.com/docs/guides/production-best-practices
- https://vercel.com/docs/security/environment-variables
---
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.