Guide: From Prototype to Production

Built with Lovable, Bolt or Replit: what is likely still open

Lovable, Bolt and Replit turn an idea into a running web application in a short amount of time, and for prototypes, vibe coding with these tools is a genuine win. Once real customer data and roles enter the picture, though, a handful of technical mechanisms decide whether the application holds up. These come with check steps that can be run directly, without outside help.

A glossy white device shell in cross-section, empty mounts and loose cables inside, lit orange from withinAI-GENERATED
UPDATED
12 September 2026
READING TIME
13 min

Short answer

Before putting a Lovable, Bolt or Replit app into production, six points are usually still open: row-level security in the database, secret keys in the frontend, missing migrations, access rights enforced only in the interface, logs containing personal data, and the portability of code and data. All six can be checked before launch.

01

What do Lovable, Bolt and Replit actually deliver, and where does that stop?

These tools turn natural-language descriptions into working web applications and take care of setup, hosting and often the database too. For prototypes and internal experiments, that is a genuine win. What stays open is whatever no prompt ever asked for: access rules, key management, schema versioning, logging and a way out of the platform.

According to its documentation, Lovable generates standard projects with Vite and React and relies on Supabase in the backend for the database, login, storage and server-side functions. Bolt projects can be downloaded as a ZIP, and Replit is a browser-based development environment. None of these points is a flaw unique to these tools: the same gaps appear in hand-written code too, just more slowly.

A preview answers whether the idea works, not whether the application can handle real customer data, multiple roles and access from outside. From prototype to a production-ready application covers the extra questions a production system raises. Covered here are the mechanisms worth checking first.

Where the open points come from
  1. 01PromptFunction gets described
  2. 02PreviewApplication runs visibly
  3. 03PublishPublic address
  4. 04Real usersReal data, real access
  5. 05OperationsChanges, updates, handover

02

What is row-level security, and why does the default matter so much?

Row-level security (RLS) is a PostgreSQL feature that decides, row by row, who can read or change which data. When browser code talks directly to a Supabase database, RLS is the actual access control. According to Supabase, if RLS is missing on a table in the public schema, anyone with the project address can read, change and delete there.

Many generated applications have no server of their own checking requests: the browser calls Supabase's database API directly and sends along a public key. Supabase calls this the Publishable Key (formerly anon) safe to expose in the frontend, but only because the database itself decides which rows the anon and authenticated roles can see. Grants govern whether a role may perform an operation at all, policies govern which rows that applies to.

The default depends on how the table was created

Tables created through the Supabase dashboard have RLS active by default. Tables created in the SQL editor or by other tools only get RLS once someone switches it on, and that is exactly how AI assistants work when they run schema changes as SQL. RLS with no policy returns no data at all through the API: that looks like a bug, but it is actually the safe state.

sql
-- Enable RLS for the table
alter table public.orders enable row level security;

-- Authenticated users read only their own orders
create policy "Read own orders"
on public.orders for select to authenticated
using ( (select auth.uid()) = user_id );

-- New rows can only be created in the user's own name
create policy "Create own orders"
on public.orders for insert to authenticated
with check ( (select auth.uid()) = user_id );
Switching on RLS and exposing only a user's own rows (example table with a user_id column)

03

How can RLS be checked directly in a project?

The fastest route is the Security Advisor in the Supabase dashboard, which flags tables with no RLS and policies that are too permissive. Two SQL queries and an outside test help after that: if rows come back using the public key with no login that an outsider should never see, the table is exposed.

  1. Run the Security Advisor

    From the dashboard or with supabase db advisors. The main ones to watch are rls_disabled_in_public, policy_exists_rls_disabled and permissive_rls_policy.

  2. Query the system catalogues

    The SQL queries here show RLS status and policies. Every table with rowsecurity = false needs a justification, and every policy needs a business rule behind it.

  3. Test from outside

    Query a table with the public key and no login, only against an organisation's own project. [] means either RLS is working or the table is empty.

  4. Cross-test with two accounts

    Try to read or change someone else's records using two test accounts. Only this shows whether the policies actually reflect the business rule.

sql
-- Which tables in the public schema have no RLS?
select schemaname, tablename, rowsecurity
from pg_tables
where schemaname = 'public'
order by rowsecurity, tablename;

-- Which policies exist, for which roles and operations?
select tablename, policyname, cmd, roles, qual, with_check
from pg_policies
where schemaname = 'public'
order by tablename, policyname;
System catalogues: RLS status and existing policies
bash
# Run only against an organisation's own project
curl 'https://<PROJECT_REF>.supabase.co/rest/v1/<table>?select=*' \
  -H "apikey: <PUBLISHABLE_KEY>"
Testing from outside with the public key

Checklist

RLS checklist before launch

0 of5

Tick off what can be demonstrated.

04

What happened in CVE-2025-48757?

The NVD entry describes insufficient row-level security policies in Lovable up to 15 April 2025, which let unauthenticated remote attackers read and write arbitrary database tables of generated sites. The entry is rated critical under CVSS 3.1, and the vendor disputes the vulnerability.

According to the disclosure, the generated frontends called the database API directly with the public anon key and relied on RLS alone. Where policies were missing or too broad, a modified request from the browser was enough. An automated scan on 21 March 2025 examined 1,645 Lovable projects this way, and 170 of them returned data (disclosure statement, 2025). Names, email addresses, API keys for third-party services and payment status are all named as exposed.

9.3CVSS 3.1 base score, rated criticalNVD, 2025
1,645Lovable projects examined by the automated scanDisclosure statement, 2025
170projects with retrievable data, about 10.3%Disclosure statement, 2025
303affected endpoints across these projectsDisclosure statement, 2025
Timeline per the disclosure and the CVE entry
  1. Discovery

    The missing policies were found, according to the disclosure.

  2. Reported to Lovable

    The scan across 1,645 projects ran the same day.

  3. Cut-off date in the CVE entry

    Lovable is named as affected up to this date.

  4. Disclosure

    The details become public.

  5. CVE published

    Entry recorded in the CVE Program and the NVD.

  6. Today

What belongs in a fair reading of this

  • The CVE entry notes that Lovable disputes the vulnerability: responsibility for protecting application data, it says, lies with customers.
  • The disclosure states it came from an employee of Replit, a vendor in the same segment. That does not make the numbers wrong, but it belongs in the context.
  • Lovable now runs a basic scan with RLS linting on publish, and a deeper scan is available on request. Its own documentation says these tools cannot guarantee complete security.

05

Are secret keys sitting in the frontend?

Anything that reaches the browser can be read by any visitor, even inside minified JavaScript. Public keys such as Supabase's Publishable Key are meant for exactly that. Secret keys for the database, for language models, or for payment or mail services, on the other hand, belong exclusively in server-side functions with a stored secret.

A Supabase Secret Key (sb_secret_..., formerly service_role) bypasses every RLS policy, and Supabase now rejects it in the browser with HTTP 401. Keys for other services have no such protection. The typical route into the frontend is environment variables: in Vite projects, Lovable included, anything with the VITE_ prefix ends up in the shipped code. A VITE_OPENAI_API_KEY is therefore public information.

  1. Search the loaded scripts under 'Sources' in the browser's developer tools for sb_secret_, service_role, sk- and Bearer.
  2. Search the repository and its history with the commands shown here: a key that was ever committed stays readable in old commits.
  3. Check the 'Network' tab for which services the browser calls directly using a secret key.
bash
# Current state of the repository
git grep -n -I -E "sb_secret_|service_role|sk-[A-Za-z0-9]{10,}|VITE_[A-Z0-9_]*(SECRET|TOKEN|PRIVATE)"

# Full history of every branch, deleted files included
git log --all -p | grep -n -E "sb_secret_|service_role|sk-[A-Za-z0-9]{10,}"
Searching a local clone for typical key patterns

06

Why are migrations often missing, and how can that be spotted?

Migrations are versioned SQL files that record every schema change. When the schema gets changed directly in the dashboard or by a tool, the current state only exists in the running database: no identical test environment, no clean way to roll back. Whether the supabase/migrations folder exists and fully describes the database is the way to check.

Supabase recommends running every schema change, even small ones, through migration files rather than directly through the dashboard or the SQL editor, and it records applied migrations in supabase_migrations.schema_migrations. In prototypes, the opposite has often happened: tables created in conversation with an assistant, columns added through the dashboard, a policy loosened for troubleshooting.

bash
supabase link --project-ref <PROJECT_REF>
supabase db pull                          # save today's schema as the baseline migration
supabase db diff -f dashboard_changes     # capture changes made in the dashboard
supabase migration new rls_orders         # create a new, empty migration file
supabase db reset                         # apply every migration locally from scratch
supabase db push                          # apply the migrations to the remote project
Bringing an existing schema into migrations after the fact (Supabase CLI)

Self-test: does supabase db reset build a schema locally from the migrations that matches production? If not, the history is incomplete. Recognising technical debt in AI-generated code describes the long-term consequences.

07

Is access control implemented only in the interface?

The question is whether the code merely hides buttons and pages while never checking the role where the data actually lives. Anyone who rebuilds the request in the browser bypasses the interface entirely. Access control only becomes effective once the database or server enforces it on every request, no matter where that request comes from.

Where does the access decision get made?

CriterionOnly in the interfaceIn the database or server
EffectA button gets hiddenThe request gets rejected
Direct API callstill worksgets checked all the same
The role lives inmetadata a user can editits own table with no write access

With Supabase, policies based on user_metadata can be bypassed because users can edit that metadata themselves; the advisor flags this as rls_references_user_metadata. Roles belong in a table of their own.

sql
create table public.roles (
  user_id uuid primary key references auth.users (id) on delete cascade,
  role text not null check (role in ('admin', 'staff'))
);
alter table public.roles enable row level security;

-- Users read only their own role; with no write policy, nobody can grant roles via the API
create policy "Read own role"
on public.roles for select to authenticated
using ( (select auth.uid()) = user_id );

-- Only administrators see invoices
create policy "Admins read invoices"
on public.invoices for select to authenticated
using (
  exists (
    select 1 from public.roles r
    where r.user_id = (select auth.uid())
      and r.role = 'admin'
  )
);
Roles in their own table, checked in the policy (example)

Self-test: using an account with no special rights, copy a data request from the 'Network' tab and change the identifier, for example id=eq.124 instead of id=eq.123, or query a table meant to be visible only to administrators. If data comes back, the access control is only for show.

08

What ends up in the logs?

While building, output such as console.log(user) helps with debugging. Once published, it ends up in every visitor's browser console or in the platform's function logs, email addresses, tokens and form contents included. Logs are meant to make events traceable, not to collect personal data, and that can be checked before launch.

Everyone can see browser output, and it reveals table names that make an attack easier. Server logs can end up readable by more people than the actual data itself, and they follow their own retention rules.

What belongs in a log

CriterionDoes not belong thereBelongs there
IdentityNames, email addressesA pseudonymous identifier
AccessPasswords, tokens, API keysAn event, such as a failed login
ContentFull requests, free-text form fields, prompts containing personal dataResult, error code, request identifier
bash
git grep -n -E "console\.(log|debug|info)\(" -- src supabase/functions
Finding logging statements in the source code

GDPR-compliant AI covers the data protection side of this.

09

Can code and data actually be taken elsewhere?

For code, yes: Lovable syncs with GitHub, and Bolt and Replit both offer a ZIP download. Data, secrets and platform services such as login, file storage and server-side functions are harder. Testing the move while nothing is urgent, rather than only once pricing, terms or requirements change, is the safer order.

Export options per vendor documentation

CriterionLovableBoltReplit
CodeTwo-way GitHub sync; download available on paid plansExport as a ZIPDownload as a ZIP; Git integration
DatabaseSupabase; moving to a self-managed Supabase project is supportedBolt Database: duplicating carries over structure only, no datanot included when a project is copied
LimitsPlain PostgreSQL needs a replacement for login, storage and edge functionsGitHub and Netlify settings do not carry over when duplicatingSecrets and deployment configuration are missing from a copy

Checklist

Testing portability while nothing is urgent

0 of5

10

In what order should these points get tackled?

First, whatever could already expose data today: RLS and secret keys. Migrations and access control follow, because every later change builds on them. Logs and portability come next, before operations begin. The decision guide walks through the questions and shows what is worth discussing next.

Decision path

Is the application ready for real data?

Answer based on what can actually be demonstrated.

    All questions and results as a list
    • Does the application store personal or business data?
      • Yes, continue with: Is RLS active everywhere, and has the cross-test with two accounts passed?
      • No, demo content only, Result: Continue as a prototype
    • Is RLS active everywhere, and has the cross-test with two accounts passed?
      • Yes, demonstrated, continue with: Are the frontend and the Git history free of secret keys?
      • No or untested, Result: Close down the database first
    • Are the frontend and the Git history free of secret keys?
      • Yes, searched, continue with: Does the schema build completely from migrations?
      • No or unchecked, Result: Revoke and relocate the keys
    • Does the schema build completely from migrations?
      • Yes, continue with: Do the database or server enforce every role?
      • No, Result: Bring the schema into migrations
    • Do the database or server enforce every role?
      • Yes, Result: Ready for the next step
      • No or unclear, Result: Move access control into the database
    • Result: Continue as a prototypeWorth discussing: at what point real data starts flowing, and who triggers this check when it does.
    • Result: Close down the database firstWorth discussing: which tables hold which data, which rule each policy reflects, and whether data has already been accessed.
    • Result: Revoke and relocate the keysWorth discussing: which keys are affected and which calls need to move to the server.
    • Result: Bring the schema into migrationsWorth discussing: capturing the current state as a baseline migration, building a test environment from it, and rolling out changes only through files from then on.
    • Result: Move access control into the databaseWorth discussing: which role model the application needs and how an API test covers every role.
    • Result: Ready for the next stepWorth discussing: logging, portability, monitoring, backups and who takes ownership going forward.

    Where IT needs to take over a department-built application, A department built an app helps. What studies show about the quality of AI-generated code summarises what these investigations into generated code actually measure.

    Who is liable when AI-generated code causes damage? covers liability questions. iiterate Technologies GmbH, based in Adenau, develops custom software and AI applications from architecture through implementation to operations, on a client's own infrastructure or in EU hosting, and hands over source code and documentation. To talk about an application: Contact.

    Frequently asked questions

    Is vibe coding with Lovable, Bolt or Replit unsuitable for organisations?

    No. For prototypes, internal experiments and clarifying requirements, these tools are well suited and save real time. What matters is the transition: once personal data, roles or payments enter the picture, the application needs the same checks as any other software. The points covered here are a starting point, not a substitute for a security review.

    Is the public Supabase key in the frontend a security problem?

    Not on its own. Supabase describes the Publishable Key, formerly anon, as safe for browsers and apps. But it is only as secure as the row-level security policies behind it, since anyone can call the database API with it. Any secret key in the frontend is a problem, in Supabase's case the Secret Key or service_role, because it bypasses every policy.

    Can a Lovable app run on an organisation's own servers?

    According to the vendor's documentation, yes. The code can be synced through GitHub, cloned and run independently, the frontend on any infrastructure, the backend on managed or self-hosted Supabase. The limit sits at the platform services: doing without Supabase entirely means building a replacement for login, file storage and server-side functions.

    Do these points also apply to Bolt and Replit?

    Yes, wherever the application uses the same architecture. If a Bolt or Replit project calls Supabase directly from the browser, RLS and key separation apply in exactly the same way. If the logic runs on a dedicated server instead, the check shifts there, and the server has to authorise every request itself. Logging, migrations and portability apply to every application regardless.

    Read on

    Sources

    1. 01 CVE-2025-48757 Detail National Vulnerability Database (NIST), 2025 · nvd.nist.gov
    2. 02 CVE Record CVE-2025-48757 CVE Program, 2025 · cve.org
    3. 03 CVE-2025-48757 Primäre Offenlegung, 2025 · mattpalmer.io
    4. 04 Statement on CVE-2025-48757 Primäre Offenlegung, 2025 · mattpalmer.io
    5. 05 Row Level Security Supabase Docs, 2026 · supabase.com
    6. 06 Securing your API Supabase Docs, 2026 · supabase.com
    7. 07 Understanding API keys Supabase Docs, 2026 · supabase.com
    8. 08 Database Advisors Supabase Docs, 2026 · supabase.com
    9. 09 Database Migrations Supabase Docs, 2026 · supabase.com
    10. 10 Build your first API Supabase Docs, 2026 · supabase.com
    11. 11 The pg_tables view PostgreSQL Documentation, 2026 · postgresql.org
    12. 12 Env Variables and Modes Vite, 2026 · vite.dev
    13. 13 Security overview Lovable Documentation, 2026 · docs.lovable.dev
    14. 14 GitHub integration Lovable Documentation, 2026 · docs.lovable.dev
    15. 15 Deployment, hosting, and ownership options Lovable Documentation, 2026 · docs.lovable.dev
    16. 16 Manage your projects Bolt Help Center, 2026 · support.bolt.new
    17. 17 Projects and files Replit Docs, 2026 · docs.replit.com

    Let us talk about your project

    Whether it is a prototype, an internal tool or an AI application: describe briefly what you are building or want to take into production.

    Arthur C. Clarke

    “Any sufficiently advanced technology is indistinguishable from magic.”