August 3, 2026
π© Your App Leaks More Secrets Than You Think Even When Itβs βSecureβ
A Security Audit Case Study: How Attackers Could Access Sensitive Information and How to Stop Them

By Shah Rukh Khan
5 min read
A Security Audit Case Study: How Attackers Could Access Sensitive Information and How to Stop Them
If you've just launched your application to production (or are about to), don't assume it's secure simply because authentication works and your APIs are protected.
Real attackers don't use your application the way legitimate users do. They look for tiny inconsistencies, exposed endpoints, weak validation, leaked client-side information, and misconfigured infrastructure. Individually, these issues may seem harmless. Combined, they can significantly increase your application's attack surface.
The good news is that many of the most impactful security improvements don't require a complete rewrite. Small changes consistent error messages, stronger token validation, proper security headers, server-side secret management, rate limiting, and infrastructure hardening can eliminate entire classes of attacks before they become real problems.
In this article, we'll walk through some of the most common ways attackers could gather information or abuse an application, explain why these issues matter, and show the practical defenses that help prevent them. Whether you're building a SaaS platform, fintech product, healthcare application, or consumer app, these are security practices every production system should have in place.
π© 1. Account Enumeration
What it means: an attacker can figure out which emails, usernames, or phone numbers exist in your system just by watching how the app responds without ever successfully logging in.
Example: if a login form says "email not found" for one case and "wrong password" for another, that difference alone tells an attacker who's registered. The same applies to signup ("email already registered") and password reset flows, and even to response timing β a 200ms reply vs. an 800ms reply can leak the same information as a different error message.
Fix: always return the same message, same HTTP status code, and same response time, regardless of whether the account exists. It feels like a small UX detail, but it's step one of most account-takeover and credential-stuffing attacks β attackers enumerate real accounts first, then focus their brute-force effort only on those.
π© 2. Web Security Essentials
Anything sent to the browser is public, including "hidden" URLs, tokens, or client-side logic. Four changes made the biggest difference:
- BFF (Backend-for-Frontend): don't call internal services directly from the browser. Put a thin server layer between the client and your real backend, so internal endpoints and URLs are never exposed to the user's device.
- CSRF protection: a logged-in user's browser can be tricked into submitting a request without their knowledge. Secure cookies (SameSite) help, but aren't sufficient alone add CSRF tokens to every state-changing request.
- CSP (Content-Security-Policy): explicitly tells the browser which script sources are allowed to execute, blocking most injected or malicious scripts by default.
- XSS prevention via nonce: pair CSP with a nonce a random, per-request value on your script tags. Even if an attacker manages to inject a
<script>tag, it won't execute without the matching nonce.
π© 3. Weak JWT Handling
If access tokens don't expire properly, or their signatures aren't verified correctly, an attacker can forge valid-looking access.
Fix: always enforce expiry server-side, reject tokens with alg: none, and never trust a token signed with an unexpected key. This sounds basic, but it's one of the most common findings in real-world API audits.
π© 4. Obfuscation Is Not Real Protection
We minify and obfuscate our client-side code to make it harder to read β and that's a reasonable thing to do. But it's important to be honest about what it actually achieves: obfuscation slows a reverse engineer down, it doesn't stop one. Treat it as friction, not a lock, and never store anything in obfuscated code that you wouldn't be comfortable making public eventually.
π© 5. Attacks That Just Slow the System Down
Not every attack is about stealing data some are about denying service by exhausting resources.
Examples: unbounded pagination or search queries, oversized file uploads, or firing the same "transfer money" request twice within the same second to race past a check.
Fix: enforce hard limits on file size, query complexity, and pagination, and make sure state-changing actions (especially financial ones) are protected by atomic transactions or idempotency keys not just application-level checks that assume requests arrive one at a time.
π© 6. Infrastructure-Level Protections We Added
- Cloudflare Zero Trust on the admin panel no admin route is reachable without passing this check, regardless of network.
- Bot Management (Cloudflare) β filters out scraping and credential-stuffing traffic before it reaches the application layer.
- Internal-only Swagger/API docs β publicly reachable API documentation is effectively a reconnaissance map handed to an attacker for free.
π© 7. Mobile-Specific Hardening
Mobile apps face a threat model web apps don't: the attacker has a full, unencrypted copy of your binary on their own device, with as much time as they want to inspect it.
- Jailbreak detection (iOS) / Root detection (Android): a jailbroken or rooted device removes the OS-level sandboxing your app relies on for security. Detecting this lets you restrict sensitive functionality (payments, biometric auth) on compromised devices, or at minimum warn the user.
- SSL/Certificate pinning: pins your app to a specific, expected certificate or public key, so a man-in-the-middle proxy (like Burp Suite or mitmproxy) can't transparently intercept and read traffic even over HTTPS. Important nuance: pinning is not unbeatable tools like Frida/Objection can hook and bypass pinning at runtime, which is why it's one layer of defense, not the only one.
- Developer mode / debugger detection: checking for USB debugging, developer options, or an attached debugger lets the app respond defensively for instance, refusing to display sensitive data while a debugger is attached.
- Protection against reverse engineering and
.envexposure: this is the one that catches teams out most often. Anything read viaprocess.envor a.envfile at build time gets compiled directly into the JS bundle shipped inside the app binary. That bundle (Hermes bytecode, for React Native apps) is not encryption it's just bytecode, and public tools can decompile it back into near-readable JavaScript in minutes. The only real fix is architectural: secrets must never live inside a mobile build. They belong server-side, fetched at runtime behind authentication β never baked into the client at build time.
None of these mobile controls are unbeatable on their own, and that's the point they raise the cost and time required for an attacker meaningfully, and they should be layered together, not relied on individually.
π© 8. Extra Rules for Fintech Apps
- Mask sensitive data everywhere card numbers, account numbers, national ID numbers show only the last four digits, always.
- Require step-up authentication (PIN, biometric, OTP) for high-risk actions: transfers, adding a payee, changing a password or email.
- Bind sessions to devices flag or block logins from a new device or location until verified.
- Keep full audit logs for every financial action: who did what, when, and from where.
- Use idempotency keys and atomic database transactions on payment APIs, so a retried or racing request can't cause a double charge.
π© 9. Extra Rules for Social/Consumer Apps
- Enforce privacy at the API level, not just the UI a "private" profile's data shouldn't be fetchable by calling the endpoint directly.
- Apply bot and spam detection on signup, comments, and direct messages.
- Validate uploaded files by content, not file extension, and strip EXIF/location metadata before storing them.
- Prevent IDOR confirm a user can only access their own object IDs (posts, chats, orders), not just that they're authenticated.
Bottom Line
Assume that anything shipped to a browser or a phone can eventually be read by someone else, and design your system around that assumption rather than around trust in the client. None of the fixes above are exotic engineering β they're mostly discipline applied consistently across the frontend, backend, mobile build, and infrastructure layers.
If you've run into similar findings in your own audits, I'd genuinely like to hear about them feel free to share in the comments.