Intercepting Flutter App Traffic When Burp Shows You Nothing
Richard · March 2, 2026
If you’ve ever pointed Burp at a Flutter app and watched the traffic tab stay completely empty, you’re not missing a step in your proxy setup. Flutter apps bundle their own network stack (BoringSSL, compiled into the binary) instead of using the platform’s, so the usual “install a CA cert and set the proxy” approach never touches it.
Why the normal approach fails
A native Android app built on OkHttp or the platform HttpsURLConnection will
respect:
- The system proxy settings
- A user-installed CA certificate (on API 24+, if the app opts in via network security config)
Flutter apps do neither by default. The Dart networking layer talks straight to a statically linked BoringSSL, which ships with its own trust store baked into the binary at compile time. Your CA cert might as well not exist as far as the app is concerned.
Getting visibility with Frida
The fix is to hook the certificate verification function directly in the BoringSSL library the app ships, rather than trying to get the app to trust your proxy. In practice that means:
- Identify the loaded library exporting
ssl_crypto_x509_session_verify_cert_chain(or the equivalent symbol for the Flutter engine version in use) - Hook it with Frida and force a return value indicating a valid chain
- Point the emulator or device’s system proxy at Burp as normal — now that the pinning check is neutralized, the encrypted traffic still terminates fine and Burp can decrypt it
Interceptor.attach(
Module.findExportByName('libflutter.so', 'ssl_crypto_x509_session_verify_cert_chain'),
{
onLeave(retval) {
retval.replace(1);
},
},
);
The exact symbol name shifts between Flutter engine versions, so the first step is always confirming what’s actually exported before writing the hook — don’t assume last year’s script works against this year’s build.
The broader lesson
This is a good example of why “run a scanner and see what lights up” breaks down on Android. Nothing about this required a zero-day or a fuzzer — it required understanding why the traffic wasn’t showing up in the first place, and going one layer deeper than the tooling defaults expect.