AI-coded apps

    Bolt.new: Is the database connection secure on mobile?

    A founder reviewing a Bolt.new generated Expo mobile project alongside the Supabase dashboard, checking which API key shipped in the bundle and whether Row Level Security policies are configured on each table before App Store submission

    When a developer asks Bolt.new to build a mobile app with a database, the model usually wires Expo to Supabase. Whether that database connection is safe to ship depends less on Bolt.new and more on which Supabase key ends up in the bundle, whether Row Level Security is configured on each table, and how the app stores the session on the device.

    Short answer

    The Bolt.new generated mobile database connection is reasonably safe only when three conditions hold: the publishable (or anon) key is the one shipped in the bundle, every Supabase table has Row Level Security enabled with a policy tighter than using (true), and the secret key (or legacy service role key) lives in an Edge Function rather than the client. Per Supabase's API keys documentation, secret keys bypass Row Level Security and must never reach a mobile bundle.

    What you should know

    • Bolt.new ships Expo for mobile. Bolt.new's Expo integration generates a React Native source tree that calls Supabase from the client.
    • Two keys, two destinations. The publishable (or anon) key is designed to ship to the client; the secret (or service role) key must stay on the server.
    • RLS is the real perimeter. A publishable key with no Row Level Security policy is the same as a public database.
    • Storage sits on the device too. Supabase's Expo quickstart writes the session to localStorage by default, not iOS Keychain or Android Keystore.
    • Store review still applies. OWASP MASVS-NETWORK and MASVS-STORAGE controls are evaluated against the compiled IPA or AAB regardless of how the source was generated.

    How does Bolt.new actually connect a mobile app to a database?

    Bolt.new's Expo integration generates a Metro powered React Native project and offers Supabase as the default backend. The model typically writes a lib/supabase.ts file that initializes the Supabase client with two values: the project URL and a publishable or anon key. Both are read from environment variables prefixed EXPO_PUBLIC_, which Expo inlines into the JavaScript bundle at build time.

    Per Supabase's Expo React Native quickstart, the recommended client configuration uses autoRefreshToken: true, persistSession: true, and detectSessionInUrl: false. Storage for the session is set to localStorage, which on Expo is a polyfill backed by AsyncStorage on a real device.

    The pattern itself is the standard Supabase Expo flow. The questions worth asking are which key Bolt.new actually picked, whether the tables behind that key have policies, and where the session token sits on the device.

    Which Supabase key ends up in the Bolt.new mobile bundle?

    The honest answer is: usually the publishable or anon key, but not always. Per the same Supabase API keys documentation, publishable keys (prefix sb_publishable_) and the legacy anon JWT are explicitly safe to ship in mobile or browser bundles. They operate through the anon and authenticated Postgres roles, both subject to Row Level Security.

    The secret keys (prefix sb_secret_) and the legacy service role key are a different category. Supabase states plainly that these keys should not be added to web pages, public documents, source code, or bundled into executables for mobile, desktop, or CLI apps. They use the service_role Postgres role with the BYPASSRLS attribute, which reads and writes every row in every table.

    The risk inside Bolt.new is prompt driven. When a developer asks the model to send an admin email, delete a user from the database, or run a server side cron, the model sometimes reaches for the service role key because it makes the immediate task work without authentication scaffolding. If that key gets written into a client file, even behind an EXPO_PUBLIC_ prefix, it ships to every install of the app. Extracting it later requires nothing more than unpacking the APK or IPA with apktool or a standard binary inspection.

    Public audits of Lovable, a similar AI builder that also defaults to Supabase, found that around 34 percent of sampled apps shipped the service role key in the browser bundle (per the 2025 dev.to audit of 50 Lovable apps). Bolt.new does not have an equivalent published audit, but the same prompt patterns produce the same outcomes.

    Is Row Level Security actually enabled on Bolt.new generated tables?

    Bolt.new can ask Supabase to create tables on the developer's behalf through its integration. The default behaviour depends on which migration Bolt.new wrote and whether the developer accepted it without reading. In practice, three patterns appear:

    1. A table with RLS disabled (the worst case; every row readable through the anon key).
    2. A table with RLS enabled and a single policy of using (true), which passes the rowsecurity flag check while being functionally equivalent to no policy at all.
    3. A table with RLS enabled and a per-row policy keyed to auth.uid(), which is what production code should look like.

    Per Supabase's Row Level Security guide, enabling RLS without any policy blocks all access through the anon key, which is the safest default. Bolt.new generated migrations sometimes add a permissive policy in the same change set, which removes that protection.

    The verification is one query in the Supabase dashboard SQL editor: select tablename, rowsecurity from pg_tables where schemaname = 'public'; paired with a read of pg_policies. Anything with rowsecurity = false, or with a policy qual of true, is reachable by any installed copy of the mobile app.

    Where does the session token live on the device?

    The Supabase Expo quickstart configures the client with storage: localStorage. Under Expo, the polyfill writes to AsyncStorage, which on iOS lands in the app sandbox under NSUserDefaults and on Android in unencrypted shared preferences. The session JWT therefore sits on disk in plaintext until the user signs out.

    For a typical low risk app this is acceptable, because access requires the device passcode and the app sandbox. For a fintech, health, or identity app it does not meet OWASP MASVS-STORAGE-2, per the OWASP MAS Project, which expects sensitive credentials to be stored in the platform secure store (iOS Keychain, Android Keystore). The fix is to swap AsyncStorage for expo-secure-store in the Supabase client configuration. Bolt.new does not make this swap by default.

    Here is how the database connection surfaces compare on a typical Bolt.new generated mobile app, before any hardening:

    SurfaceBolt.new defaultProduction target
    Key shipped in bundlePublishable or anon (usually correct)Publishable or anon only
    Service role key locationSometimes inlined behind EXPO_PUBLIC_ if promptedEdge Function or server only
    RLS on tablesOften disabled or using (true)RLS on, per-row policies keyed to auth.uid()
    Session storageAsyncStorage (plaintext on disk)expo-secure-store for sensitive apps
    Network transportHTTPS to *.supabase.co (correct)HTTPS, optionally with certificate pinning
    Edge Function gateRarely used unless promptedUsed for any privileged action
    Pre publish security scanNone inside Bolt.newOWASP MASTG aligned scan of the binary

    The transport question is the only one Bolt.new gets right by default. Supabase endpoints are HTTPS only, so a generated client cannot accidentally talk to Postgres over plaintext.

    What does this mean for App Store and Google Play submission?

    App Review does not inspect the source code; it inspects the compiled binary. A Bolt.new generated Expo project that ships through EAS Build lands in App Store Connect as a regular IPA, judged by the same static and dynamic checks any native build sees. Apple's automated layer pulls out strings that look like secrets and flags entitlements that look misaligned with the binary's actual behaviour.

    Google Play applies its target API and Data Safety policies to the AAB. Per Google Play Console help on Data Safety, every SDK that handles user data has to be declared on the Data Safety form. The Supabase client is one such SDK; the requests it generates carry user identifiers and authentication tokens, both of which need to be reflected on the form.

    For builders who want an independent automated read of the compiled APK, AAB, or IPA before submission, PTKD.com (https://ptkd.com) is one of the platforms focused specifically on pre submission scanning aligned with OWASP MASVS for AI generated and no code mobile builds. The Bolt.new IDE shows the source; a scan of the compiled binary covers what App Review and Play Protect actually see.

    What to watch out for

    The first myth worth ejecting is that EXPO_PUBLIC_ is somehow a security marker. The prefix only tells Expo to inline the variable into the client bundle. Anything behind it is published the moment the app is. A service role key with that prefix is a service role key in the wild.

    The second pitfall is the assumption that RLS being enabled means RLS is configured. Per the Supabase documentation, the pg_tables.rowsecurity = true flag without a meaningful policy is satisfied by using (true), which lets every row through. Treat the policy list as the source of truth, not the enable flag.

    The third pitfall is that the Supabase Expo quickstart's default storage is not appropriate for a regulated app. AsyncStorage is fine for a marketing app or a personal project. For anything that touches financial accounts, health records, or identity documents, the session belongs in expo-secure-store, and the threat model sits in MASVS-STORAGE-2 territory rather than convenience.

    Key takeaways

    • A Bolt.new generated mobile database connection is safe to ship only when the publishable key is in the bundle, every table has RLS with a meaningful policy, and the service role key lives in an Edge Function.
    • Verifying which Supabase key Bolt.new actually wrote into the client file is the single highest value check before submission.
    • AsyncStorage backed session storage is acceptable for low risk apps and not appropriate for fintech, health, or identity builds; switch to expo-secure-store for those categories.
    • For a binary level audit aligned with OWASP MASVS before submission to App Store Connect or Google Play, PTKD.com (https://ptkd.com) runs pre submission scans on the compiled APK, AAB, or IPA.
    • Bolt.new is not currently a security gate; the developer's prompts and a post generation review decide whether the database connection is production safe.
    • #bolt.new
    • #supabase
    • #expo
    • #react native
    • #row level security
    • #mobile security
    • #ai-coded apps

    Frequently asked questions

    Does Bolt.new put the Supabase service role key in my mobile bundle?
    Not by default, but a prompt asking for an admin action can lead the model to wire the service role key into a client file behind an EXPO_PUBLIC_ prefix. Anything with that prefix is inlined into the JavaScript bundle by Expo at build time, which means a compiled IPA or APK will carry it. Per Supabase's API key documentation, secret keys must never ship to mobile apps because they bypass Row Level Security.
    Is the anon key safe to ship in a Bolt.new Expo app?
    Yes, the anon key and the newer publishable key are designed for client distribution. Supabase's documentation lists mobile, desktop, and CLI bundles as approved locations for these keys. The actual perimeter is the Row Level Security policy attached to each table; with permissive policies the anon key still reads every row. Verify that each table has RLS enabled and a policy keyed to auth.uid().
    Where does Bolt.new store my Supabase session on the device?
    The Supabase Expo quickstart that Bolt.new follows configures the client with localStorage, which on Expo falls back to AsyncStorage. On iOS that lands in the app sandbox under NSUserDefaults and on Android in unencrypted shared preferences. For fintech, health, or identity apps this fails OWASP MASVS-STORAGE-2 and the storage should be swapped for expo-secure-store, which uses the Keychain on iOS and the Keystore on Android.
    Does App Review check whether my Bolt.new database connection is secure?
    App Review does not audit the Supabase configuration, but the automated layer in App Store Connect does scan the compiled binary for strings that look like leaked secrets and for entitlements that are misaligned with the binary. Google Play applies its Data Safety policy to the AAB. Neither store will catch a missing RLS policy on a Supabase table, which is why a separate pre submission scan is the practical fallback.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free