// PENTEST

The most common mobile app security mistakes

A mobile app differs from a web application in one thing: it runs on someone else’s device, and the attacker holds that device in their hand. They can take the build apart, read what the app has stored on the phone, and listen in on what it talks to. So the most common mobile app mistakes don’t come from exotic attacks. They come from development habits carried over from an environment where nobody took the server apart. Here is what we find on tests and why it happens.

Pentest

By Juraj Daniš

// 01

Data on the phone that anyone can get at

The first category is the easiest to exploit, because it needs no network at all. The app stores login tokens, personal data, or a cache of server responses on the phone, and it stores them in readable form. Anyone who gets to the device or to its backup reads them without cracking anything.

It comes from a habit picked up in server development, where storage sits behind a wall. On a phone there is no such wall. On a device with the system unlocked, rooted on Android or jailbroken on iOS, and in a debug backup as well, the app’s files are readable. A developer who writes a token into a plain file or into SharedPreferences without encryption is counting on protection the phone doesn’t give.

So on a test we look for long-lived login tokens in a readable file, personal data in an unencrypted local database, and a cache that keeps whole API responses even after logout. Sensitive keys belong in the keychain on iOS and in Keystore on Android, the system vaults protected by hardware, not in an ordinary file next to them.

// 02

Secrets hidden in the app

The second category rests on a mistaken belief: that nobody will see what sits inside the build. A developer puts an API key, the address of an internal server, or an access credential into the app and trusts that it is hidden in the binary. It isn’t. The app build can be downloaded and taken apart.

On Android an APK decompiles to something close to source code, and an IPA on iOS gives up plenty too. Strings such as keys, tokens, and server addresses sit in them in the clear or behind trivial encoding. Hiding something in code is not secrecy. It is one step more work, and the attacker takes that step once for every user of the app at the same time.

The worst are keys that open something on the server: a key to a payment gateway, to cloud storage, to a third-party API. Once it is in the build it is public, and replacing it means shipping a new version of the app and waiting for everyone to install it. So secrets belong on the server, not in the app, and the client asks for data over an authenticated session.

// 03

Traffic that can be listened in on

The third category is about the path between the app and the server. Even when the traffic runs over HTTPS, the app may not check who it is really talking to, and then a proxy can be put between it and the server and the traffic both read and changed. What is missing is certificate pinning, that is, pinning a specific server certificate right in the app so it doesn’t trust anyone who holds a valid certificate.

Without pinning, an attacker only needs a certificate the phone trusts, and on a device they control that is easy to arrange. A tester’s proxy is exactly that scenario: we install our own certificate and read what the app and the server send each other. If we can do it, so can an attacker on a spoofed Wi-Fi network or on a compromised device.

We run into harder cases too: traffic that drops from HTTPS to plain HTTP on part of the route, trust in any certificate at all, added to make development easier and left in the production version, and sensitive data sent in the URL, where it ends up in logs. The whole transport gets tested, not just whether the app shows a padlock next to its name.

// 04

A backend that trusts the client

The fourth category is the most expensive, because it isn’t about the phone but about the server behind it. A mobile app is only a client, and the attacker controls it completely: they can bypass the checks in the app and send the API anything they like. When the backend trusts what the client sends, the rest is a formality.

One pattern repeats: authorization is handled in the app, not on the server. A button is hidden, a screen never renders, and the server assumes the client plays fair. But a request to the API can be sent from outside the app. When the server doesn’t verify that the logged-in user may see this particular record, swapping an identifier in the request returns someone else’s data. It is the same class of flaw as on the web, and it is tested on the server, not on the phone.

So we test the backend from the mobile client’s point of view: whether the permission check runs on the server, whether API calls can be replayed and modified, and whether the server validates inputs. A test of a web application and its API on its own is a separate service. The mobile test touches the server only as far as the app talks to it.

// 05

How to avoid these mistakes

The defense follows those four categories, not a list of general advice. Sensitive data belongs in the system vault, the keychain or Keystore, and should never reach a backup at all. Secrets that open something on the server do not belong in the build, and the client asks for data over an authenticated session. The transport is covered by certificate pinning and by removing every shortcut left in the code from development. And authorization is decided on the server for every request, because the client can’t be trusted.

So that neither the developer nor the tester forgets anything, there is OWASP MASVS (Mobile Application Security Verification Standard), the standard for mobile app security, which names the requirements for storage, cryptography, network, and authentication. It works as a checklist during development, not just when the test comes. For the web, OWASP ASVS (Application Security Verification Standard) plays the same role, and MASVS is its counterpart for mobile.

A developer checklist doesn’t replace the view from outside, though. Some of these flaws show up only on a real device and in a running app, not in the code, so it pays to have the mobile app tested before release or after every larger change.

// 06

Is data in a mobile app safe?

Whether the data is safe depends on how the app handles it, not on the brand of phone. Data is put at risk by unprotected local storage, keys hidden directly in the build, traffic that never verifies the server certificate, and a backend that trusts the client. It is safe when sensitive things sit in the system vault, secrets stay on the server, and access is decided by the server, not by the app on the phone.

// 07

Is HTTPS enough for a mobile app?

No. HTTPS encrypts the traffic, but on its own it settles neither who the app is talking to nor what happens on the server. Without certificate pinning, a proxy can be put between the app and the server and the traffic read. And even flawless transport is worth nothing when the backend doesn’t check permissions and trusts what the client sends. HTTPS is a foundation, not the whole defense.

// 08

Are Android and iOS tested differently?

Partly. The goal is the same; the techniques differ by platform. On Android more comes out of decompiling the APK and out of the permissions and components the app exposes to other apps on the phone. On iOS it is more about local storage, the keychain, and behavior on a jailbroken device. When an app ships for both platforms, we test each one separately, because the same code behaves differently on them.

Updated .

// NEXT STEP

Want us to check the same thing in your environment?

Tell us what you want tested. We’ll get back to you and schedule a call to pin down scope, timing, and price.