The AI Prototype Security Checklist: 10 Critical Vulnerabilities to Fix
AI-generated prototypes are built for speed, not security. Here is the 10-point checklists to harden your v0/Lovable app before real users hit it.
AI tools like v0, Lovable, and Bolt.new have revolutionized prototype development. They allow you to go from prompt to product in hours. However, in their race to generate code that works, they frequently omit fundamental security guards.
When real users start registering, these omissions can turn into business-threatening vulnerabilities. Here is a highly actionable, 10-point checklist to secure your AI prototype before you scale.
1. Move Sensitive API Keys to the Backend
AI tools often drop third-party API keys (like OpenAI, Stripe, or SendGrid) directly into client-side environment variables (.env.local exposed via NEXT_PUBLIC_ or React client bundles).
The Risk
Any user can open their browser's Developer Tools, inspect network requests or JS bundles, and steal your keys, running up thousands of dollars on your API accounts.
The Fix
Never expose keys to the client. Instead, route requests through a secure server-side API handler (e.g. Next.js Route Handlers) or a lightweight edge proxy like Cloudflare Workers.
// INSECURE: Directly calling OpenAI from the client browser
const response = await fetch("https://api.openai.com/v1/chat/completions", {
headers: {
"Authorization": `Bearer ${process.env.NEXT_PUBLIC_OPENAI_KEY}` // Exposed!
}
});
// SECURE: Call your own backend proxy endpoint
const response = await fetch("/api/generate-content", {
method: "POST"
});
2. Enable Supabase Row-Level Security (RLS)
By default, when creating tables in Supabase, Row-Level Security (RLS) is often disabled or configured with permissive true policies by AI generators so that frontend queries succeed instantly.
The Risk
If RLS is disabled, anyone with your public Supabase Anon Key can query your database URL directly and read, write, or delete every row of user data in your system.
The Fix
Always enable RLS on every database table and define explicit policies restricting access based on authenticated user IDs.
-- Enable Row Level Security
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
-- Create policy allowing users to only read/write their own records
CREATE POLICY "Users can manage their own profiles"
ON profiles
FOR ALL
TO authenticated
USING (auth.uid() = id)
WITH CHECK (auth.uid() = id);
3. Implement Client Rate Limiting
AI-generated frontends frequently call server functions or backend endpoints directly without any rate limiting.
The Risk
A simple script looping 10,000 times can spam your expensive AI generation endpoint, ballooning your OpenAI bill or bringing down your database server.
The Fix
Implement API rate limiting. Use an edge middleware (e.g. Upstash Redis, Cloudflare Rate Limiting) to limit requests based on IP or authenticated user ID.
// Simple middleware example using a Redis token bucket
import { RateLimiter } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
const limiter = new RateLimiter({
redis: Redis.fromEnv(),
limiter: RateLimiter.slidingWindow(10, "10 s"), // 10 requests per 10s
});
4. Secure the CORS Configuration
If your app uses a separate backend service, AI code builders will often configure cross-origin resource sharing (CORS) with Origin: * to prevent console errors during development.
The Risk
Any malicious site can make authenticated requests to your backend API on behalf of your logged-in users.
The Fix
Change the wildcard * to explicitly authorize only your production domains.
5. Sanitize and Validate User Inputs
AI generators rely heavily on client-side validation (HTML required or React state filters) but frequently fail to sanitize input on the server/database layer.
The Risk
SQL injections, cross-site scripting (XSS), and database corruption from unescaped input payloads.
The Fix
Utilize schema validation libraries (such as Zod) on every server action or API route.
import { z } from "zod";
const FeedbackSchema = z.object({
email: z.string().email(),
message: z.string().min(10).max(500),
});
export async function POST(request: Request) {
const body = await request.json();
const result = FeedbackSchema.safeParse(body);
if (!result.success) {
return new Response("Invalid Input", { status: 400 });
}
// Proceed with sanitized data
}
6. Never Trust Client-Provided User IDs
Many AI-generated mutations look like this: updateUser(userId, data). The client decides which userId is being modified.
The Risk
A user can edit the payload to supply another user's ID, successfully executing unauthorized account changes.
The Fix
Extract user context directly from secure, verified server-side JWT session cookies, never from body params sent by the client browser.
7. Hide API Keys in Production .env
AI code frequently commits test keys to Git repositories or saves them in unencrypted client-side config modules.
The Fix
Add .env and .env.local to your .gitignore. Use your hosting provider’s secure environment variable vault (Vercel, AWS Secrets Manager, Cloudflare Secrets) to inject keys dynamically at runtime.
8. Prevent LLM Prompts Injection
If your application allows users to supply raw input that is directly injected into an LLM prompt (e.g., Translate this: ${userInput}), it is vulnerable to prompt injection.
The Risk
Users can override your system instructions, forcing the model to leak system prompts, bypass safety filters, or generate unauthorized content.
The Fix
Use structured prompt templates, wrap user input in clear delimiters, and run validation filters over user text before feeding it to your models.
9. Enable Content Security Policy (CSP) Headers
AI prototypes rarely set HTTP security headers.
The Risk
Vulnerability to cross-site scripting (XSS) and code injection attacks.
The Fix
Configure your web server or hosting framework to return strict security headers, specifically Content-Security-Policy (restrict script execution origins) and X-Content-Type-Options: nosniff.
10. Establish Proper Session Expirations
AI templates frequently use default authentication settings where cookies last forever and never expire.
The Risk
If a device is compromised or a token is intercepted, the attacker maintains perpetual access.
The Fix
Configure your authentication provider (Supabase, Clerk, Auth0) to enforce reasonable session lifetimes and implement secure, HTTP-only refresh tokens.
Need a Hand Hardening Your Architecture?
Don't want to dig through your backend configurations yourself? Let CCM handle the security hardening. We'll audit your code, establish robust database rules, secure your secrets, and ensure your system is enterprise-ready.Ready to Harden Your App?
We can help you audit your AI prototype, set up proper database structures, protect your APIs, and deploy it to a production-ready infrastructure in just 2 weeks.