These are failure modes from launch-audit patterns, described in plain language. They are stack-agnostic: Next.js + Supabase, Firebase, Bubble workflows, Replit backends, Cursor-generated Express APIs, and mixed Claude/v0 frontends all hit variations of the same issues.
1. Secrets in the wrong place
What breaks: API keys, service-role tokens, webhook signing secrets, or database URLs ship in the browser bundle, public repos, client env files committed to Git, or “temporary” hardcodes that never leave the prompt history.
Why AI builds invite this: Models often put keys “where the code needs them” without distinguishing public NEXT_PUBLIC_* / client config from server-only secrets. Founders paste .env examples into chats and leave real values in screenshots or committed files.
What real users trigger: Scrapers and casual “view source” find keys; leaked keys drain AI credits, spam email APIs, or open admin database access.
What “good enough” looks like:- Server-only secrets never appear in client bundles
- Separate keys per environment (dev / staging / prod)
- Rotation plan if a key was ever in a repo or chat
- Provider dashboards checked for unexpected usage
2. Authentication without authorization (authn ≠ authz)
What breaks: Users must log in—but once logged in, the app trusts the client for “what this user can see or do.” Object IDs in URLs or request bodies are accepted without ownership checks. “Admin” is a UI flag, not a server rule.
Audit pattern: Protected pages exist; API routes or Bubble/backend workflows still return other users’ records if you change an ID. Multi-tenant apps share one table with no tenant scope on every query.
What real users trigger: Curious power users, shared links, support staff testing accounts, or simple IDOR (insecure direct object reference) probing.
What “good enough” looks like:- Every read/write path enforces “this principal may act on this resource”
- Role checks on the server, not only in the nav menu
- Org/workspace membership verified on every tenant-scoped action
3. Missing or weak Row Level Security (RLS) and data policies
What breaks: Supabase, Firebase, or similar backends are used with broad client access. RLS is off, default-allow, or written once for a happy path and never extended when tables grow. Service-role keys are used from the client “to make it work.”
Audit pattern: Policies allow select for authenticated without user_id = auth.uid(). Storage buckets are public. Realtime channels broadcast other tenants’ events.
What real users trigger: Any authenticated account becomes a data-export path. Mobile clients and third-party scripts amplify exposure.
What “good enough” looks like:- Default deny; explicit policies per table and operation
- Policies tested with two real users and two orgs
- Service role only on trusted server paths
- Storage and realtime under the same discipline as SQL/documents
4. Webhooks and callbacks that trust the body
What breaks: Stripe, Clerk, Supabase, email, or custom webhooks accept POST bodies without signature verification, replay protection, or idempotency. OAuth callbacks accept state loosely. “Success” URLs mark plans as paid because the browser reached a thank-you page.
Audit pattern: Entitlement flips on unauthenticated webhook routes; duplicate events double-credit accounts; failed signature checks are logged and ignored.
What real users trigger: Accidental double webhooks under load—or deliberate forged events if the endpoint is guessable.
What “good enough” looks like:- Provider signature verification required
- Idempotency keys for payment and provisioning events
- Server-side source of truth for plan status (not the thank-you page)
- Staging webhooks isolated from production secrets
5. Payments and entitlements enforced only in the UI
What breaks: Pricing page and feature flags hide Pro UI, but APIs still run Pro logic for free users. Trial ends in the dashboard copy while backend access continues. Refunds and cancellations do not revoke seats or API quotas.
Audit pattern: isPro from local storage or a client-readable profile field; no server check against Stripe customer/subscription state before expensive or sensitive actions.
What real users trigger: Anyone who can call the API (or replay a network request) bypasses the paywall. Support load spikes when billing state and product state disagree.
What “good enough” looks like:- Entitlement check on every gated server action
- Single billing source of truth synced via verified webhooks
- Explicit handling for past_due, canceled, refunded, and seat changes
6. Agent and automation over-permission
What breaks: AI agents, cron jobs, “support bots,” or n8n/Make-style automations use founder-level tokens. Prompt injection or a buggy tool call becomes full database or email access. Cursor/Claude-generated admin scripts reuse production credentials.
Audit pattern: One shared service account for migrations, customer email, and the in-product agent; tools allowed to run arbitrary SQL or shell; no human approval on destructive actions.
What real users trigger: Hostile or accidental inputs in agent chat; scheduled jobs running against the wrong environment; a leaked automation token equaling full takeover.
What “good enough” looks like:- Least-privilege tokens per automation
- Tool allowlists and rate limits
- No production credentials in local agent configs
- Audit logs for agent-initiated writes
7. Dependency and supply-chain drift
What breaks: Lockfiles ignored, packages added from hurried prompts, abandoned libs, or known-vulnerable versions left unpatched. Prototype “install whatever works” becomes the production image.
Audit pattern: Multiple overlapping auth or UI libraries; unused packages with large attack surface; no process for npm audit / equivalent after each AI-driven dependency burst.
What real users trigger: Automated scanners against your public JS; compromised transitive deps; breakage during emergency upgrades under launch pressure.
What “good enough” looks like:- Lockfiles committed and used in CI
- Periodic vulnerability review before launch and after big AI refactors
- Minimal dependency set for auth, payments, and crypto-related code
8. PII and secrets in logs, analytics, and error trackers
What breaks: Request bodies, auth headers, full payment payloads, or chat contents are console.log’d, sent to client analytics, or stored forever in error tools. Support screenshots include live customer data.
Audit pattern: Debug logging left on from Cursor/Claude sessions; forms posting emails and phone numbers to third-party debug endpoints; AI prompt logs retaining customer content without retention policy.
What real users trigger: Compliance questions, breach notification risk, and painful “can you delete my data?” requests you cannot fulfill cleanly.
What “good enough” looks like:- Structured logs with redaction
- No secrets or raw cards/tokens in any log sink
- Retention and access control on error/analytics tools
- Clear data map: what PII you store and where