Frontend JavaScript is public by definition
Every line of JavaScript your browser executes is available to anyone who opens DevTools. Right-click, Inspect, Sources tab. That's it. Your React components, your Vue logic, your API endpoint paths, your client-side validation rules — all of it is there.
Webpack, Vite, and other bundlers combine and minify your code, which makes variable names shorter and removes whitespace. Some developers treat this as a security measure. It is not. Minification is a performance optimisation. A tool like js-beautifier reverses most of it in seconds, and meaningful string literals (API URLs, error messages, route patterns) survive minification untouched.
Source maps make it even easier
If you deploy source maps to production (and many teams do by accident), the original, unminified source code is fully reconstructable. Every function name, every comment, every variable name — exactly as your developers wrote it. We find production source maps in roughly one out of three penetration tests we run for web applications.
Check your build configuration now. In Next.js, verify productionBrowserSourceMaps is false. In Vite, check that build.sourcemap is not set to true. In Webpack, ensure devtool is set to false or hidden-source-map for production builds.
Source maps exposing business logic
During a web application assessment for a Nigerian payment processor, we recovered the complete frontend source code including internal API schemas, admin route paths, and fee calculation logic — all from production source maps served alongside the minified bundle.
Mobile apps are decompilable
If you build a mobile fintech app — whether native Android (Kotlin/Java), native iOS (Swift), React Native, or Flutter — the compiled binary is extractable and reversible.
Android (APK/AAB)
Tools like jadx, apktool, and dex2jar decompile Android apps back to readable Java/Kotlin source. Smali/baksmali provides lower-level disassembly. The result isn't a perfect copy of your original code, but it's close enough to extract API keys, endpoint URLs, hardcoded tokens, business logic, and authentication flows. For mobile app pentests, this is always the first step.
iOS (IPA)
iOS apps compiled as Mach-O binaries are harder to decompile than Android, but not secure. Tools like Hopper, Ghidra, and class-dump extract class structures, method names, and string constants. On jailbroken devices, runtime analysis tools like Frida can hook into live method calls, bypass certificate pinning, and modify return values in real time.
Flutter and React Native
Flutter compiles to native code, but the Dart snapshot format is reversible with tools like darter and reFlutter. React Native bundles ship a JavaScript bundle (index.android.bundle) that's essentially the same as web JavaScript — fully readable, just minified. Any API key, secret, or business logic in that bundle is extractable.
What obfuscation actually does (and doesn't)
Obfuscation renames variables, shuffles control flow, and adds dead code to make reverse engineering slower. ProGuard/R8 for Android, obfuscation plugins for Flutter, and JavaScript obfuscators all fall into this category.
What obfuscation does: increases the time and skill required to understand your code. What obfuscation does not do: prevent a determined attacker from extracting secrets, understanding API flows, or bypassing client-side checks. String literals, API endpoints, and cryptographic keys are typically unaffected by obfuscation. Treat obfuscation as a speed bump, never as a wall.
Wondering what an attacker could extract from your mobile app or frontend? We can show you exactly what's exposed.
Request a security assessmentWhat to move server-side
The fix is architectural, not cosmetic. Anything that would cause damage if an attacker saw it must live on your server, not in the client. Specifically:
- API keys and secrets — all third-party credentials (Paystack, Flutterwave, Mono, Termii) must only exist on your backend. See our guide on where to store API keys.
- Business logic that enforces pricing or limits — fee calculations, transfer limits, credit scoring thresholds. If the client computes these, an attacker can modify them.
- Authorization decisions — never rely on client-side role checks. The server must enforce every permission. This is how BOLA vulnerabilities occur.
- Validation rules — client-side validation is UX. Server-side validation is security. Always validate on the server even if you also validate on the client.
What's safe to keep client-side
Not everything needs to move. Public API keys (like a Paystack public key meant for initialising transactions) are designed to be client-facing. UI routing logic, display formatting, and non-sensitive utility functions are fine. The test is simple: if an attacker reads this code, can they escalate access, steal data, or manipulate transactions? If yes, move it.
Practical checklist
- Disable source maps in production builds across all frameworks
- Audit your frontend bundle for hardcoded secrets using tools like
trufflehogorgitleaks - Implement the backend proxy pattern for all third-party API calls from mobile apps
- Enable ProGuard/R8 for Android release builds
- Implement certificate pinning for mobile API connections (and test that it works with tools like Frida)
- Move all authorization, pricing logic, and sensitive validation to the server
- Run a web app pentest or mobile app pentest to verify nothing sensitive is exposed
Client code is attacker-readable code
Minification is not security. Obfuscation is not security. Compilation is not security. The only reliable protection for sensitive logic and credentials is keeping them on infrastructure you control — your server, your backend, your API. Design your architecture with this assumption from day one.
Related reading
Blog: Where to store API keys · .env files in production · Secure your fintech API
Guides: Mobile app pentesting · Web app pentesting · Security checklist
Services: Penetration testing · API security · Vulnerability assessment