Node2Shell (CVE-2026-111497) affects Node.js: read how to fix it

Guides

Is my Bolt app secure?

Written by our founder, a cybersecurity architect · Updated

Short answer

Not automatically. Bolt builds a working app quickly, usually a React frontend built with Vite that talks to Supabase or another backend straight from the browser. Whether it is secure depends on a few things Bolt can get wrong: which keys reach the browser, what your database lets a visitor read, and whether your server functions check who is calling.

The most common problem is a secret key (OpenAI, Stripe, Supabase service_role) stored in a VITE_ variable or written into a component. Vite copies it into the JavaScript every visitor downloads.

The checklist below goes through what to check, in order of how much damage each mistake does.

Why do Bolt apps leak keys?

When you ask Bolt for a feature that calls OpenAI or Stripe, the quickest version that works calls the API from the frontend, with the key in a VITE_ variable. It works in the preview, and once deployed it hands the key to every visitor.

The second cause is the database. With Supabase, the browser talks to your tables directly, so the only thing standing between a visitor and your data is Row Level Security (RLS).

1. Are secret keys kept out of the frontend?

Open your .env file and look at every variable that starts with VITE_. Only values meant to be public belong there, such as your Supabase URL and anon key. Anything else moves to server code:

  • A Supabase Edge Function, with the key stored in Edge Function secrets.
  • A serverless function on your host, such as Netlify Functions, with the key in the host’s environment variables without the VITE_ prefix.

If a secret was ever in your frontend, rotate it: deleting the line doesn’t remove it from old builds. Our guide on finding API keys in your JavaScript shows how to search the live site and the build.

2. Is RLS on for every Supabase table?

Run this in the Supabase SQL editor. Any table with false can be read and changed by anyone who has the anon key your site ships:

SQL editor
select tablename, rowsecurity as rls_enabled
from pg_tables
where schemaname = 'public'
order by rowsecurity, tablename;

Then check what each policy allows, and test a table with only the anon key from a terminal. Our Supabase RLS guide walks through both.

3. Do your server functions check the user?

  • Read the signed-in user from the request and refuse the call if there is none.
  • When a function takes an id (an order, a document), check that the record belongs to that user.
  • Functions that call an AI model cost you money on every call. Require a signed-in user and set a limit per user.
  • Compute prices on the server from your own product list, and verify the signature of Stripe webhooks.

4. Is your .env file kept private?

Vite serves everything in the public/ folder as is, so a .env or backup file placed there can be downloaded by anyone. If you export your project to GitHub, check that .env is listed in .gitignore before the first push.

5. What does your live site expose?

Finally, look at the deployed site the way a stranger would: keys inside the JavaScript, source maps that reveal your source code, files like .env left public, and missing security headers.

Our free scan checks those in about a minute, with no account. It doesn’t test your database or your logins: Supabase tables readable without an account are checked by our backend checks after you prove you own the site, once a month on the free plan and weekly on Pro.

Checklist

  • Only public values (Supabase URL, anon key, Stripe pk_) are in VITE_ variables
  • OpenAI, Stripe secret and Supabase service_role keys are only in server functions
  • Keys that were ever in the frontend have been rotated
  • RLS is on for every table in public
  • Policies check ownership, not just “signed in”
  • Server functions check the user and limit AI calls
  • Prices are computed on the server; Stripe webhooks are verified
  • No .env or backup file in public/ or in Git

Scan your site for free

Leaked API keys, exposed files and missing security headers, with a fix for each. No account, about a minute.

Free, no signup needed

Questions

Are VITE_ environment variables secret?
No. Every variable starting with VITE_ is copied into the JavaScript the browser downloads. Use them only for values meant to be public, like your Supabase URL and anon key.
Where should I put my OpenAI key in a Bolt app?
In server code: a Supabase Edge Function secret, or your host’s environment variables without the VITE_ prefix. The frontend calls your function, and only the function calls OpenAI.
Is the Supabase anon key in my Bolt app a problem?
No, it is public by design. It only gives the access your Row Level Security policies allow, so the policies are what you need to check.
Can I scan my Bolt app for free?
Yes. Paste its live address into our free scan to check for leaked keys, exposed files and missing security headers, with a fix for each issue. It doesn’t test logins or your database rules.

Related guides

Is my Bolt app secure? · Afterprompt