← All guides

Bolt.new App Security Checklist Before You Launch

Updated 2026-10-14

Bolt.new can take you from a prompt to a working, deployed app in an afternoon. What it can't do is know which parts of your app are supposed to be private. That's on you, and it's worth an hour before you share the link.

This checklist is written for the typical Bolt stack: a Vite + React (or similar) frontend, a backend like Supabase, and a host such as Netlify or Bolt's own hosting. Work through it top to bottom.

Understand the shape of a Bolt app

Most Bolt apps are client-side apps. The code runs in your visitor's browser, and the browser talks directly to services like Supabase. That has two consequences:

  1. Anything in the frontend code, including environment variables, is public.
  2. Your backend's access rules are the real security boundary, not your UI.

Keep those two facts in mind and most of this checklist makes sense.

☐ 1. Check every VITE_ variable

Vite inlines any variable that starts with VITE_ into your JavaScript bundle at build time. Anyone can read it in their browser's dev tools.

Open your .env file and the Bolt project settings, and list every VITE_ variable. For each, ask: is this meant to be public?

Fine to expose:

Must never be VITE_:

If a secret is in a VITE_ variable, the fix is twofold: rotate the key, and move the code that uses it into a server-side function. See exposed keys in NEXT_PUBLIC_ and VITE_ and how to rotate leaked keys.

☐ 2. Search the code for hardcoded keys

Sometimes keys aren't in env vars at all. They're pasted straight into a file. Download or sync your project to GitHub and search:

grep -rnE "sk_live|sk_test|sk-[A-Za-z0-9]|service_role|sb_secret_" src supabase 2>/dev/null

If your Bolt project is connected to a GitHub repo, also check the history. Our guide on checking whether keys leaked on GitHub shows how with gitleaks.

☐ 3. Turn on RLS for every Supabase table

If your Bolt app uses Supabase, this is the most important item. The anon key in your frontend can query any table in the public schema. Row Level Security decides what it actually gets back.

Run this in the Supabase SQL editor:

select c.relname as table, c.relrowsecurity as rls_on
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
where c.relkind = 'r' and n.nspname = 'public'
order by rls_on;

Any table with rls_on = false is readable and writable by anyone with your anon key. Enable RLS and add owner-based policies. The Supabase RLS checklist walks through the policies step by step.

If you're on Firebase instead, the equivalent check is your Firestore rules. See Firebase security rules for AI-built apps.

☐ 4. Look for "allow everything" policies

When something fails with a permission error, AI tools often "fix" it by adding a policy like:

create policy "Enable read access for all users"
on public.profiles for select using (true);

That makes the error go away by making the table public. Search your migrations and the dashboard for using (true) and with check (true), and replace them with real conditions such as (select auth.uid()) = user_id.

☐ 5. Check that users can't edit privileged fields

If a profiles table has columns like role, is_admin, plan or credits, and users can update their own row, they can upgrade themselves. Try it: sign in, open the browser console, and run an update on your own profile setting plan to 'pro'. If it works, move those fields to a separate table that users can't write to, or revoke update on those columns.

☐ 6. Move secret work into server functions

Anything that needs a secret key has to run on a server. In a Bolt + Supabase app, that usually means a Supabase Edge Function. Store secrets with:

supabase secrets set OPENAI_API_KEY=sk-...

And read them inside the function with Deno.env.get("OPENAI_API_KEY").

Then make sure each function checks who's calling it:

// supabase/functions/generate/index.ts
import { createClient } from "jsr:@supabase/supabase-js@2";

Deno.serve(async (req) => {
  const authHeader = req.headers.get("Authorization");
  if (!authHeader) return new Response("Unauthorized", { status: 401 });

  const supabase = createClient(
    Deno.env.get("SUPABASE_URL")!,
    Deno.env.get("SUPABASE_ANON_KEY")!,
    { global: { headers: { Authorization: authHeader } } }
  );
  const { data: { user } } = await supabase.auth.getUser();
  if (!user) return new Response("Unauthorized", { status: 401 });

  // ... do the work for this user only
  return Response.json({ ok: true });
});

If your project uses Supabase's newer API keys, check the current docs for which env var names your functions receive. Functions that call paid APIs also need rate limits. The ideas in rate limiting OpenAI API routes apply directly.

☐ 7. Don't unlock paid features from the client

A common Bolt pattern: after Stripe Checkout, the user lands on /success, and the frontend sets isPro = true in the database. Anyone can visit /success or run that update themselves.

Paid access should only be granted by a server that has verified a Stripe webhook signature. See Stripe webhook signature verification in Next.js; the same verification works in an Edge Function using stripe.webhooks.constructEventAsync.

☐ 8. Check Storage buckets

If users upload files, check whether the bucket is public. Files in a public bucket can be downloaded by anyone with the URL. For private uploads, use a private bucket with per-user policies and signed URLs. Our Supabase Storage security guide covers the setup.

☐ 9. Review auth settings

In the Supabase dashboard under Authentication:

☐ 10. Update dependencies

Generated projects pin whatever versions were current when they were created. Run:

npm audit
npm outdated

Update anything with a known high-severity issue, then re-test your app.

☐ 11. Test as a stranger

Open a private browser window, don't log in, and try to:

curl "https://YOUR-PROJECT.supabase.co/rest/v1/profiles?select=*" \
  -H "apikey: YOUR_ANON_KEY"

Then log in as one test user and try to read another test user's data. Anything that works here will work for an attacker too.

Before you share the link

If you've ticked every box, you've covered the issues that most often bite apps built this way. For a wider list that covers monitoring and backups too, see the pre-launch security checklist for AI-built apps. Lovable users will find a similar walkthrough in is my Lovable app secure?.

PreflightPR can do a first pass for you. Connect your Bolt project to GitHub, then run a free scan on the public repo to check for exposed keys, tables without RLS, unprotected functions and webhook problems. It's an automated best-effort review, not a pen test, so keep the manual tests above too.

Check your repo in about a minute

Paste a public GitHub URL and get a free launch score.

Run a free scan

More guides