fixes / launch-ready

How I Would Fix exposed API keys and missing auth in a Flutter and Firebase internal admin app Using Launch Ready.

If I open a Flutter and Firebase internal admin app and find exposed API keys plus missing auth, I assume the product is already in a risky state. The...

Opening

If I open a Flutter and Firebase internal admin app and find exposed API keys plus missing auth, I assume the product is already in a risky state. The symptom is usually simple: someone can inspect the app bundle, network calls, or Firebase config and see credentials, while the admin screens are reachable without proper sign-in or role checks.

The most likely root cause is not "hackers". It is rushed AI-built code that shipped Firebase client config as if it were secret, then used UI-only gating instead of real authorization. The first thing I would inspect is the Firebase Auth setup, Firestore and Storage security rules, and whether any sensitive operations are being done from the client without server-side verification.

Triage in the First Hour

1. Check whether the app is live in production or only in preview. 2. Confirm which keys are exposed:

  • Firebase web config
  • Third-party API keys
  • service account JSON
  • Stripe, OpenAI, or email provider secrets

3. Inspect Firebase Authentication:

  • Is auth enabled?
  • Are anonymous users allowed?
  • Are custom claims used for admin access?

4. Review Firestore rules and Storage rules. 5. Check if any admin routes are protected only by Flutter navigation logic. 6. Open browser dev tools and verify what network requests reveal. 7. Review recent deploys from FlutterFlow, Cursor, GitHub Actions, or manual builds. 8. Check Firebase Console for:

  • active users
  • sign-in methods
  • suspicious reads/writes
  • usage spikes

9. Inspect Cloud Logging / Analytics / Crashlytics for unauthorized access patterns. 10. Review environment handling in:

  • `google-services.json`
  • `GoogleService-Info.plist`
  • `.env`
  • CI/CD secrets store

11. Confirm whether any privileged actions are happening directly from the client app. 12. If the app handles real customer data, pause writes until access control is fixed.

A fast diagnostic command I would run locally:

firebase deploy --only firestore:rules,storage
firebase emulators:start --only auth,firestore

That tells me quickly whether rules are actually being enforced before I touch production.

Root Causes

| Likely cause | How I confirm it | Business risk | |---|---|---| | Firebase config treated as secret | Search repo, build artifacts, and shipped JS/Flutter assets | Anyone can copy config and probe your backend | | Admin access controlled only in UI | Log out and directly hit admin routes or data endpoints | Unauthorized staff or outsiders can access sensitive data | | Firestore rules too open | Review `allow read, write: if true` or broad wildcard rules | Data exposure and accidental deletion | | Missing custom claims or role checks | Inspect auth token claims after login | Regular users may get admin-level access | | Secrets stored in client app | Search for API keys in Dart files or bundled assets | Keys get extracted from APK/IPA/web build | | Privileged operations done from client | Look for direct writes to billing, user management, or exports | Abuse, fraud risk, and hard-to-trace mistakes |

Important distinction: Firebase client config is not always a secret by itself. The real problem is when that config gives access to weakly protected services, open rules, or privileged workflows that should never be callable from an untrusted client.

The Fix Plan

First, I would stop treating this as a UI bug. This is an authorization problem with possible secret exposure, so I would fix access control before changing design or adding features.

1. Rotate anything that is truly secret.

  • Revoke exposed third-party API keys.
  • Replace any service account JSON immediately.
  • Rotate email, payment, analytics, and AI provider secrets.

2. Lock down Firebase security rules.

  • Deny by default.
  • Allow reads and writes only for authenticated users with the right role.
  • Separate public data from admin-only collections.

3. Move privileged logic out of the Flutter client.

  • Put sensitive actions behind Cloud Functions or a secure backend.
  • Validate auth server-side before any write happens.

4. Add real authorization using custom claims.

  • Assign `admin`, `editor`, or `viewer` roles on the server side only.
  • Read claims after login and gate routes based on them.

5. Protect admin screens at two layers.

  • UI route guard for usability
  • Security rule or backend check for actual enforcement

6. Remove secrets from the app bundle.

  • Use environment variables only for non-secret public config where appropriate.
  • Keep private keys on server infrastructure or managed secret storage.

7. Rebuild and redeploy from a clean pipeline.

  • Clear old artifacts.
  • Verify no stale config remains in cached builds or preview deployments.

8. Add audit logging for sensitive actions.

  • Who changed what
  • When it happened
  • From which account

9. Put monitoring on login failures, unusual reads/writes, and rule denials.

A safe pattern I would use looks like this:

// Example Firestore rule pattern
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    function isAdmin() {
      return request.auth != null && request.auth.token.admin == true;
    }

    match /adminData/{doc} {
      allow read, write: if isAdmin();
    }

    match /publicData/{doc} {
      allow read: if true;
      allow write: if request.auth != null;
    }
  }
}

That does not solve everything by itself, but it stops the most common failure mode: assuming the frontend will protect sensitive data.

I would also review any file upload path separately. Storage rules are often left wide open while Firestore gets some attention, which creates a second leak path through documents, exports, screenshots, or CSV uploads.

Regression Tests Before Redeploy

Before shipping the fix, I would run both functional tests and abuse-case checks.

Acceptance criteria:

  • Unauthenticated users cannot read admin collections.
  • Unauthenticated users cannot write to protected collections.
  • Authenticated non-admin users get denied on admin routes and data calls.
  • Admin users can still complete their workflows end to end.
  • Exposed secrets are rotated and no longer work from old copies of the app.

QA checks I would run:

1. Log out and try every admin screen from a fresh session. 2. Test direct document access through Firestore queries with no auth token. 3. Verify Storage upload/download permissions separately from Firestore rules. 4. Confirm role-based access works after token refresh and re-login. 5. Test mobile app reinstall to ensure cached auth state does not bypass checks. 6. Verify error states are clear enough that staff know they need permission rather than thinking "the app is broken". 7. Run one negative test for each sensitive action:

  • delete user
  • export data
  • update billing settings
  • change roles

I would also insist on a small regression suite in CI:

  • 100 percent coverage of security rule tests for protected collections
  • at least 80 percent coverage on critical auth flows
  • zero failing emulator tests before merge

For an internal admin app like this, I care more about preventing one bad write than about polishing animations.

Prevention

The fix should not be "we will remember this next time". I would put guardrails in place so this class of issue does not return.

Security guardrails:

  • Store secrets only in approved secret managers or CI secrets stores.
  • Never commit service account files to GitHub.
  • Require code review for any auth rule change or backend permission change.
  • Add least privilege by default for all new collections and endpoints.
  • Enable rate limiting where possible on callable functions and external APIs.

Monitoring guardrails:

  • Alert on unusual read/write spikes in Firestore usage.
  • Alert on repeated permission denied errors after deploys.
  • Track failed logins and token refresh failures in logs or analytics,
  • Monitor uptime so you catch broken deployments before staff do.

UX guardrails:

  • Show clear "access denied" states instead of blank pages.
  • Make role-based navigation obvious so staff do not keep clicking into blocked areas.
  • Surface loading states during token refresh to avoid confusion during login transitions.

Performance guardrails matter too because security fixes can accidentally slow down the app:

  • Keep auth checks lightweight so startup time stays under 2 seconds on mobile networks where possible,
  • Avoid heavy synchronous work during route guards,
  • Cache non-sensitive reference data so admins do not wait on every screen load.

I would also add a release checklist item: no production deploy goes out unless security rules have been tested against the emulator and reviewed by a second engineer.

When to Use Launch Ready

Launch Ready fits when you need this fixed fast without turning it into a long rescue project.

Use it when:

  • your Flutter/Firebase admin app is working but unsafe,
  • you need production deployment cleaned up quickly,
  • you want exposed secrets rotated before more people see them,
  • you need one senior pass that makes the release safer without rewriting the whole product.

What you should prepare before booking: 1. Firebase project access with owner-level permissions as needed, 2. Repo access, 3. Current deployment pipeline details, 4. List of all third-party services connected to the app, 5. Any known admins who should retain access, 6. A short note on what must stay live during the fix window.

If there is active customer data exposure risk, I would prioritize containment first and launch second.

References

1. https://roadmap.sh/cyber-security 2. https://roadmap.sh/api-security-best-practices 3. https://firebase.google.com/docs/rules 4. https://firebase.google.com/docs/auth 5. https://cloud.google.com/secret-manager/docs

---

Take the next step

If this is a problem in your product right now, here is what to do next:

  • [Use the free Cyprian tools](/tools) - estimate cost, score app risk, check launch readiness, or pick the right service sprint.
  • [Book a discovery call](/contact) - I will tell you honestly whether you need a sprint or if you can DIY the next step.

*Written by Cyprian Tinashe Aarons - senior full-stack and AI engineer helping founders rescue, launch, automate, and scale AI-built products.*

Next steps
About the author

Cyprian Tinashe AaronsSenior Full Stack & AI Engineer

Cyprian helps founders rescue, secure, deploy, and automate AI-built apps with production-grade engineering, launch systems, and AI integration.