HOW TO SECURE FLUTTERFLOW
Step-by-step guide to securing your FlutterFlow visual app builder project.
FlutterFlow Security Context
FlutterFlow generates Flutter / Dart and connects to Firebase, Supabase, or a custom REST API. The visual builder hides the bug: a “Read documents” action drag-dropped onto a page reaches Firestore directly with the public Firebase config — every security check is in the rules file, not in the visual flow. Apps shipped without revisiting Firestore rules are publicly readable; that’s the recurring incident shape.
Security Checklist
1. Review Firebase security rules (Critical)
Open firestore.rules (FlutterFlow → Firebase → Firestore Rules). The default FlutterFlow project ships with allow read, write: if true; to make development frictionless. Replace every wildcard with a real predicate:
match /users/{userId} {
allow read, write: if request.auth.uid == userId;
}
match /posts/{postId} {
allow read: if request.auth != null;
allow write: if request.auth.uid == resource.data.author_id;
}
Then deploy: firebase deploy --only firestore:rules. Verify with the Firebase Scanner.
2. Audit API key handling (Critical)
FlutterFlow embeds Firebase config in the compiled app — that’s intended and fine, because Firebase config is public-by-design when rules are set correctly. What is not fine: embedding a Stripe secret key, a SendGrid key, or a third-party API key directly in a Flutter custom action. Move those calls to a Cloud Function and have the Flutter client call the function (which is auth-checked) instead.
3. Configure authentication properly (Critical)
In Firebase → Authentication → Sign-in method: enable email verification (Settings → User actions → Enable account creation). In FlutterFlow → App Settings → Authentication: set the “logged-in initial page” and “logged-out initial page” so unauthenticated users don’t reach the app’s main flows.
4. Add Supabase RLS if using Supabase (Critical)
FlutterFlow doesn’t auto-generate RLS policies for Supabase tables. After connecting Supabase: open the Supabase dashboard, Database → Tables → [each table] → Enable RLS, and add ownership policies. Verify with the Supabase RLS Checker.
5. Secure custom Dart actions (Critical)
Custom actions are arbitrary Dart code with full app context. Audit: (1) string-concatenated URLs (SSRF risk), (2) http.get() calls that include the user’s auth token in URL parameters (logged everywhere), (3) calls to unvalidated user input. Custom actions should validate inputs the same way an API route would.
6. Add navigation guards on protected pages
In FlutterFlow → page Backend Query → set “If user not logged in, navigate to: /login”. Don’t rely on hiding the menu item; an attacker uses the deep link.
7. Audit third-party API integrations
Every API call defined in App Settings → API Calls is visible in the compiled app, including any header values you set. If a header value is Authorization: Bearer sk_..., that secret ships to the client. Move the call to a Cloud Function.
8. Configure app-level permissions
In Settings → Permissions: request only the permissions your app actually uses. The default FlutterFlow scaffold often requests Camera, Location, Contacts, even when only one is needed. Each unused permission is a privacy / app-store-review risk.
9. Secure push notifications
If using FCM: never store the FCM device token in a publicly-readable Firestore collection. Send notifications via a Cloud Function that receives the user ID and looks up the token server-side, not from the client.
10. Audit exported source
If you exported the FlutterFlow project to GitHub: walk every file looking for hardcoded URLs (especially http://localhost, http://10.0.2.2 from emulator testing) and credentials. Check git history too — git log -p | grep -E 'sk_|service_role|apiKey'.
11. Configure deep link handling
If your app uses deep links (/profile/{userId}): validate the parameter before using it. The bug shape is “open myapp://profile/123 and the app trusts the ID without checking it belongs to the current user.” Treat deep-link params the same as URL query params from a browser.
12. Review payment integration
For Stripe / RevenueCat / in-app purchases: never grant entitlement from the client-side success callback. The only honest signal is the webhook to your Cloud Function with a verified signature. See Stripe webhook and paid-trust.
13. Enable code obfuscation for production builds
flutter build apk --obfuscate --split-debug-info=./debug-info (or the FlutterFlow equivalent toggle). Obfuscation isn’t security on its own — anyone determined will reverse the APK — but it raises the cost of casual analysis and hides the obvious string constants.
14. Audit local storage usage
For SharedPreferences / Hive / sqflite: never store auth tokens or PII unencrypted on the device. For tokens use flutter_secure_storage (which uses Keychain on iOS and Keystore on Android). For sensitive PII, encrypt before storing.
15. Configure certificate pinning for production APIs
Use dio with a certificate pinning interceptor for any API call that must not be MITM-able. Pin the leaf cert SHA-256, not the CA — and have a rotation plan before you deploy, because a pinned cert outage means a forced app update.
16. Run a security scan
The Firebase Scanner covers the rules side; the full VibeEval scan adds BOLA, custom-action input validation, and dependency CVE checks.
Related Resources
Free Self-Audit Suite
Five free scanners.
Vibe Coding Security Risk Guide
Full risk catalogue.
Firebase Guide
Deep-dive on Firestore / Storage / Auth security.
Automate Your Security Checks
VibeEval scans your FlutterFlow app and its Firebase backend against every category above plus the long tail (BOLA, role escalation, webhook trust, dependency CVEs).
SCAN YOUR APP
14-day trial. No card. Results in under 60 seconds.