fixes / launch-ready

How I Would Fix exposed API keys and missing auth in a Cursor-built Next.js automation-heavy service business Using Launch Ready.

The symptom is usually obvious: a founder ships fast, then notices API keys in the browser bundle, public GitHub history, or client-side network calls,...

How I Would Fix exposed API keys and missing auth in a Cursor-built Next.js automation-heavy service business Using Launch Ready

The symptom is usually obvious: a founder ships fast, then notices API keys in the browser bundle, public GitHub history, or client-side network calls, and at the same time core actions are reachable without login. In an automation-heavy service business, that is not just a code smell. It can mean stolen credits, unauthorized workflow runs, customer data exposure, and support chaos within hours.

The most likely root cause is that the app was built too close to the frontend. Cursor can move fast, but if the architecture never forced a server boundary, secrets end up in React components and auth checks get skipped on "temporary" endpoints. The first thing I would inspect is where sensitive actions are executed: route handlers, server actions, webhook handlers, and any client code calling third-party APIs directly.

Triage in the First Hour

1. Check the live site for exposed secrets.

  • Open DevTools and inspect network requests.
  • View page source and bundled JS for API keys, tokens, or internal URLs.
  • Search the deployed repo for `NEXT_PUBLIC_`, hardcoded tokens, and webhook secrets.

2. Review deployment and hosting settings.

  • Confirm which environment variables are set in production.
  • Check whether preview deployments inherited prod secrets.
  • Verify Cloudflare, Vercel, or host logs for unusual request spikes.

3. Inspect auth boundaries.

  • List every endpoint that creates jobs, sends emails, triggers automations, or reads customer records.
  • Confirm whether each one checks session state and role permissions server-side.
  • Look for "trust the frontend" patterns.

4. Review recent builds and commits.

  • Find the last commit that introduced auth changes or env var changes.
  • Check whether Cursor generated new files that bypassed existing middleware.
  • Compare preview vs production behavior.

5. Audit third-party integrations.

  • Stripe, OpenAI, email providers, CRM tools, Zapier-like services, and webhooks should all be reviewed.
  • Verify whether any provider keys were exposed in logs or client calls.

6. Freeze risky actions if needed.

  • Temporarily disable public signup, automation triggers, admin routes, or webhook receivers if they are open.
  • Rotate any key that may have been exposed before you continue.

A quick command I often use during diagnosis:

grep -R "NEXT_PUBLIC_\|sk-\|Bearer \|api_key\|secret\|token" . --exclude-dir=node_modules --exclude-dir=.next

Root Causes

1. Secrets were placed in client-exposed variables.

  • Confirmation: find keys prefixed with `NEXT_PUBLIC_` or imported into components used by the browser.
  • Business impact: anyone can copy those values from the bundle and burn through your API quota.

2. Sensitive logic runs directly in client components.

  • Confirmation: buttons call external APIs from `use client` files instead of route handlers or server actions.
  • Business impact: users can replay requests or tamper with payloads without auth barriers.

3. Missing server-side authorization checks.

  • Confirmation: endpoints accept IDs from the request body but never verify ownership or role on the server.
  • Business impact: one customer can access another customer's automations or records.

4. Webhooks are not verified.

  • Confirmation: inbound webhook routes accept requests without signature validation or timestamp checks.
  • Business impact: attackers can trigger jobs, send emails, or create false events.

5. Preview and production environments share unsafe config.

  • Confirmation: staging uses prod credentials or broad-scoped service accounts.
  • Business impact: a test deploy becomes a production incident.

6. Cursor-generated code bypassed existing patterns.

  • Confirmation: new files do not match your current auth middleware or env handling conventions.
  • Business impact: fast shipping created inconsistent security behavior across routes.

The Fix Plan

I would fix this in layers so we stop the bleeding first and then rebuild safely.

1. Rotate anything exposed before touching code.

  • Rotate API keys, webhook secrets, OAuth client secrets if they were leaked anywhere public.
  • Revoke old tokens immediately if there is any chance they reached a browser bundle or repo history.

2. Move all secret-dependent logic to the server.

  • Put third-party calls inside Next.js route handlers or server actions only.
  • Keep browser code limited to sending user intent to your own backend.

3. Add real auth at every sensitive boundary.

  • Require session verification on every route that reads data or triggers automation.
  • Enforce role checks on admin actions and ownership checks on record access.

4. Lock down environment variables properly.

  • Remove all secrets from `NEXT_PUBLIC_`.
  • Separate preview and production env vars by environment name and scope them narrowly.

5. Verify webhooks before processing them.

  • Reject unsigned requests outright.
  • Check timestamp tolerance to reduce replay risk.

6. Reduce blast radius on automation endpoints.

  • Add rate limits per user and per IP on job-triggering routes.
  • Queue long-running work instead of running it inline in request handlers.

7. Clean up logs and error handling.

  • Stop logging raw headers, request bodies with tokens, or full provider responses containing secrets.
  • Return generic errors to users while keeping structured internal logs for debugging.

8. Patch history if needed.

  • If secrets were committed to Git history, rewrite history only if you control the repo lifecycle and understand the deployment implications.
  • In many cases I prefer rotation plus fresh commits over risky history rewrites unless compliance demands cleanup.

A safe pattern looks like this:

// app/api/run-automation/route.ts
import { NextResponse } from "next/server";

export async function POST(req: Request) {
  const session = await requireSession(req);
  if (!session) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const body = await req.json();
  if (!body.workflowId) {
    return NextResponse.json({ error: "Missing workflowId" }, { status: 400 });
  }

  // Server-side secret usage only
  await runWorkflow({
    workflowId: body.workflowId,
    userId: session.user.id,
    apiKey: process.env.INTERNAL_API_KEY!,
  });

  return NextResponse.json({ ok: true });
}

My rule here is simple: if a request can spend money, send email, mutate customer data, or expose records, it must be authenticated on the server before anything else happens.

Regression Tests Before Redeploy

Before I ship this fix back into production I want proof that I did not just move the problem around.

  • Auth tests
  • Unauthenticated requests to protected endpoints return 401 or redirect to login.
  • Cross-user access attempts return 403 when ownership does not match.
  • Secret exposure tests
  • Search built assets for keys after build completes.
  • Confirm no secret appears in browser network responses or page source.
  • Webhook tests

-"Valid signed webhook" passes." -"Invalid signature" fails with 401." -"Replay attempt" fails after timestamp window."

  • Automation safety tests

-"Trigger job" works only for logged-in users." -"Rate limit" blocks repeated abuse after a defined threshold." -"Queue failure" does not duplicate downstream actions."

  • Deployment checks

-"Preview deploy" uses non-production credentials." -"Production deploy" has monitoring enabled." -"Rollback path" is documented and tested."

Acceptance criteria I would use:

  • Zero secrets visible in client bundles after build inspection.
  • All protected routes enforce auth server-side with no exceptions for "internal use".
  • Webhook verification coverage at least 100 percent for critical providers used by revenue workflows.
  • Smoke test pass rate of at least 95 percent before release approval.

Prevention

I would prevent this from coming back with guardrails across code review, deployment, and monitoring.

| Area | Guardrail | Why it matters | |---|---|---| | Code review | Block any secret usage in client components | Stops leaks before merge | | Auth | Require middleware plus server-side authorization | Prevents trust-the-frontend bugs | | CI | Scan bundles for known secret patterns | Catches accidental exposure early | | Deployment | Separate preview and prod env vars | Reduces blast radius | | Monitoring | Alert on unusual automation volume | Catches abuse fast | | Logging | Redact tokens and headers | Prevents secondary leaks | | UX | Show clear login state before action buttons | Reduces confusing unauthorized flows |

I would also add lightweight observability:

  • Alert on failed auth spikes above baseline by more than 3x in an hour.
  • Alert on outbound API spend anomalies daily at minimum.
  • Track p95 latency on automation routes so added auth checks do not create slowdowns above about 300 ms for normal requests.

For review discipline:

  • No merge unless sensitive endpoints have explicit auth checks shown in diff review.
  • No direct third-party calls from browser code unless they are public-only APIs by design.
  • No exception paths like "temporary admin route" without a ticketed expiry date.

When to Use Launch Ready

Launch Ready fits when you already have a working Cursor-built product but need it made safe enough to run under real traffic within 48 hours.

I would recommend Launch Ready when:

  • You have exposed keys or missing auth and need fast containment before ad spend increases risk further.
  • Your app is close to launch but still fragile around deployment or environment configuration.
  • You need one senior engineer to clean up launch blockers instead of piecing together freelancers across security and DevOps tasks.

What you should prepare before booking:

  • Repo access with write permissions only where needed
  • Hosting access such as Vercel or similar
  • Domain registrar access
  • Cloudflare access if already connected
  • A list of third-party services used by the app
  • Any known incidents involving leaked keys or unauthorized access

My goal in this sprint is not cosmetic cleanup. It is to get you back to a production-safe state without breaking onboarding flow delivery emails automation triggers or customer trust.

Delivery Map

References

  • https://roadmap.sh/api-security-best-practices
  • https://roadmap.sh/code-review-best-practices
  • https://roadmap.sh/cyber-security
  • https://nextjs.org/docs/app/building-your-application/authentication
  • https://cloudflare.com/learning/path/how-cloudflare-protects-websites/what-is-api-security/

---

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.*

Next steps
About the author

Cyprian Tinashe AaronsSenior Full Stack & AI Engineer

Cyprian helps founders rescue, secure, deploy, and automate AI-built apps with production-grade engineering, launch systems, and AI integration.