RORK SECURITY CHECKLIST
Rork is a text-to-mobile-app builder that generates React Native + Expo apps from natural language, typically wired to a hosted backend like Supabase or Firebase. The most common security issues come from one mobile-specific fact and one generation habit: everything in the app bundle is extractable from the APK/IPA, so the backend’s security rules are the only real boundary — and generated code habitually enforces access in the client, where enforcement doesn’t count. The checklist below is what we look for first when we audit a Rork app.
Treat Critical as launch-blocking. High is week-one. Medium is the cleanup once you have users.
How to use this checklist
Walk it once against the generated code and the backend console, with two test accounts. After each fix, sign in as user B and try to read user A’s data — both through the app and with a direct API call, because attackers skip the app. Remember the mobile constraint: anything wrong in a shipped binary stays wrong until users update, so fix bundle-side issues before the first store release.
Critical (fix before launch)
1. Enable RLS on every Supabase table (or lock Firestore rules)
Why it matters. The Supabase anon key (or Firebase config) ships in your app bundle by design and is extractable by anyone. That is safe ONLY if Row Level Security is on for every table (or Firestore rules scope every collection). One unprotected table is fully readable and writable with the key already in the attacker’s hands.
How to check. In the backend console, list every table/collection and confirm RLS is enabled with an owner-scoping policy — not just “authenticated”. Then probe from outside with the Supabase RLS Checker or Firebase Scanner.
How to fix. Enable RLS per table with policies keyed to auth.uid(); in Firestore, gate each collection on request.auth.uid == resource.data.owner_id. Deny by default.
2. Get real secrets out of the bundle
Why it matters. Every key compiled into the app is public: service-role keys, payment secrets, LLM API keys. And unlike a web deploy, you cannot un-ship it — a leaked secret in a released binary stays leaked until every user updates, which app store review makes slow.
How to check. Grep the generated source and env config for key prefixes (sk_, sk-, AIza, service_role). Build the release bundle and string-search it too.
How to fix. Move every non-publishable secret behind a server-side function the app calls. Rotate anything that ever appeared in the source or a shipped build.
3. Verify purchases and entitlements server-side
Why it matters. Generated premium gating is usually a client-side conditional. An attacker with a patched binary — or just a replayed API request — gets premium for free. On mobile this is the single most commonly shipped business-logic hole.
How to check. Find every isPremium / isPro style check. Trace where the flag is set. If the client sets it, or if the backend grants it without verifying a store receipt, it’s broken.
How to fix. Verify in-app purchase receipts server-side against Apple/Google, store the entitlement in the database, and gate it with backend rules. The client reads the flag; it never writes it.
4. Move tokens from AsyncStorage to SecureStore
Why it matters. Rork-generated auth flows commonly persist session tokens in AsyncStorage — unencrypted, readable on compromised devices and via some backup paths. Session tokens belong in the platform keystore.
How to check. Grep for AsyncStorage.setItem and see what’s stored. Tokens, refresh tokens, or credentials in the value are the finding.
How to fix. Switch to expo-secure-store (Keychain on iOS, Keystore on Android) for anything credential-shaped. Keep AsyncStorage for genuinely non-sensitive state.
5. Audit generated API routes for auth and ownership (BOLA)
Why it matters. Generated CRUD layers — Edge Functions, Cloud Functions, or a small server — routinely ship without authentication, and even with auth, without ownership checks. Since the API endpoint is extractable from the bundle, attackers call it directly, no app required.
How to check. Sign in as user A, note a record ID. As user B, request that ID directly against the API. A 200 with A’s data is a BOLA.
How to fix. Every route checks auth, then checks that the session owns the resource. Rules and route code both deny by default.
6. Validate deep link parameters
Why it matters. Generated deep link handlers accept whatever parameters arrive. Unvalidated links can redirect auth flows, inject state, or trigger privileged screens from a crafted URL sent to the victim.
How to check. List every registered deep link/scheme in the Expo config. For each handler, check whether parameters are validated and redirect targets allowlisted.
How to fix. Validate every parameter’s type and range, allowlist redirect destinations, and never grant auth state from a link parameter alone. Prefer verified universal links / app links over raw custom schemes for sensitive flows.
High (fix in the first week)
7. Strip privileged fields from client writes
If users can update their own profile row and it carries role, is_admin, or is_premium, a patched client can self-promote. Restrict writable columns (Supabase) or reject privileged-field writes in rules (Firestore).
8. Rate-limit auth and expensive endpoints
Throttles must live server-side — the app can’t enforce them against a replay script. Auth, password reset, and anything that costs money (LLM calls, SMS) come first.
9. Return generic errors from the backend
Generated functions pass raw errors — SQL fragments, stack traces — to the client. Log details server-side; return {"error": "Internal server error"}.
10. Disable email enumeration in the auth flow
Signup, password reset, and magic-link responses must be identical for “user exists” and “user does not exist.”
11. Decide on certificate pinning deliberately
Rork apps ship without pinning by default. That’s usually fine; if your threat model warrants it, add pinning with a rotation plan — a bad pin bricks the installed base until users update.
12. Review third-party SDK permissions
Each SDK the generator added (analytics, crash reporting, ads) ships in your binary with its own data collection. Remove what you don’t use; it’s attack surface and a privacy-label liability.
Medium (fix when you can)
13. Remove demo data and test accounts before store submission
Generated seed users and sample rows ship with the backend. Delete them; store reviewers and attackers both find them.
14. Cap file upload size and types
If the app uploads images or files, enforce size and MIME limits server-side — storage rules or the receiving function, not the client picker.
15. Monitor for enumeration patterns
Watch backend logs for one client reading thousands of rows in seconds — that’s someone with your extracted anon key walking the tables.
16. Document each table’s access model
A written record of who can read/write each table gives you something to diff after every regeneration.
17. Keep Expo and React Native dependencies current
Generated lockfiles age fast. Patch releases fix real vulnerabilities in the networking and storage layers your app depends on.
18. Plan the incident path for a shipped secret
Because you can’t rotate a binary, the plan is: rotate server-side, invalidate the old credential, force-upgrade via a minimum-version check. Write it down before you need it.
After every Rork regeneration
- Re-check token storage — regeneration can quietly revert SecureStore to AsyncStorage.
- Diff backend rules against the schema; new tables ship without policies.
- Grep for newly hardcoded keys in the regenerated code.
- Re-test cross-user access (user B reading user A’s records, via direct API call).
- Re-review deep link handlers and the Expo scheme config.
Common attack patterns we see in Rork apps
The extracted anon key. Attacker pulls the APK from a mirror, extracts the Supabase URL and anon key, and reads every table that lacks RLS — never opening the app.
The patched premium check. Client-side isPremium conditional flipped in a modified binary; premium features free, no backend involvement.
The replayed purchase. Backend grants entitlements from a client-reported “purchase succeeded” call without verifying the store receipt.
The hostile deep link. Crafted app:// link with an attacker-controlled redirect parameter walks the victim through a login flow that hands over the session.
Related Resources
How to Secure Rork
Step-by-step guide for hardening a Rork app — backend rules, token storage, receipt verification, and the regeneration re-audit in long form.
Is Rork Safe?
In-depth analysis of Rork’s defaults — what the platform handles, what the generated app leaves open.
Automate Your Checklist
A checklist tells you what to look for. A scanner tells you what’s actually broken right now. VibeEval probes the backend your Rork app ships its keys for, attempts the cross-user BOLA and open-rules attacks above, and reports what got through — with the table or route to fix.
SCAN YOUR RORK APP
14-day trial. No card. Results in under 60 seconds.