Every banking app I've ever worked on "worked" on the day it shipped. Login worked. Transfers worked. The balance updated correctly after every test case. QA signed off, the release notes went out, and everyone moved on to the next sprint.
And almost every one of those apps still had at least one issue that had nothing to do with whether a feature worked — and everything to do with whether it could be bent. That's the gap functional testing doesn't catch. A banking app can pass 100% of its regression suite and still let someone empty an account, fake a refund, or pull a stranger's statement just by changing a number in a request.
This is why threat-scenario testing matters more in banking than in almost any other category of software. You're not just protecting data — you're protecting money that moves in real time, often irreversibly. A missed XSS bug on a marketing site is embarrassing. A missed authorization check on a fund-transfer API is a regulatory incident.
Below are 20 scenarios I make sure get tested on every banking, NBFC, or payments app I touch — grouped the way they actually surface during an assessment, not in OWASP's order. If you're a developer, a QA engineer, or a security tester, treat this as a working checklist rather than a reading list.
Identity & Access: Where Most Real Damage Begins
1. Predictable or poorly rate-limited OTP
Most banking apps still lean on OTP as the backbone of authentication, and most OTP implementations have at least one soft spot: short length, long expiry windows, no lockout after repeated wrong attempts, or an OTP that stays valid even after a fresh one has been generated. Try it yourself — request an OTP, get it wrong ten times in a row, and see what happens. If nothing does, you've found your first real bug.
2. Session tokens that outlive the logout button
Tap "Logout," then replay the exact same token against an authenticated endpoint a minute later. A surprising number of apps still treat logout as a purely client-side event — the screen changes, but the server-side session is still very much alive. Pair this with a check on whether logging in from a new device actually kills sessions on the old one.
3. Privilege escalation between account roles
Joint accounts, sub-users on a merchant dashboard, family banking apps with a "guardian" and a "minor" profile — anywhere there's more than one role attached to a single account is worth probing. Log in as the lower-privilege user, then swap the account or user ID in an API call to one belonging to the higher-privilege role. If the backend trusts the ID in the request over the ID tied to the session token, you've got a problem.
4. Account-recovery flows that quietly bypass the front door
"Forgot password" and "forgot MPIN" flows get far less scrutiny than login itself, which is exactly why they're worth extra attention. Check whether recovery can be triggered with a SIM-swapped number, whether security questions are guessable, and — this one's easy to miss — whether resetting a password also forces re-registration of biometrics and device binding. If it doesn't, an attacker who takes over recovery has effectively taken over everything downstream too.
Transaction Integrity: The Money Has to Move Exactly Once, Exactly as Authorized
5. Client-side amount tampering
This is the oldest trick in the book and it still works more often than it should. Initiate a transfer, intercept the request after the app has already validated the amount on screen, and change the number before it hits the server. If the backend doesn't independently re-validate the amount against the user's actual limits and balance, the client-side check was theater.
6. Race conditions that enable double-spending
Fire two transfer or withdrawal requests against the same account balance at almost the exact same moment. If the backend reads the balance, processes both requests, and only then writes the updated balance, both can succeed even though only one should have. This is one of the highest-impact bugs you can find in a banking app, and it's also one of the easiest to overlook in a single-threaded test plan.
7. Negative amounts and decimal-precision abuse
Submit a transfer of -500 instead of 500, or try absurd decimal precision like 100.999999999. Some backends round in the attacker's favor, some misinterpret a negative number as a credit instead of rejecting it outright, and some simply crash in a way that leaves a transaction half-applied.
8. Currency conversion and rounding exploitation
Anywhere there's a forex conversion, a wallet-to-bank exchange, or a cashback calculation involving fractions of a rupee, there's a rounding rule. Run the same small transaction hundreds of times and check whether the rounding consistently favors the user. A loss of half a paisa per transaction sounds trivial until it's multiplied across a few hundred thousand accounts.
9. Replay attacks on transaction requests
Capture a completed, valid transaction request and resend it unchanged a few minutes later. Properly built systems reject this through nonces, timestamps, or idempotency keys. Plenty of systems don't, and a captured request becomes a repeatable transaction.
API & Communication: What Happens Between the App and the Server
10. Rate-limit bypass on OTP, PIN, or CVV verification
Brute-forcing a 4 or 6-digit PIN is entirely feasible if there's no lockout. Test whether throttling is tied to the account, the IP, or the device — and then test what happens when you simply change whichever one it's tied to. A counter that resets the moment you rotate your IP isn't really a counter.
11. SSL pinning bypass enabling interception
On a rooted device or emulator with a proxy tool and a pinning-bypass framework, check whether the app still happily talks to a server whose certificate it shouldn't trust. If sensitive payloads — OTPs, account numbers, auth tokens — are visible once pinning is defeated, that's a real interception risk for any user on a compromised device or hostile network.
12. Excessive data exposure in API responses
The endpoint that powers a clean two-line account summary on screen often returns far more than two lines under the hood. Inspect the raw response and look for full account numbers, PAN, linked-card details, or other fields the UI quietly discards. If the data left the server, it's exposed — regardless of what the screen shows.
13. IDOR on account, transaction, or statement identifiers
While authenticated as yourself, substitute another user's account ID, transaction ID, or statement reference into an API call. This is one of the most consistently found issues across banking apps, and one of the most damaging, because it's a direct path to someone else's financial data with no exploit chain required — just a changed number.
14. Webhook and callback spoofing
If your app relies on a payment gateway calling back to confirm success, ask what stops anyone from sending that exact callback directly, without ever touching the gateway. Signature verification on incoming webhooks is non-negotiable here; without it, "payment successful" becomes whatever an attacker says it is.
Mobile & Device: The App Doesn't Control the Device It Runs On
15. Root, jailbreak, and emulator detection bypass
Most apps check for root or jailbreak and then refuse to run, or run in a restricted mode. Most of those checks can be defeated with common, freely available tooling. The real test isn't whether detection exists — it's whether sensitive flows like fund transfer or beneficiary addition still function once detection is bypassed.
16. Insecure local storage of sensitive data
Pull the app's data directory or take a backup, then look through the local database and shared preferences for anything that shouldn't be sitting there in plaintext — auth tokens, account numbers, cached statements. Also check the app switcher: does the app blur its screen when backgrounded, or does it leave the last balance check sitting in plain view in the recent-apps tray?
17. Biometric authentication that's only skin-deep
Test whether the biometric check is enforced server-side or whether it's purely a local "true/false" gate that a modified client could simply answer "true" to. Also check the PIN fallback — it needs the same lockout and rate-limiting protections as biometrics, otherwise it's the easier door right next to the harder one.
Business Logic & Data Hygiene: The Bugs That Don't Show Up in Any Scanner
18. Beneficiary addition without proportionate friction
Adding a new beneficiary is one of the highest-risk actions in a banking app, because it's the first step toward moving money to an account that was never trusted before. Check whether it requires step-up authentication, whether there's a cooling-off period before large transfers to a newly added beneficiary are allowed, and whether the API enforces that limit independently of whatever the UI shows.
19. Loan and credit-limit calculation logic abuse
Income, employment status, and existing obligations typically feed into an eligibility or credit-limit calculation. Try tampering with these fields after the initial client-side check has already run, and test boundary values — an income or age figure sitting exactly on a threshold — to see whether the backend recalculates independently or simply trusts what it's handed.
20. Sensitive data leaking through logs and crash reports
Deliberately trigger a crash mid-transaction and then check what lands in the crash reporting tool. Full request and response bodies, OTPs, and account numbers showing up in a third-party crash analytics dashboard is far more common than most teams realize — and it's a finding that rarely comes up until someone actually goes looking.
Why This List Matters More Than a Clean Scan Report
A clean automated scan tells you the app probably isn't vulnerable to the issues a scanner knows how to look for. It tells you almost nothing about whether the logic of your banking app can be turned against itself — and that logic is exactly where most of the scenarios above live. None of them are exotic. None require zero-days. They require someone to sit down, think like both a tester and a fraudster, and actually try.
If you're building or testing a banking app, don't treat this as a one-time audit checklist. Build it into your test plans, revisit it every release, and add to it as your app grows new features — because every new feature is also a new place for an old assumption to quietly become a new vulnerability.
Top comments (0)