HTTP API call works despite cleartextTrafficPermitted="false" in Android app with minimum SDK 29 and Flutter 3.22.3

I’m facing an issue where an HTTP API call is still working on my Android app despite configuring the app to block cleartext traffic. Below are the details:

Configuration:

AndroidManifest.xml: I have added the following in my AndroidManifest.xml file to disallow cleartext traffic:

<application
    android:usesCleartextTraffic="false"
    ...>
</application>

Network Security Config (network_security_config.xml):

I have created a network_security_config.xml file with the following configuration to ensure no cleartext traffic is permitted:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="false" />
</network-security-config>

API Call (Dio): I am making an HTTP request to an AWS-hosted API that does not have HTTPS and does not perform any HTTPS redirection:

try {
    AppFileLogger.writeErrorLog("Got response.", "Dashboard", "Calling................................................");
    Dio _dio = Dio();

    final response = await _dio.get('http://13.*****.232:8080/****');
    if (response.statusCode == 200) {
        AppFileLogger.writeErrorLog("Got response.", "Dashboard", "=====> ${response.data}");
    } else {
        AppFileLogger.writeErrorLog("Got response.", "Dashboard", "=====> ${response.statusCode} - ${response.data}");
    }
} catch (error) {
    AppFileLogger.writeErrorLog("Got response.", "Dashboard", "=====> $error");
}

Device Information:

  1. Device: Real device Samsung Motorola (Android 14)
  2. Minimum SDK: 29
  3. Flutter Version: 3.22.3
  4. App runs: Release mode

Problem: Despite the network security configuration and the fact that the API is HTTP (not HTTPS), the API call works and I receive a response. The API is hosted on AWS and does not have SSL certificates or HTTPS redirection.

  1. Why is the HTTP call working despite the security configurations to block cleartext traffic?
  2. Could this issue be specific to Flutter or the Android version (Android 14)?
  3. Are there any other settings or configurations I should check to ensure that HTTP calls are blocked in my app?

Any help or insights would be appreciated!

This behavior is likely the result of one or more of the following reasons:


1. network_security_config.xml is not applied correctly

  • The android:networkSecurityConfig attribute in your AndroidManifest.xml is required to link your custom network security configuration (network_security_config.xml) to the app.
  • If this is missing, the default cleartextTrafficPermitted="false" in the <application> tag will not enforce the strict policy across all configurations.

Solution: Ensure your AndroidManifest.xml includes this line inside the <application> tag:

<application
    android:usesCleartextTraffic="false"
    android:networkSecurityConfig="@xml/network_security_config"
    ...>
</application>

2. Specific domain exemption in network_security_config.xml

  • The base-config directive defines the default policy, but individual domains can override this policy. If there is a domain-specific configuration (e.g., <domain cleartextTrafficPermitted="true">), it will allow cleartext traffic for that domain.

Solution: Verify the entire network_security_config.xml to ensure there are no domain-specific exemptions, for example:

<domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="true">example.com</domain>
</domain-config>

Updated network_security_config.xml to block all cleartext traffic:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="false" />
</network-security-config>

3. Flutter-specific behavior

Flutter uses platform channels to call native APIs, and while the network_security_config.xml should apply to native HTTP libraries, certain Flutter HTTP libraries, such as Dio, might bypass the native stack.

Solution: Check the library configuration. Dio, for example, allows configuring a custom HttpClientAdapter. Ensure that the default adapter is not overriding the Android restrictions. To enforce secure traffic:

BaseOptions options = BaseOptions(
    baseUrl: "https://example.com",
    connectTimeout: 5000,
    receiveTimeout: 3000,
);

Dio dio = Dio(options);

dio.httpClientAdapter = DefaultHttpClientAdapter()
  ..onHttpClientCreate = (client) {
      // Enforce strict HTTPS checks here
      client.badCertificateCallback = (X509Certificate cert, String host, int port) => false;
  };

4. Android 14 behavior

Android 14 (API level 34) might have slightly altered network security policies or could behave differently due to updated defaults.

Solution: Double-check the behavior in older Android versions to determine if this is specific to Android 14. You can also try enabling logging for the network security configuration:

adb shell setprop log.tag.NetworkSecurityConfig VERBOSE
adb logcat -s NetworkSecurityConfig

This will help confirm whether the configuration is being enforced.


5. AWS Endpoint Response

The AWS endpoint might have a mechanism to allow HTTP traffic from trusted sources, and it could be responding to requests even if cleartextTrafficPermitted is disabled. However, the issue is more likely to be related to client-side configuration.


Debugging Steps

  1. Verify the android:networkSecurityConfig attribute in AndroidManifest.xml.
  2. Check for domain-specific exemptions in network_security_config.xml.
  3. Test with another HTTP library (e.g., http in Flutter) to confirm that Dio isn’t bypassing restrictions.
  4. Run logging to confirm that the network_security_config.xml is being applied.
  5. Test on a device running a different Android version to rule out platform-specific quirks.

Best Practices for Secure Configurations

  1. Always use HTTPS for API endpoints. Consider setting up an SSL certificate for the AWS API.
  2. Validate and enforce HTTPS within the application logic to ensure that non-secure traffic fails at the client level.
  3. Add automated tests to verify that HTTP traffic is blocked.

By following these steps, you should be able to ensure that HTTP traffic is properly blocked. Let me know if you need further clarification!