This repository provides tools and Frida scripts to analyze, intercept and forward network traffic from Flutter applications via Frida. Because Flutter often bypasses system proxy settings and uses custom networking stacks, standard proxy interception fails. The scripts here help identify which client (e.g. dart:io, NSURLSession, NSURLConnection, or WKWebView) is in use and redirect traffic through a proxy for effective reverse engineering.
- Install mitmproxy or Burp Suite on your analysis machine.
- Export and install the proxy’s CA certificate on your iOS device, then enable full trust under Settings --> General --> About --> Certificate Trust Settings.
- Configure your iPhone’s Wi‑Fi proxy manually to point to your machine’s IP and chosen port (e.g.
192.168.1.5:8889). - Run the proxy in standard mode (
mitmproxy -p 8889) or Burp with an “Invisible Proxy” listener. - Use Frida hooks to redirect Dart’s
connect()calls to the proxy (e.g.frida -n YourApp -l intercept_dartio.js) - Refresh the app and watch requests appear in your proxy.
- If traffic is still missing, check which networking stack the app uses by running any of the scripts within the frida_detect_engine folder (Dart:io, Cupertino/NSURLSession, NSURLConnection, WKWebView) and apply the corresponding hook.
Flutter simplifies cross‑platform development, but when it comes to network traffic, it introduces complexities that make traditional proxy interception unreliable. This document explains in detail why Flutter apps often bypass normal proxy setups, the technical background behind it, and what approaches can still work.
Flutter apps can use different networking stacks depending on the code path. The most common is the Dart‑based dart:io HttpClient. Unlike native iOS/Android clients, dart:io often ignores system proxy settings and does not perform the expected proxy handshake, which breaks standard interception with tools like Burp or mitmproxy.
- Core issue: Many Flutter apps connect directly to target hosts without sending a CONNECT request to the proxy.
- Result: Proxies see no traffic, TLS connections fail, or only raw socket streams appear without host context.
- Workarounds: Transparent interception (NAT/pf/iptables), manual proxy configuration plus hooks, installing custom CA certificates, and bypassing certificate pinning.
This repo includes several scripts to make reverse engineering of flutter APIs easier.
| Engine / Library | Detection (iOS) | Detection (Android) | Intercept (iOS) | Intercept (Android) |
|---|---|---|---|---|
| dart:io HttpClient | frida_detect_engine/check_dartio.js | Coming soon | intercept_dartio.js | intercept_dartio.js |
| package:http (default / IOClient) | Coming soon | Coming soon | Coming soon | Coming soon |
| package:http via IOClient | Coming soon | Coming soon | Coming soon | Coming soon |
| cupertino_http (NSURLSession) | frida_detect_engine/check_cupertino.js | N/A | Coming soon | N/A |
| NSURLConnection / CFURL | frida_detect_engine/check_nsurl.js | N/A | Coming soon | N/A |
| WKWebView / WebView | frida_detect_engine/check_webview.js | Coming soon | Coming soon | Coming soon |
| Android HttpURLConnection | N/A | Coming soon | N/A | Coming soon |
| Android OkHttp | N/A | Coming soon | N/A | Coming soon |
| Android Cronet (embedded) | N/A | Coming soon | N/A | Coming soon |
| libcurl (native) | Coming soon | Coming soon | Coming soon | Coming soon |
- No CONNECT handshake unless explicitly configured.
- System proxy often ignored.
- Direct socket calls bypass proxy‑aware APIs.
- Cupertino HTTP (NSURLSession) – may respect system proxy, but often configured to bypass.
- WebView (WKWebView) – traffic depends on WebKit and system settings.
- Native bridges – custom ObjC/Swift/Java networking stacks may ignore proxy.
- Direct TLS connections cannot be intercepted by a standard proxy.
- HTTP/2 and ALPN negotiation requires proper TLS termination.
- ATS and certificate pinning block interception unless bypassed (see accept_all_certs.js for a general ssl pinning bypass)
- IPv6 and QUIC/HTTP/3 introduce additional challenges.
- Proxy shows no traffic.
- mitmproxy transparent mode errors (“cannot resolve original destination”).
- TLS handshake failures.
- Partial visibility (only WebView traffic intercepted).
- Manual proxy in Wi‑Fi settings.
- Frida hook on
connect()to force Dart traffic through proxy. - Install and trust proxy CA.
- Bypass certificate pinning.
- Use
pforiptablesto redirect traffic. - Run mitmproxy in transparent mode.
- On Windows, use WSL or Burp Invisible Proxy mode.
- Dart:io: Hook
connect()inlibsystem_kernel.dylib. - Cupertino/NSURLSession: Hook
-[NSURLSession dataTaskWithRequest:completionHandler:]. - NSURLConnection/CFNetwork: Hook
+[NSURLConnection sendSynchronousRequest:returningResponse:error:]orCFURLConnectionCreateWithRequest. - WebView: Hook
-[WKWebView loadRequest:].
Example App: Fluttida (example_app/fluttida)
![]() |
![]() |
![]() |
![]() |
This repository includes a small Flutter example app located at example_app/fluttida. The app is a network-stack lab and playground designed to help you test, compare, and instrument different HTTP clients and platform stacks while using Frida.
- Enable/disable pinning per stack (dart:io, package:http, Android HttpURLConnection/OkHttp/Cronet, native libcurl).
- Switch between SPKI (public key) and certificate hash pins; import/export pins as base64.
- UI logs show server cert/SPKI hashes alongside configured pins for quick debugging.
- Playground for multiple stacks: run the same request via
dart:io,package:http, iOSNSURLSession(viacupertino_http), Android native stacks (HttpURLConnection, OkHttp, Cronet), and a headless WebView — compare results side-by-side. - Safe instrumentation target: use the app on a device or emulator as a controlled target for Frida scripts so you can attach hooks without affecting production apps.
- Validate hooks & proxying: reproduce real-world scenarios (headers, redirects, TLS behavior) and verify that your Frida scripts (e.g.
intercept_dartio.js) correctly redirect or modify traffic. - Debugging helper: the app shows unified results (
status,body,durationMs,error) and logs, making it easy to observe the effects of your live instrumentation.
- Run the example app on a device or emulator:
cd example_app/fluttida
flutter pub get
flutter run- Attach Frida and load a detection or interception script, for example:
# list processes and attach by name or PID
frida-ps -Uai
frida -U -n Fluttida -l frida_detect_engine/check_dartio.js
# or to intercept
frida -U -n Fluttida -l intercept_dartio.js- Use the app UI to run requests across different stacks and inspect the Results/Logs to confirm whether your hooks or proxying are working as intended.
The lab app also includes native libcurl stacks to compare behavior outside the platform HTTP clients. In case you want to include your own libcurl builds, read the following how-to:
-
Android NDK (libcurl)
- See android/README-libcurl.md for full setup instructions (libraries, headers, CA bundle).
- In the app, select the stack "Android NDK (libcurl)".
-
iOS Native (libcurl XCFramework)
- Place the XCFramework under:
example_app/fluttida/ios/Frameworks/libcurl.xcframework
- The project is wired to link this XCFramework and expose a method channel stack named "iOS Native (libcurl)".
- Build variants:
- Secure Transport (DarwinSSL): libcurl can be built against the Apple TLS stack and will use the system trust store (no OpenSSL files required).
- OpenSSL (static): the repo also supports building libcurl against OpenSSL. If you use the OpenSSL variant, you must bundle the OpenSSL static libraries and a CA bundle with the app (instructions below).
- If you build your own XCFramework, ensure device (arm64) and simulator (arm64/x86_64) slices are present.
OpenSSL (static) packaging (when libcurl was built with OpenSSL):
-
Copy these static libs into the app so the app can link at build time:
example_app/fluttida/ios/Runner/Frameworks/OpenSSL-static/iphoneos/libssl.aexample_app/fluttida/ios/Runner/Frameworks/OpenSSL-static/iphoneos/libcrypto.aexample_app/fluttida/ios/Runner/Frameworks/OpenSSL-static/iphonesimulator/libssl.aexample_app/fluttida/ios/Runner/Frameworks/OpenSSL-static/iphonesimulator/libcrypto.a
-
CA bundle: add a CA bundle (for example
cacert.pemfrom curl) to:example_app/fluttida/ios/Runner/Resources/cacert.pemThe app setsCURLOPT_CAINFOto the bundledcacert.pemat runtime (seeNativeHttp.mm). Ensure the file is included in the Runner target's "Copy Bundle Resources" so it is available at runtime.
-
Project wiring: the project has been updated to add library search paths and link flags for the
OpenSSL-staticfolders and to copycacert.peminto the app bundle. If you prefer, you can instead add the four.afiles as file references under the Runner target.
- Place the XCFramework under:
- The app includes license files under the XCFramework (e.g.,
licenses/COPYING-curl.txt). Keep third‑party license texts with distributed binaries.




