Public audits
We ran a deep audit on the starters that 131k+ stars worth of vibe-coded apps are built on.
Same pipeline every paying customer gets: Claude Fable 5.1, high effort, up to ~280K tokens of source per repo. Every finding cites a file and line and ships with a paste-ready fix prompt. If your app started from one of these, you probably inherited some of what's below. The critical findings were reported to the maintainers before this page went public.
Chatbot UI is a Next.js 14 + Supabase multi-provider LLM chat app with workspaces, file retrieval (pgvector), assistants and OpenAPI tools. Client-side data access is mostly protected by sensible RLS, but several server routes bypass RLS with the service-role key without checking who is calling or what they own, and the SQL setup exposes a SECURITY DEFINER storage-deletion RPC to any caller. Fix the exposed delete_storage_object RPC and the unauthenticated /api/chat/custom route first, then close the file-ID IDORs in the retrieval routes and the SSRF in the tools route before letting real users in.
- criticaldelete_storage_object() is a SECURITY DEFINER RPC callable by anyone and deletes any storage objectsupabase/migrations/20240108234540_setup.sql:47
- critical/api/chat/custom has no authentication and uses the service-role client to read any user's custom model API keyapp/api/chat/custom/route.ts:20
- highProduction service_role_key is meant to be hardcoded into a committed SQL migrationsupabase/migrations/20240108234540_setup.sql:54
This is the Vercel ai-chatbot template (Next.js 16 App Router, AI SDK 7 via AI Gateway, NextAuth v5 with guest + credentials, Drizzle/Postgres, Vercel Blob, Redis rate limiting). The API routes are mostly well guarded, but two server actions bypass authorization entirely: `getSuggestions` lets any logged-in (or guest) user read another user's document suggestions by ID, and `generateTitleFromUserMessage` is an exported server action that triggers an unmetered LLM call. Beyond that, the main risks are abuse/cost (unlimited guest account creation resets the per-user quota, IP limit silently disabled without Redis), a missing UNIQUE constraint on User.email, upload content-type spoofing, CI tests pointed at the production database, and zero non-PK indexes on tables that are scanned on every chat request. Fix the two server actions and the guest/rate-limit gaps before launch.
- highartifacts/actions.ts getSuggestions server action has no auth or ownership check (IDOR on document suggestions)artifacts/actions.ts:5
- highgenerateTitleFromUserMessage is exported from a "use server" file, making an unauthenticated, unmetered LLM call publicly invokableapp/(chat)/actions.ts:23
- mediumUpload route trusts client MIME type and keeps original extension, allowing HTML/SVG to be hosted on your public Blob store; filenames are not user-scopedapp/(chat)/api/files/upload/route.ts:52
Taxonomy is a Next.js 13 App Router SaaS starter (shadcn/taxonomy): NextAuth login, a Prisma/MySQL post editor, and a Stripe PRO subscription that lifts a 3-post limit. The core flows are wired sensibly, but there is one outright authorization hole: an unauthenticated request can DELETE or PATCH any post by ID because the ownership check passes `undefined` as the author filter and Prisma drops it. Beyond that, the app is pinned to an April-2023 Next.js canary with many unpatched CVEs, the Stripe checkout flow can double-subscribe a user, and the site still ships demo copy ('you won't be charged', lorem-ipsum Terms/Privacy, shadcn branding). Fix the post route authz and the framework version before anything else.
- criticalUnauthenticated DELETE/PATCH of any post: verifyCurrentUserHasAccessToPost passes authorId: undefined and Prisma ignores itapp/api/posts/[postId]/route.ts:88
- highPinned to Next.js 13.3.2-canary.13 (April 2023) from an archived template with many unpatched CVEspackage.json:70
- highCheckout can create duplicate Stripe customers/subscriptions: /api/users/stripe never reuses stripeCustomerId or guards against a second active subscriptionapp/api/users/stripe/route.ts:35
Next.js 15 (canary) SaaS starter with email/password JWT auth, Drizzle/Postgres, teams with owner/member roles, and Stripe subscriptions. The scaffolding is reasonable (webhook signatures verified, bcrypt, zod on every action, soft deletes), but the authorization layer only exists in the UI: server actions never check team role, invited users are stamped 'owner', the Remove Member action is broken by a zod type mismatch, and the invitation flow lets anyone who signs up with an unverified email join a team by guessing a small integer. On the money side, a paid checkout is only recorded via the browser redirect, so a closed tab means a paying customer with no plan, and the API exposes the user's bcrypt hash to the browser. Fix the role checks, the checkout/webhook provisioning, and the /api/user leak before taking real customers.
- highinviteTeamMember never checks the caller is an owner; any member can invite anyone as 'owner'app/(login)/actions.ts:399
- highremoveTeamMember always fails: schema uses z.number() but FormData delivers a stringapp/(login)/actions.ts:362
- highremoveTeamMember has no role check; any member can remove any other member, including ownersapp/(login)/actions.ts:375
roomGPT is a Next.js 13 App Router app: users upload a room photo via Bytescale, a single POST /generate route hands the URL and a prompt to a Replicate ControlNet model, polls until done, and returns the image. The core flow works on the happy path, but the API route is unauthenticated, rate limiting is silently disabled when Upstash env vars are absent, request input is unvalidated, and almost every failure path (Replicate error, rate limit hit, generation failure) either crashes the client or hangs the spinner forever. The most important fix is protecting /generate from unlimited Replicate spend (auth or mandatory, correctly-keyed rate limiting plus input validation), followed by making the route and client handle failures without hanging.
- criticalPOST /generate is unauthenticated and rate limiting is optional, so anyone can burn unlimited Replicate creditsapp/generate/route.ts:17
- highRate limit identifier falls back to empty string and trusts x-real-ip, collapsing all users into one bucketapp/generate/route.ts:21
- hightheme, room and imageUrl from the request body are unvalidated and go straight into the Replicate promptapp/generate/route.ts:37
This is the Vercel/Supabase/Stripe subscription starter: Supabase auth with RLS, Stripe Checkout and Customer Portal via Server Actions, and a webhook that syncs products/prices/subscriptions into Postgres. The foundations are sound (webhook signature verification, service-role key kept server-side, RLS on every table), but there are several bugs that will cost money or embarrass you with real customers: the checkout Server Action trusts a client-supplied price object including trial_period_days, the 'Manage' button on the pricing page silently creates a second subscription, the webhook returns 400 for every event type it doesn't handle (which will get the endpoint disabled if you 'select all events' as the README says), and the password-confirmation check never actually blocks anything. Fix the checkout action and the pricing button first.
- highcheckoutWithStripe trusts a client-supplied Price object, so users can set their own trial length and pick any Stripe priceutils/stripe/server.ts:76
- highPricing 'Manage' button creates a brand-new Checkout session for already-subscribed users (double billing)components/ui/Pricing/Pricing.tsx:189
- highWebhook returns HTTP 400 for every unhandled event type; Stripe will mark the endpoint failing and eventually disable itapp/api/webhooks/route.ts:91
LlamaCoder is an anonymous, no-login Next.js 16 app that turns a prompt into a small React app via Together AI, streams the result to the browser, previews it in a sandboxed esbuild-wasm iframe, and stores chats/messages in Neon Postgres via Prisma. The preview pipeline and the S3 screenshot upload path are unusually well engineered, but the money-spending surface is wide open: any client (including anyone holding a public share link, which contains a messageId) can trigger unlimited 20k-token generations on your Together account with a model of their choosing, and the createMessage server action lets anyone append arbitrary role/content to any chat. Fix rate limiting + model allow-listing + server action validation before launch; also move assistant-response persistence to the server so closing a tab doesn't throw away a paid generation.
- criticalPaid LLM endpoints (/api/create-chat, /api/get-next-completion-stream-promise, /api/generate-chat-title) have no rate limiting or abuse controlsapp/api/get-next-completion-stream-promise/route.ts:204
- highStream route trusts the client-supplied `model` instead of the chat's stored modelapp/api/get-next-completion-stream-promise/route.ts:158
- highcreateMessage server action lets any client append arbitrary role/content/files to any chat, and can permanently break a chatapp/(main)/actions.ts:21
This is the Kiranism Next.js 16 + shadcn admin dashboard starter: Clerk auth, Sentry, TanStack Query/Table/Form, with all product/user data served from an in-memory faker mock. The UI and auth wiring are solid, but the backend surface is not launch-safe: the /api/products and /api/users route handlers accept unauthenticated, unvalidated GET/POST/PUT/DELETE and write to a shared in-memory store, and the middleware protects nothing outside the /dashboard layout. Before real users arrive, protect and validate the API routes, replace the mock store with a real data layer, and fix the Sentry env-flag bug that silently disables error tracking when you follow the example env file.
- highAll /api/products and /api/users route handlers are public — no auth() check and proxy.ts protects no routessrc/app/api/products/route.ts:41
- highPOST/PUT handlers pass raw request.json() straight into the store — no schema validation, mass assignment of id/created_atsrc/app/api/products/[id]/route.ts:25
- highMock in-memory faker store is the production data layer — data resets on restart, differs per instance, and generates duplicate ids after deletesrc/constants/mock-api.ts:182
BoxyHQ SaaS Starter Kit: a Next.js 15 (pages router) multi-tenant B2B app with NextAuth, Prisma/Postgres, embedded SAML Jackson (SSO + SCIM), Stripe billing, Svix webhooks and Retraced audit logs. The core structure is solid (zod validation, RBAC helper, hashed API keys, lockout, verified Stripe webhooks), but the enterprise-auth surface has real cross-tenant holes: SAML/OAuth logins link to any existing account by email with no tenant check, the SSO DELETE route lets one team delete another team's connections, the DSync PATCH route lets a body-supplied directoryId override the authorized one, and the payments routes skip RBAC entirely. Fix the account-linking takeover first, then the two cross-tenant IDORs and the billing authorization gap, then the broken HTTPS logout.
- criticalSAML/IdP logins link to any existing user by email (allowDangerousEmailAccountLinking) with no tenant or domain check → cross-tenant account takeoverlib/nextAuth.ts:136
- highDELETE /api/teams/[slug]/sso forwards raw req.query to Jackson → team admin can delete another team's SSO connections by passing tenant/productpages/api/teams/[slug]/sso.ts:139
- highPATCH /api/teams/[slug]/dsync/[directoryId] lets request body override directoryId after the access checkpages/api/teams/[slug]/dsync/[directoryId].ts:76
notesGPT is a Next.js + Convex + Clerk app that records voice notes, transcribes them with Together's Whisper, extracts title/summary/action items with an LLM, and embeds transcripts for vector search. Authorization is actually solid (every Convex function goes through queryWithUser/mutationWithUser and checks ownership), but the app is not launch-ready: the recording page destructures `params` synchronously, which is broken on the pinned Next.js 16; any Whisper/LLM failure leaves a note in a permanent loading skeleton; and there is no cap on how much paid transcription/LLM/embedding work a single account can trigger. Fix the Next 16 params bug and add try/catch + failure states to the processing pipeline first, then put per-user limits on the paid path.
- highapp/recording/[id]/page.tsx destructures `params` synchronously — broken on Next.js 16app/recording/[id]/page.tsx:7
- highNo per-user limits on the paid pipeline: createNote, generateUploadUrl and similarNotes can burn Together.ai credits without boundconvex/notes.ts:13
- highconvex/whisper.ts chat action has no error handling — a failed transcription leaves the note in a permanent loading stateconvex/whisper.ts:25
PDFToChat is a Next.js 14 app where users upload a PDF (via Bytescale), it gets chunked and indexed into Chroma Cloud (or Pinecone/MongoDB), and they chat with it through Together AI. The core flows work and the delete route shows the right ownership pattern, but the two expensive API routes do not: /api/chat lets any signed-in user chat with any document by id, and /api/ingestPdf fetches an arbitrary user-supplied URL server-side and has no limits on PDF size. There is also no rate limiting anywhere, and the Chroma retriever creates a new collection for every unknown chatId, so a single script can run up LLM/Chroma bills. Fix the ownership check on /api/chat and the URL/size validation on ingest before letting real users in.
- high/api/chat never checks that chatId belongs to the caller (IDOR) and has no in-route authapp/api/chat/route.ts:36
- high/api/ingestPdf fetches an arbitrary user-supplied fileUrl server-side (SSRF) with no host, type, or size validationapp/api/ingestPdf/route.ts:35
- highNo rate limiting or input bounds on the paid endpoints (/api/chat makes two LLM calls per request; history and message length are unbounded)app/api/chat/route.ts:35
Built on one of these? Audit your fork.
Free quick scan in under a minute; the full Fable 5.1 audit is $19.
Scan my repo →These reports are AI-generated reviews of public open-source code, published to help the people who build on these starters. Findings may include false positives and are not a substitute for a professional security assessment. Maintainers: if you'd like a report removed or corrected, email dlagywns9992@gmail.com.