← All articles

Security

AI-Generated App Security: 7 Gaps to Fix Before You Launch

7 min read

Updated

Ensure your AI-built application is secure. Discover the 7 most common security gaps in AI-generated code and how to audit and fix them in 30 minutes.

Most applications built with AI coding tools ship with the same handful of security gaps. None of them are exotic, and all of them can be found in under 30 minutes using free tools.

  • The 7 Common Gaps: API keys in the client bundle, Supabase RLS disabled, missing JWT verification, client-side role checks, unsanitized HTML rendering, no LLM rate limits, and wide-open CORS.
  • The 30-Minute Audit Kit: Use gitleaks, Semgrep, and your preferred AI assistant. No expensive enterprise scanners required.
  • Hosted Builders vs. Security: Platforms like Lovable, Bolt, and v0 abstract away infrastructure, but they do not automatically make your application secure. You still need to audit the outputs.
  • Professional Audits: If your self-audit reveals complex issues, consider bringing in a security agency before scaling your user base.

AI coding tools optimize for functional, working code, but they do not automatically prioritize security. Unless you explicitly prompt them to secure the application, they may leave critical trust boundaries open. The checklist below details what to look for and how to patch these vulnerabilities.

The 30-Minute Audit Kit

You can run a basic security audit using three free tools:

  1. gitleaks (github.com/gitleaks/gitleaks) scans your repository for hardcoded secrets. It runs in seconds.
  2. Semgrep CE (semgrep.dev) performs pattern-based static analysis to identify common code-level vulnerabilities like the OWASP Top 10.
  3. An LLM Assistant. You can use tools like Claude Code or Cursor to review specific directories. For example, ask: "Read every file in app/api and src/api. For each route, tell me which ones do not verify the user's auth token before reading or writing the database."

To install and run the command-line tools:

# Secrets scan
brew install gitleaks
gitleaks detect --source . --no-banner

# Static analysis
brew install semgrep
semgrep --config=auto .

This automated check will find a significant portion of typical code issues. The remaining gaps involve architectural patterns, pricing guardrails, and access control.

The 7 Security Gaps to Check

Gap 1: API Keys in the Client Bundle

  • The Issue: Exposing sensitive keys (like Stripe secret keys or OpenAI keys) by naming them with frontend prefixes (e.g., NEXT_PUBLIC_ or VITE_). These keys are built into the public JavaScript bundle and sent to the browser.
  • Why It Happens: AI models choose the shortest path to verify that an API call works. Storing the key directly in a frontend-accessible variable satisfies that goal.
  • The Fix: Move the key to a backend environment variable. Route the client requests through your own backend API endpoint (e.g., app/api/openai/route.ts), which appends the key and forwards the request. If a key has already leaked, rotate it immediately in the provider's dashboard.

Gap 2: Supabase Row-Level Security (RLS) Disabled

  • The Issue: Database tables created with RLS turned off. Without RLS, anyone with your public anonymous database key can read, update, or delete any record in the table.
  • Why It Happens: RLS may be disabled by default depending on how tables are initialized, and AI generators assume you will configure database policies yourself.
  • The Fix: Run this SQL query in your database dashboard to find unprotected tables:
    SELECT tablename FROM pg_tables WHERE schemaname = 'public' AND rowsecurity = false;
    
    For each table, enable RLS and add a policy:
    ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
    
    CREATE POLICY "users read own posts" ON posts
    FOR SELECT USING (auth.uid() = user_id);
    

Gap 3: Missing JWT Verification on API Routes

  • The Issue: API endpoints that process user data (like fetching orders or updating profiles) without validating the caller's authentication token.
  • Why It Happens: AI generators build the data operation logic but often skip the request validation step unless explicitly instructed.
  • The Fix: Place an authorization guard at the top of every protected API route:
    const { data: { user } } = await supabase.auth.getUser()
    if (!user) return new Response('Unauthorized', { status: 401 })
    
    Ensure your queries use the verified user ID from the token, rather than relying on a user ID sent in the request body.

Gap 4: Client-Side Role Checks Only

  • The Issue: Relying entirely on conditional frontend rendering (e.g., {user.role === 'admin' && <AdminPanel />}) to restrict access to sensitive pages. While this hides the UI elements, it does not prevent unauthorized users from calling the underlying APIs directly.
  • Why It Happens: Conditional rendering is the default way to show or hide UI components in modern frameworks, and models apply it for access control without checking the backend.
  • The Fix: Enforce role checks directly in the API route before executing any database or system operations.

Gap 5: Rendering Unsanitized HTML

  • The Issue: Using methods like dangerouslySetInnerHTML or v-html to display user-supplied text (such as bio fields, comments, or markdown) without cleaning the input. This exposes your application to Cross-Site Scripting (XSS) attacks.
  • Why It Happens: Standard rendering methods do not parse markdown or custom formatting, leading models to recommend raw HTML insertion.
  • The Fix: Sanitize all dynamic HTML output using a library like DOMPurify:
    import DOMPurify from 'isomorphic-dompurify'
    <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(html) }} />
    

Gap 6: Uncapped LLM API Endpoints

  • The Issue: Exposing endpoints that trigger paid LLM calls without rate limiting or budget controls, leaving the application vulnerable to automated loops that inflate API costs.
  • Why It Happens: AI generators build the core functionality of the feature but do not include middleware or network-level limits.
  • The Fix:
    1. Set monthly hard spending limits directly within your LLM provider's dashboard (e.g., OpenAI's usage limits).
    2. Implement rate limiting on your API routes using tools like Vercel KV or Upstash Ratelimit.

Gap 7: Permissive CORS Configurations

  • The Issue: Setting API headers to Access-Control-Allow-Origin: * while enabling Access-Control-Allow-Credentials: true. This configuration allows external sites to perform authenticated requests on behalf of your users if cookie authentication is used.
  • Why It Happens: Developers and models often set wildcard values to resolve browser CORS errors quickly during development.
  • The Fix: Explicitly set the allowed origin to your production domain and local development URLs. Avoid using wildcards alongside credentials. If you are building a public API, use bearer tokens rather than cookie-based authentication.

Builder-Specific Security Notes

Hosted builders and scaffolding tools help automate deployment, but security responsibilities remain.

  • Lovable: While the environment variables are kept server-side automatically, tables generated by the platform do not always default to active RLS or custom role checks. Always run the RLS diagnostic query after a schema change.
  • Bolt: Bolt keeps secrets server-side by default in modern deployment paths, but code generation heavily utilizes client-side permissions logic. Ensure all API routes verify JWTs and roles server-side.
  • v0: v0 produces high-quality UI scaffolding. You must implement the backend authentication, database configuration, and API security measures manually. Run static analysis tools like Semgrep on your exported code before launching.

Pre-Flight Security Checklist

Run these five checks before every deploy that affects data, authentication, or billing:

  1. Secrets Check: Run gitleaks detect --no-banner to verify no keys are present in your git history.
  2. RLS Audit: Query your database to confirm that all public tables have Row-Level Security active.
  3. Route Protection: Search your codebase to ensure that every API route handling user data includes token verification.
  4. Endpoint Testing: Test your admin and protected endpoints via command line (curl) as an unauthenticated visitor to confirm they return HTTP 401 or 403 status codes.
  5. Spend Safeguards: Verify that your LLM billing limits are set to a manageable maximum cost.

FAQ

Are hosted app builders more secure than self-hosted frameworks?
Not necessarily. Hosted builders handle infrastructure setup and deployment pipelines, which avoids server misconfigurations. However, the application-level logic they produce requires the same verification and auditing as manually written code.

How often should I run these security audits?
Run automated secret scans on every commit or pull request. Perform a review of your API routes and database rules whenever you add new features that touch payments, authentication, or database schemas.

Do I need an enterprise security scanner?
Open-source tools like gitleaks and Semgrep CE are sufficient for basic security audits. As your application grows, handles regulated data, or prepares for compliance audits, you can transition to paid security tools.

Which vulnerability should be addressed first?
Exposed credentials. If an API key or database secret is committed to a public repository, it can be detected and exploited immediately. Rotate leaked credentials immediately.