Pre-launch check
Start hereFor founders about to let real users in.
$490
- Keys and secrets in the browser or repo
- Who can read and change whose data
- Login, roles and admin routes
- Errors, retries and rate limits
- Debug mode, headers, deploy path
The Expo docs treat everything shipped in the client bundle as public; secret handling belongs in API routes or another server.
Expo is a React Native framework for Android, iOS and web, with EAS for builds, updates and environment variables. Variables prefixed EXPO_PUBLIC_ are inlined into the app bundle; everything in the bundle can be read from the installed app.
Mobile apps add three questions to the web list. What is inside the shipped bundle. Whether network traffic is pinned to your servers where it matters. What happens to local data when the device is offline and comes back. The patterns here cover those plus the backend's own rules.
Each row is taken from the vendor's documentation on the date shown. Defaults change; the date is the claim.
| Area | Default | Source |
|---|---|---|
| EXPO_PUBLIC_ env exposure | Expo CLI loads EXPO_PUBLIC_ variables from .env files and Metro inlines them into the client JavaScript bundle. The docs say not to store private keys in them because they are visible in plain text in the compiled app. | docs · verified 2026-09-21 |
| Secrets in bundle | EAS secret-type variables are not readable outside EAS servers, but the docs state they provide no additional security for values you embed in the app; anything in client-side code should be considered public. | docs · verified 2026-09-21 |
| EAS variable visibility levels | Plain text (visible everywhere), Sensitive (obfuscated in logs, toggle to view on the website) and Secret (not readable outside EAS servers); available to EAS Build, Workflows, Update and Hosting. | docs · verified 2026-09-21 |
| Server-side code | Expo Router API routes run on a server, isolated from client code, and can read all environment variables; they require web.output server (or static with the apiRoutes plugin) and a host such as EAS Hosting. | docs · verified 2026-09-21 |
| On-device storage | expo-secure-store encrypts key-value pairs with Android Keystore and iOS keychain; not available on web, and some iOS releases rejected values above roughly 2048 bytes. | docs · verified 2026-09-21 |
Documentation home: docs.expo.dev
15 patterns in the catalogue name Expo; the most severe are listed here across secrets and keys, data access, login and permissions, ai features, mobile, payments, reliability, deploy and config, performance. Attribution is descriptive: the default stack makes the pattern reachable, or a public incident names it.
Everyone who can see the repository, now or later, holds working keys to the database, payment account and model provider, and the keys stay in history after the file is deleted.
Anyone who changes the id in a URL or request can read, edit or delete another customer's record.
Anyone who calls the API directly, or edits the page in developer tools, gets the data and actions the screen was hiding.
Anyone who views the page source can copy the key and run their own workloads on your account until the bill or the provider stops them.
Anyone who downloads the app from the store can unzip it and read the key, then run up your bill or read your database as an administrator.
Anyone who views the page source can take the key and run up charges, send messages or pull data on your account until the key is revoked.
Anyone can type one line in the browser console to become a paying customer, and the server hands over the paid feature without checking.
A script can try thousands of passwords against your login form, hammer a form that sends emails or calls a paid API, or knock the app over, and the bill lands on you.
A published advisory is a public instruction sheet, so an attacker does not need to find a flaw in your code; they only need to know which library version you run.
Users lose edits they watched themselves save, records end up half-updated, and nobody can tell which copy of the data is the real one.
When a request fails, users see a spinner that never ends or an empty list, assume the app is broken or their data is gone, and nobody on your side hears about it.
One outage turns into a flood of retries from every open browser tab, which keeps the service down longer, runs up usage bills and can submit the same order or payment twice.
As the table grows, the response gets slower and heavier until it hits a platform body-size or time limit and the page simply stops loading, usually for your biggest customer first.
Every user's device downloads far more than it shows, so pages slow down as the table grows, and if the database does not also restrict rows, other people's records land in the browser.
Someone who can put a certificate on a phone, for example on a shared or managed device or a rooted one, can read and alter everything the app sends, including login tokens.
Lovable reported that from 3 February to 20 April 2026 a backend regression let any logged-in Lovable user read the chat history and source code of public projects; a fix shipped within two hours.
Apr 2026 · Lovable · all sources
One education app built on Lovable had 16 vulnerabilities, 6 critical; a database function denied callers whose role was 'authenticated', so anonymous callers passed and 18,697 user records were readable without login.
Feb 2026 · Taimur Khan · all sources
On the Base44 app builder, undocumented registration and one-time-password endpoints accepted a non-secret app_id, so anyone could create a verified account on a private app; Wix fixed it within 24 hours.
Jul 2025 · Wiz Research · all sources
Two days after announcing a SaaS built with Cursor and no hand-written code, its founder reported subscription bypasses, maxed-out API keys and unwanted database writes; he shut the app down three days later.
Mar 2025 · Leo (Enrichlead founder) · all sources
Each entry links to its primary source in the evidence list. What to do about it is the self-check below.
Stated from the vendor's documentation. The limits are the vendor's scope statements, not judgements.
EAS secret environment variables
Secret visibility keeps values off the website, EAS CLI and job logs, for use during builds and workflows.
Where it stops: The docs state secrets do not protect values that end up embedded in the application itself.
vendor docs · verified 2026-09-21
API routes
Sensitive data in +api.ts files is excluded from the client bundle even if imported elsewhere in the app directory; unsupported methods return 405.
Where it stops: Production use requires deploying the server (EAS Hosting or a third party); the route's own authorization is the app's code.
vendor docs · verified 2026-09-21
expo-secure-store
Encrypted on-device storage backed by Keystore and keychain, with an optional biometric requireAuthentication flag.
Where it stops: Data protected with requireAuthentication becomes inaccessible after biometric changes; Android entries are lost on uninstall and cannot be restored from Auto Backup.
vendor docs · verified 2026-09-21
The critical patterns first. Each uses the dashboard and your browser.
.env, .env.local, .env.production, serviceAccountKey.json or firebase-adminsdk files.sk_live, sk-, service_role, BEGIN PRIVATE KEY and password=.git log --all -p -S sk_live -- . | head. Any output means a live key has been committed at some point.A bad result is account A's record appearing for account B, or an edit or delete going through.
A bad result is a full response where you expected an HTTP 401 or HTTP 403 error.
Expo pre-launch checklist
15 checks, in the order we run them. Usable without buying anything.
Self-check tool
Answer questions about your setup and get the patterns that apply, ordered by severity. Runs in your browser; nothing is sent.
For founders about to let real users in.
$490
For teams and startups who need a document, not just a list.
$1,900
All packages and prices. Every report includes a re-check after your fixes.
No secrets in EXPO_PUBLIC_ variables or code, secrets read from a server you control, backend rules tested with two accounts, certificate pinning where the data warrants it, offline writes that reconcile safely, and dependency updates. Each item maps to a pattern on this page.
Expo's docs state EXPO_PUBLIC_ variables are embedded in the bundle. Anything with that prefix is readable from the installed app; treat it as public and move secrets behind your own API.
We unpack the built app to read what ships, test the backend it talks to with two accounts, check transport settings, and test offline behaviour on a device. Findings include the file or setting to change.