Why Flutter apps need specialised pentesting
Most pentest vendors treat Flutter apps like standard native Android apps. They run MobSF, check for a few common misconfigurations, and call it done. This misses the Flutter-specific attack surface entirely. The Dart runtime, platform channel communication, Flutter's own rendering engine, and the specific local storage libraries used in Flutter apps all require dedicated testing tools and techniques.
We have tested Flutter-based fintech apps from some of Nigeria's fastest-growing startups — digital banks, payment platforms, POS aggregators, and lending apps. The same vulnerability patterns appear across the ecosystem.
What we test in a Flutter penetration test
Dart binary analysis
Flutter compiles Dart to native ARM code, but function names and string constants are often preserved in the binary. We use tools like reFlutter, Blutter, and Doldrums to recover the app's class structure, API endpoint URLs, encryption key material, and business logic. Even without full decompilation, the recovered symbols reveal the app's architecture and attack surface.
Platform channel interception
Flutter communicates with native Android/iOS functionality through platform channels — MethodChannels, EventChannels, and BasicMessageChannels. We intercept these channels using Frida to observe and manipulate the data flowing between the Dart isolate and native code. This reveals biometric authentication responses, cryptographic operations, and native plugin data.
Local storage security
We audit every local storage mechanism: SharedPreferences (plaintext), Hive (optional encryption), sqflite (SQLite, often unencrypted), flutter_secure_storage (Keystore/Keychain-backed), and cached HTTP responses. In Nigerian fintech apps, we consistently find BVN data, session tokens, and PIN hashes stored in SharedPreferences or unencrypted Hive boxes.
SSL pinning and network security
We test certificate pinning implementations including dio with custom certificate validation, http_certificate_pinning, and native-level pinning. Flutter's SSL pinning can be bypassed using reFlutter's traffic interception mode or by hooking the Dart SecurityContext. We verify whether your pinning implementation survives these bypass techniques.
Authentication and biometric flows
We test the local_auth plugin implementation for biometric bypass, PIN brute-forcing, session token handling, and token refresh logic. Common Flutter findings include biometric results that are only validated client-side, PINs that are hashed with weak algorithms (MD5/SHA1), and refresh tokens stored alongside access tokens in unencrypted storage.
Backend API testing
From the Dart binary analysis, we extract every API endpoint and test them for BOLA/IDOR, broken authentication, mass assignment, and business logic flaws. Flutter apps frequently expose admin-level API endpoints that are hidden from the UI but accessible in the compiled binary's string table.
Real findings from Flutter pentests
Transaction PIN stored in SharedPreferences as plaintext
A Nigerian mobile banking app stored the user's 4-digit transaction PIN in SharedPreferences — an unencrypted XML file readable by any app with root access or by anyone with physical access to a backup. The PIN was stored immediately after login and never cleared. Combined with the session token (also in SharedPreferences), an attacker who obtained a device backup could perform transactions without any additional authentication.
Biometric authentication bypass via platform channel hook
The app used the local_auth Flutter plugin for fingerprint login. By hooking the platform channel response using Frida, we intercepted the native biometric result and replaced it with a success response. The Dart code trusted the channel response without server-side verification. An attacker with a rooted device could bypass fingerprint authentication and access any account on that device.
Internal admin API endpoints discoverable in Flutter binary
Using Blutter to analyse the compiled Dart code, we recovered string constants containing API endpoint paths. Among them were /api/admin/users, /api/admin/transactions/reverse, and /api/admin/kyc/override. While these endpoints required admin authentication, their discovery allowed us to test them directly. The /kyc/override endpoint accepted admin-level Basic authentication with a weak default password that had never been changed.
Building a fintech app with Flutter? We test the attack surfaces that generic pentest vendors miss — Dart binary analysis, platform channel interception, and Flutter-specific storage vulnerabilities.
Book a Flutter PentestFlutter vs React Native: security comparison
Nigerian CTOs frequently ask us which framework is more secure. The honest answer: both have vulnerabilities, but the attack profiles differ:
- Reverse engineering: React Native bundles readable JavaScript; Flutter compiles to native ARM code. Flutter is harder to reverse-engineer, but not impossible — we recover function names and strings from both.
- Local storage: Both ecosystems have the same problem — developers default to insecure storage. AsyncStorage (RN) and SharedPreferences (Flutter) are equally unencrypted. The secure alternatives (react-native-keychain, flutter_secure_storage) exist but are underused.
- Network interception: SSL pinning bypass is achievable on both platforms. Flutter's Dart-level pinning requires Flutter-specific bypass tools (reFlutter), while React Native uses standard native pinning libraries.
- The bottom line: Framework choice does not determine security posture. A well-tested Flutter app is more secure than an untested React Native app, and vice versa. Both need penetration testing before handling financial data.
Frequently asked questions
Is Flutter more secure than React Native for fintech apps?
Flutter compiles Dart to native ARM code (AOT compilation), which makes reverse engineering harder than React Native's JavaScript bundles. However, Flutter is not immune to attack. Dart symbols can be recovered, platform channels can be intercepted, and local storage is frequently misused. The security difference between Flutter and React Native is smaller than most developers assume — both require proper hardening and penetration testing.
Can Flutter apps be reverse engineered?
Yes. While Dart AOT compilation produces native ARM machine code (not readable like JavaScript), tools like reFlutter, Doldrums, and Blutter can recover function names, class structures, and string constants from Flutter binaries. This is enough for an attacker to understand your app's architecture, identify API endpoints, and find cryptographic implementations.
What local storage vulnerabilities do you find in Flutter apps?
The most common finding is sensitive data stored in SharedPreferences (Android) or UserDefaults (iOS), which are plaintext XML/plist files. We also find apps using Hive databases without encryption, storing session tokens in unprotected SQLite databases, and caching API responses containing PII in the app's temporary directory. The fix is to use flutter_secure_storage, which wraps the platform Keystore/Keychain.
How long does a Flutter penetration test take?
A Flutter mobile app pentest typically takes 2-3 weeks, covering both Android and iOS builds plus the backend API. We provide a fixed-price quote after a free scoping call. For apps with complex features like biometric payment, agent banking, or multi-wallet systems, we may recommend 3-4 weeks to ensure thorough coverage.
Related reading
Blog: Flutter Security Audit Checklist · React Native Penetration Testing · Certificate Pinning · Biometric Spoofing
Guides: Mobile App Pentesting Guide · OWASP for Fintech
Services: Penetration Testing · API Security Testing