Pre-launch security review for vibe-coded apps
Six checks to run before you submit a vibe-coded app. Each one ends as detected, unknown or confirmed by owner evidence.
Published Last updated
Review a vibe-coded app in this order: the keys that ship inside it, the database rules, the server check on every route, what the AI feature can reach and spend, and what the app stores require. Each check ends as detected, unknown or confirmed by owner evidence. No review proves an app has no flaws, so the aim is a short list of proof you can show.
In what order should I review a vibe-coded app?
Start with what costs most when wrong and is quickest to confirm. A leaked secret key and an open table work for a stranger on launch day. A missing store declaration only blocks your submission.
| Check | Question | Confirmed by owner evidence |
|---|---|---|
| 1. Keys | Which keys are inside the app? | Only public keys ship; any secret key that shipped is revoked |
| 2. Database rules | Can a user read rows that belong to someone else? | Rules on every table; a second account is refused |
| 3. Routes | Does every endpoint check who is asking? | A logged refusal for another user's record |
| 4. AI feature | What can it reach, and what does it cost? | Provider key on a server; a per-user limit is set |
| 5. Stores and payments | What must be in place to publish? | In-app account deletion; webhook signatures verified |
| 6. Website and repository | Are secrets served or stored in history? | 404 on /.env and /.git/config |
The checks work whoever wrote the code. Newly builds a real iPhone and Android app with React Native and Expo, and you can download the code or connect your own repository, so every file named below is one you can open. The settings and the proof that they hold are yours. The OWASP Mobile Top 10 (2024) names the failures these checks target: improper credential usage (M1), insecure authentication and authorization (M3) and security misconfiguration (M8).
Which keys can ship inside the app, and which cannot?
Anything compiled into an app can be read by whoever installs it. Expo's docs warn that EXPO_PUBLIC_ variables "will be visible in plain-text in your compiled application", and the EAS docs add that anything included in client-side code should be considered public. List every variable in your .env files, your app config and your EAS settings, then sort each one with this table.
| Key | In the app? | What the docs say |
|---|---|---|
| Supabase publishable (anon) | Yes | Safe to expose, provided row level security is on |
| Supabase secret (service role) | No | Backend only; it carries the bypassrls attribute |
| Firebase API key | Yes | Identifies the project; Security Rules decide access |
| Stripe publishable | Yes | Meant for apps and web pages |
| Stripe secret | No | Server environment only; prefer restricted keys |
| OpenAI or another AI provider | No | Never deploy the key in a mobile app |
Firebase adds that keys for other services, such as the Gemini Developer API, should stay protected. If a secret key was ever inside a build or a public repository, treat it as exposed. GitHub's remediation guide calls revoking the secret with its provider the most important step, and says removing it from the code is not enough. Create the new key, switch the server to it, revoke the old one, then read the provider's usage log for requests you do not recognise. The rotation guide on red.run.cloud lists what to rotate first.
Tokens the app receives after sign-in belong somewhere else. expo-secure-store keeps them in the iOS Keychain and Android Keystore. It suits values created on the device at run time. It cannot hide a key you shipped.
Can one user read another user's data?
The public key in the app lets anyone call your backend directly, so the rules behind it are the guard. Supabase states that a table in an exposed schema without row level security is readable and writable by any role with a grant on it. With security enabled and no policy, the publishable key sees nothing. In each table, look for three things:
- Row level security is enabled. In the dashboard this is a per-table switch.
- No policy has a condition of plain
true, which lets everyone through. - Views respect the policies. Supabase notes that views bypass row level security by default and offers
security_invoker = trueon Postgres 15 and later. Its guide on securing the Data API covers grants.
On Firebase, open the published rules. Firestore's test mode lets anyone read and overwrite your data, and Firebase describes Security Rules as the only safeguard against malicious users. A rule that allows read and write with a condition of true belongs to development only.
The two-account test
Rules can look right and still leave a gap, so test the behaviour. Create account A and account B. As A, make a record. Signed in as B, ask for A's record by its id, then try to change it and delete it. You want three refusals or empty results. OWASP lists this failure first in its API Security Top 10 as API1:2023, broken object level authorization. A secret key bypasses these rules when a request carries no user token, so any server function that uses one must run its own check on who is asking.
What can your AI feature reach, and what can it cost?
Four entries in the OWASP Top 10 for LLM Applications (2025) matter before launch: prompt injection (LLM01), excessive agency (LLM06), system prompt leakage (LLM07) and unbounded consumption (LLM10). OWASP's prompt injection cheat sheet says input screening is not a security boundary, because models do not separate instructions from data. Its advice is to grant minimal permissions and to require human approval for consequential tool actions.
Check five things in your own app. For the chat screen, use the chatbot self-test:
- The provider key sits on a server. If it ever shipped, rotate it, as in this key rotation page.
- The system prompt holds no secrets. Assume a user can make the model repeat it.
- The model's tools act with the signed-in user's rights and no more.
- Deleting, paying and sending need a confirmation from the user.
- Each user has a message limit. AI inside a Newly app uses credits, and some features have limits. An endpoint anyone can call lets a stranger spend them.
What do the app stores and payment providers require?
You publish under your own Apple and Google accounts, so these declarations are yours. Both stores ask for account deletion from inside the product.
| Requirement | What the source says | What to check |
|---|---|---|
| Apple account deletion | Guideline 5.1.1(v): if the app supports account creation, offer deletion within the app | Create and delete an account; confirm the rows are gone |
| Google account deletion | In-app path plus a web link to request deletion of the account and its data | Both paths work and reach the same deletion |
| Google data safety | Declare how the app collects and handles user data | The form matches what your database and AI provider receive |
| Payment webhooks | Stripe: verify that events come from Stripe before acting on them | A test event with a bad signature is rejected |
Declarations follow the data
If a chat message or an uploaded document goes to an AI provider, your store declarations and privacy text should say so. We checked the store sources on 24 October 2026; read the current text when you submit.
What about the website and the repository?
Open /.env and /.git/config on your own domain in a browser. A 404 is the result you want. Automated requests for these paths are common, and the 30-second check on red.run.cloud explains what a hit in your logs means.
For the repository, turn on push protection, which blocks pushes that contain secrets before they reach the repository. GitHub's docs say it requires GitHub Secret Protection on private repositories, so read the current plan terms. It does not clean history that already holds a secret, so rotate those keys first. Runtime versions such as Node.js belong to your build and server machines, and the 15-minute check has the fixed versions.
Where do you stand?
Every item starts as unknown. Mark it detected when you find the problem, and confirmed only when you hold the evidence listed under it. For a longer list, OWASP's MASVS sets out the requirements a mobile app can be verified against.
Your pre-launch review
- Detected: You found the problem.
- Unknown: Not checked yet, or the check could not tell.
- Confirmed by owner evidence: You checked and kept the proof.
Your answers stay in this browser tab. Nothing is saved or sent.
Frequently asked questions
How long does a pre-launch review take?
The key list and the store checks are quick. Most of the time goes into reading each table's policies and running the two-account test on every route that returns user data, so it grows with the size of the app.
Is a Supabase publishable (anon) key in my app a leak?
No. Supabase documents publishable keys as safe to expose in a mobile app, provided row level security is enabled on every table in an exposed schema. The service role (secret) key must never ship.
I found a secret key in my app bundle. What do I do first?
Revoke it with the provider and issue a new one. GitHub's guidance calls revoking the most important step, and deleting the key from code or history does not help once a build has shipped. Then keep the new key on a server and read the provider's usage for requests you do not recognise.
Do I have to read every line of code the AI wrote?
No. The checks look at behaviour: which keys ship, which rows a second account can reach, what an endpoint answers and what the AI feature may do. Reading the code only helps you find where to point them.
If a red.run.cloud scan finds nothing, can I launch?
No scan can say that. Both red.run.cloud scans work from outside, so rules and code that never answer a public request stay unknown until you hold owner evidence.
Who is responsible for the security of an app built with AI?
You are, as the owner. You publish under your own Apple and Google accounts, hold the keys, write the database rules and make the store declarations.
Sources
- OWASP Mobile Top 10, 2024 final list, OWASP Foundation, checked 2026-10-24
- OWASP API Security Top 10, 2023, OWASP Foundation, checked 2026-10-24
- OWASP Top 10 for LLM Applications, 2025, OWASP GenAI Security Project, checked 2026-10-24
- LLM Prompt Injection Prevention Cheat Sheet, OWASP Cheat Sheet Series, checked 2026-10-24
- Mobile Application Security Verification Standard, OWASP MAS project, checked 2026-10-24
- Row Level Security, Supabase docs, checked 2026-10-24
- Understanding API keys, Supabase docs, checked 2026-10-24
- Securing your API, Supabase docs, checked 2026-10-24
- Get started with Cloud Firestore Security Rules, Firebase docs, checked 2026-10-24
- Learn about using and managing API keys, Firebase docs, checked 2026-10-24
- Environment variables in Expo, Expo docs, checked 2026-10-24
- Environment variables in EAS, Expo docs, checked 2026-10-24
- SecureStore, Expo docs, checked 2026-10-24
- Remediating a leaked secret, GitHub Docs, checked 2026-10-24
- About push protection, GitHub Docs, checked 2026-10-24
- API key best practices, Stripe docs, checked 2026-10-24
- Receive Stripe events in your webhook endpoint, Stripe docs, checked 2026-10-24
- Best practices for API key safety, OpenAI Help Center, checked 2026-10-24
- App Review Guidelines, section 5.1.1, Apple Developer, checked 2026-10-24
- Understand app account deletion requirements, Google Play Console Help, checked 2026-10-24
- Provide information for Google Play's Data safety section, Google Play Console Help, checked 2026-10-24
Continue Learning
Is my AI-built app secure? A 15-minute check →
A shorter first pass, including the October 2026 Node.js and PHP fixes.
Is my website chatbot vulnerable? A 15-minute self-test →
A closer look at the chat feature inside an app.
OpenCode Console breach: rotate your LLM provider keys →
What to rotate when an AI provider key may be exposed.
