Guide · Mobile app security
Can a mobile app keep a secret?
A mobile app runs on a device you do not control. Its package can be unpacked, its network traffic can be observed and its behaviour can be changed. That does not make every value found inside it a vulnerability—but it does mean a real server secret cannot live there. This guide explains the boundary, using Firebase as the case people most often misunderstand.
The short answer: assume the client can be inspected
When an Android or iOS app is released, every user receives a copy of its executable code and resources. The original source is not handed over neatly, but common tools can recover strings, configuration files, endpoints and a useful approximation of the program's structure. An attacker does not need to reconstruct the whole app to search for a token or replay one request.
Obfuscation removes readable names and makes code harder to analyse. It cannot reliably hide a value the app must use from someone who controls the device. Design the client to be inspectable and keep privileged credentials and security decisions on a system you control.
| Reasonable in the app | Keep on the server | |
|---|---|---|
| Configuration | API base URL, project ID, feature availability | Private network locations and administrative configuration |
| Identity | A short-lived token for the signed-in user | Service-account keys and signing secrets |
| Third-party services | A deliberately public, tightly restricted client key | Payment, email, AI-model and unrestricted API keys |
| Business rules | Validation that improves the interface | Authorization, prices, entitlements and fraud decisions |
What decompiling an app can actually reveal
A first pass is often mundane. Unpack the application, list its resources and search the strings. That can reveal server addresses, analytics identifiers, Firebase configuration, feature flags and credentials that were copied into a build file. The next step is observing the requests the app makes. If a privileged action depends only on a value embedded in the client, the problem is not that the decompiler was clever; the trust boundary was in the wrong place.
Runtime storage needs the same care. A token issued to a signed-in user has to reach the device, so the goal is not to make it invisible forever. Give it a narrow scope and short lifetime, store it with the platform's protected storage, transmit it over TLS and let the server verify what that user may do on every request.
Do not confuse inconvenience with protection. Splitting a key across strings, encoding it or downloading it after launch may hide it from a basic search, but the complete value must exist when it is used. These techniques can slow bulk scraping; they cannot turn a shared secret into a private one.
The Firebase API key exception—and what it does not excuse
Open a Firebase Android build and you will usually find an API key in google-services.json; an Apple app carries the equivalent configuration. This alarms many audits, but Firebase documents these keys as public by design when they are restricted to Firebase-related APIs. They identify the project. They do not authorize a user to read Firestore, Realtime Database or Cloud Storage.
The locks are Firebase Security Rules, backed by the user's authentication state. App Check adds another signal: it helps a supported backend reject traffic that did not come from an attested instance of your app. Neither control is replaced by hiding the Firebase key.
The nuance matters. The same Google Cloud project can contain other keys whose services do charge or authorize by key. A key usable with a mapping, payment, email or generative-AI API may be valuable to an attacker. Use separate keys, restrict each one to the expected API and application, set sensible quotas, and keep any service that requires a true secret behind your server.
Gemini made this concrete. In February 2026 Truffle Security reported that enabling the Gemini API in a Google Cloud project allowed the project's existing unrestricted keys, including keys already published for Maps or Firebase, to call Gemini, reach files uploaded to it and run up charges. Google's Gemini documentation now says the API rejects unrestricted standard keys, and Firebase warns never to include the Gemini Developer API in the allowlist of a publicly accessible key. Limit each public key to the APIs it actually uses, and call Gemini from your server or through Firebase AI Logic with App Check.
- Firebase: Learn about and manage API keys
- Truffle Security: Google API keys and Gemini
- Google AI: using Gemini API keys
- Firebase AI Logic
- The key is limited to Firebase services
- Review Security Rules, Authentication and App Check.
- The key also enables another Google API
- Separate it and apply API and application restrictions.
- The app contains a service account or private key
- Revoke it, investigate its use and move the operation server-side.
- Data is readable without the intended user rights
- Treat the rules or backend authorization as the vulnerability.
Put the security decision on the server
Imagine a booking app that shows available appointments and lets a customer reserve one. The app may know the public API address and carry a token for the signed-in customer. It should not decide that an appointment is free, set its own price or call the payment provider with your private key.
Instead, the server receives the request, verifies the user, checks the current availability and price, performs the privileged action with a server-side credential and returns only the result. This example is fictional, but the boundary is the same in a customer portal, a warehouse app or a subscription product.
Client-side checks still improve the experience: disable an invalid button, catch a malformed date, explain why an action is unavailable. Repeat every security-relevant check on the server, where a modified app cannot simply skip it.
- 01 App requests User intent plus a short-lived identity token
- 02 Server verifies Identity, permission, current state and limits
- 03 Service acts The private credential never reaches the phone
- 04 Result returns Only the data the user is allowed to receive
If the backend connects to business systems, also review how to segment the network and limit access between devices.
What App Check, Play Integrity and App Attest add
Authorization answers whether this user may perform this action. App integrity answers a different question: does the request appear to come from a genuine, untampered instance of the app? Firebase App Check can use Play Integrity on Android and App Attest or DeviceCheck on Apple platforms to provide that signal to Firebase services or your own backend.
That is valuable for limiting automated abuse, copied clients and some modified-app traffic. It is not a magic proof. Devices can be unavailable or compromised, attestation services can fail, and a genuine app can still be driven by a malicious user. Roll enforcement out while monitoring, define what happens when attestation is unavailable and keep ordinary authentication, authorization, rate limits and logging in place.
Apply stronger checks to actions that could cause harm or significant cost: claiming a promotion, making an expensive AI request, downloading paid content or changing a payment destination. Reading a public catalogue has different requirements.
A practical release review
Before release, inspect the same artefact users will install—not only the source repository. Search the built package for credentials and private material; list every outbound service; verify that each key is public by design or restricted to the minimum; and attempt important requests without the app's own interface.
Then test authorization with two ordinary accounts. Can one read or change the other's records by editing an identifier? Can either invoke an administrative endpoint? Are Firebase rules tested against denied cases as well as happy paths? Finally, check logs, quotas and alerts: a control you cannot observe is difficult to trust in production.
- No service-account files, signing secrets, payment secrets or private keys in the package.
- Every client key has an owner, a purpose, API restrictions and a rotation plan.
- The server rechecks identity, ownership, roles, prices and entitlements.
- Firebase Rules deny by default and have emulator tests for allowed and denied requests.
- App attestation complements—never replaces—authentication and authorization.
- Rate limits, budgets and alerts make abuse visible before the invoice does.
If you find a real secret in a released app
Treat the value as exposed. Revoke or rotate it first, using the provider's safe overlap procedure if an immediate cutover would break production. Review access logs, billing and changes made with the credential; preserve enough evidence to understand the window; and tell the relevant people if data or accounts may have been affected.
Move the privileged call to a server or managed function, verify the user’s permissions there and limit the runtime’s access. Encoding the same secret differently in another app release does not resolve the exposure.
For how more capable models change this work, read AI hacking agents: real progress and limits.
Sources and further reading
- Firebase: Learn about and manage API keysWhy Firebase client keys identify a project and how to restrict them.↗
- Firebase security checklistSecurity Rules, App Check, credentials and launch controls.↗
- Android: Hardcoded cryptographic secretsAndroid's guidance on secrets recoverable through reverse engineering.↗
- Android: Play Integrity APISignals for genuine app binaries and devices.↗
- Apple: Establishing your app's integrityApp Attest and server-verified assertions.↗
- Truffle Security: Google API keys and GeminiFebruary 2026 research on existing keys gaining access to Gemini.↗
- Google AI: using Gemini API keysKey types, restrictions and the rejection of unrestricted standard keys.↗
- Firebase AI LogicClient SDKs that call Gemini through a proxy, so the Gemini key stays off the app.↗
Questions before we start
Can someone really decompile an Android or iOS app?
They can inspect the package, recover resources and strings, approximate parts of the code and observe runtime behaviour. Obfuscation raises the effort but does not make a value used by the app permanently secret.
Is exposing a Firebase API key a security vulnerability?
Usually not by itself. Firebase client keys are designed to identify the project. Check that the key is restricted to the intended Firebase APIs, then test Security Rules, Authentication and App Check—the controls that actually protect the data and backend.
Can a public Firebase API key be used to call Gemini?
Only if the key allows the Gemini API. In Google Cloud, open APIs & Services → Credentials, check the API restrictions of every key that ships in an app or website: the Generative Language API (Gemini) should not be on the list. If a public key allowed it, rotate the key and review usage and billing.
Should I hide an API key with obfuscation or encryption?
Only as an extra obstacle for a key that is already safe to distribute. If every copy of the app can decrypt a shared credential, a determined analyst can recover it. A true server secret belongs outside the app.
Does App Check stop every copied or modified client?
No. It adds a useful app-integrity signal and reduces several forms of abuse, but it needs monitoring and fallbacks and does not replace user authentication, server-side authorization, quotas or logs.