SCAN YOUR A0.DEV APP FOR VULNERABILITIES

ENTER YOUR A0.DEV BACKEND URL

Enter your deployed app URL to check for security vulnerabilities.

a0.dev turns a prompt into a React Native / Expo app you can preview live on your own phone, iterating in chat until it works — with the backend wired to Supabase, Firebase, or generated API endpoints along the way. There is no app URL to point a scanner at, which is why the scanner asks for the backend URL instead: the Supabase project, Firebase config, or API base your app talks to. That is the right target for a second reason — it is the only place security can actually be enforced.

The live preview is exactly where the risk hides: an a0.dev app that behaves perfectly on your phone proves nothing about its security, because the checks you’re watching run in the client, and the client ships to the attacker. Anyone can download the released build, unzip the bundle, and read every string in it — keys, endpoint URLs, feature flags, premium logic. Whatever the backend allows with that extracted config is what an attacker gets, regardless of what the UI shows. And since a released build cannot be recalled, bundle-side mistakes have to be caught before the first store submission, not rotated away after.

Common vulnerabilities we find in a0.dev apps

Six failure modes recur in AI-generated Expo apps. Every one is testable from the backend URL — the same way an attacker with the extracted bundle config would test it.

Missing backend rules

The app enforces permissions in React Native code while the Supabase project behind it has RLS disabled, or the Firestore rules sit in test mode or gate only on request.auth != null. Since the client config ships in the bundle by design, anyone can query the backend directly and skip every client-side check. Exploit shape: extract the config, query the REST endpoint with no session (or any session), read the whole table. Fix direction: deny by default, then explicit per-table policies keyed to auth.uid() — “any authenticated user” is not a scope for personal data.

Unauthenticated generated endpoints (BOLA)

Generated API endpoints and edge functions frequently ship with no auth check, or with auth but no ownership check, so any signed-in user can fetch any record by ID. Exploit shape: sign in as user B, replay user A’s record ID against the endpoint — a 200 with A’s data is the finding. This is the BOLA in AI-generated CRUD pattern, and on mobile the endpoint URLs are trivially discoverable from the bundle. Fix direction: validate the session on every endpoint, then confirm the resource belongs to the caller before returning it.

Secrets in the app bundle

When a prompted feature needs OpenAI or Stripe, the generated call is often made from the client, key included — sometimes via app.json extra fields, which are bundled, not secret. On mobile there is no instant rotation: rotating the key breaks installs still carrying the old one, and archived builds keep it forever. Fix direction: every secret-requiring call moves behind an edge function or server endpoint that holds the key, before the first release; rotate anything that ever appeared in a build. A quick self-check before every export:

grep -rE 'sk_(live|test)_|sk-[A-Za-z0-9]{20,}|service_role' . --exclude-dir=node_modules

Tokens in AsyncStorage instead of SecureStore

Generated auth flows persist session and refresh tokens in AsyncStorage — unencrypted files on the device, readable via device access or backup extraction. Fix direction: expo-secure-store (Keychain on iOS, Keystore on Android) for anything session-shaped, including as the storage adapter passed to the supabase-js client so the SDK never touches AsyncStorage.

Client-side premium gating

if (isPremium) in React Native code is decoration: attackers patch the binary, tamper with responses, or call the premium endpoint directly with a free-tier token. Exploit shape: find the backend call behind a premium screen, replay it from a free account — if it responds, the paid tier is free. Fix direction: the server checks the entitlement (a server-stored subscription flag, a validated App Store / Play receipt, or a RevenueCat check) before serving premium content; the client check is UX only.

Privileged-field writes

Generated rules that do exist tend to cover reads and forget writes: a user who can update their own profile row can often update role, is_premium, or credits in the same request. Exploit shape: a direct PATCH to the user’s own row setting "role": "admin" — the mass assignment pattern against the backend the bundle points at. Fix direction: column-level restrictions or a server-mediated write path that strips privileged fields before they reach the database.

How VibeEval works with a0.dev

  1. Enter the backend URL your a0.dev app talks to — the Supabase project URL, Firebase endpoint, or generated API base. It’s listed in the generated client config; it’s also what an attacker extracts from the released bundle.
  2. The agent probes it the way an attacker would. Browser-driven and direct-API testing: querying with only the client config and no session, cross-account replays of resource IDs (BOLA), writes to privileged fields like role and credits, premium endpoints called with free-tier tokens, and auth flows, headers, and error responses checked for leakage.
  3. You get findings with severity and paste-ready fix prompts. Each finding names the table or endpoint, shows the request that proved it, and ships a remediation prompt you can paste into the a0.dev chat — plus the RLS policy or rules change where the fix belongs in the backend project instead.

Manual testing vs VibeEval

Manual review is still where business logic gets caught — no scanner knows what your app is supposed to allow. The scanner wins on repeatability: every a0.dev chat iteration can regenerate endpoints, storage calls, and auth wiring, so a manual pass is stale the moment you prompt again.

Manual testing VibeEval
Time per pass Hours: rule review per table, endpoint replay with two accounts Minutes against the backend URL
Cross-user (BOLA) coverage The IDs and endpoints you think to try Every discovered endpoint, both accounts, systematically
After each chat iteration Full re-test, rarely done Re-run the scan, diff the findings
Rules vs extracted config Backend console review, easy to miss a collection Probed from outside with only the client config
Business logic and abuse cases Where humans are essential Out of scope
Cost Your time before every release Flat, per scan

Frequently asked questions

Does VibeEval have special support for a0.dev?

Yes. VibeEval recognizes the backend patterns AI-generated Expo apps use — Supabase, Firebase, and generated endpoints — and runs the probes that match this stack’s failure modes: missing rules behind a shipped client config, endpoints without auth or ownership checks, privileged-field writes, and premium endpoints that never check the entitlement.

Why scan the backend URL when the problem is my mobile app?

Because the backend is the only enforceable boundary. The mobile client ships to the attacker in full — every check in the React Native code can be read, patched, or skipped by calling the backend directly with the extracted config. Scanning the backend tests what actually stands between that config and your data.

The app works in the live preview — isn’t that enough?

No, and this is a0.dev’s specific trap: the preview shows you the client behaving, and the client is the one component whose behavior doesn’t count. A missing RLS policy fails open, invisibly — the app looks identical with or without it. The only meaningful test is from outside, against the backend, with no cooperation from the app.

Can I scan during a0.dev development?

Yes — scan the backend while you iterate in chat, and always before the first store submission. Mobile makes the ordering strict: secrets and keys in a released binary cannot be un-shipped, so bundle-side findings must be fixed before the build reaches devices, and backend rules re-verified after every regeneration.

What authentication issues are common in a0.dev apps?

Missing auth on generated endpoints, missing ownership checks (BOLA), session tokens in AsyncStorage instead of SecureStore, OAuth deep-link redirects on claimable custom schemes with unvalidated state, and entitlements the backend never verifies.

Test your a0.dev app before launch

An a0.dev app that works on your phone tells you nothing about what the backend allows to someone who never opens the app. Scan the backend URL before the build ships, fix with the paste-ready prompts, and re-scan after every chat iteration — because on mobile, you don’t get to quietly fix it after release.

SCAN YOUR APP

14-day trial. No card. Results in under 60 seconds.

START FREE SCAN