DEV Community

Cover image for OWASP Mobile Top 10 — M5: Insecure Communication
Barış Kandemir
Barış Kandemir

Posted on

OWASP Mobile Top 10 — M5: Insecure Communication

Welcome to the fifth article in our OWASP Mobile Top 10 2024 series! In previous articles we covered M1: Improper Credential Usage, M2: Inadequate Supply Chain Security, M3: Insecure Authentication/Authorization, and M4: Insufficient Input/Output Validation. Today we discuss why "we already use HTTPS" isn't a sufficient answer.


Introduction

M5 is the most misleading item on the list, because most teams read it and move on: "We use HTTPS, this doesn't apply to us."

OWASP's definition is far broader. This risk covers all aspects of getting data from point A to point B, but doing it insecurely. It encompasses mobile-to-mobile communications, app-to-server communications, or mobile-to-something-else communications. It includes all communications technologies that a mobile device might use: TCP/IP, WiFi, Bluetooth/Bluetooth-LE, NFC, audio, infrared, GSM, 3G, SMS, etc.

So M5 isn't just "do you use HTTPS." It's all of this:

  • Whether you set up TLS correctly (certificate checking, cipher selection)
  • Whether your traffic is consistent (some endpoints HTTPS, others not)
  • What your third-party SDKs are doing
  • What your WebView is loading
  • What you send over alternate channels like push notifications and SMS

💡 Key point: Just because an app uses transport security protocols doesn't mean it's implemented correctly. HTTPS is not a checkbox; it's a system that must be configured properly.

A specific situation for React Native developers

In React Native the network layer lives in three separate places, and most developers only think about the first:

  1. The JavaScript sidefetch, axios, XMLHttpRequest
  2. Platform configuration — ATS on iOS, Network Security Config on Android
  3. Native modules and SDKs — analytics, ads, crash reporting, payment SDKs

Whatever you do on the JavaScript side, if platform configuration is loose or a third-party SDK uses plaintext HTTP, your app is exposed.


OWASP Assessment

Metric Value Meaning
Exploitability EASY A proxy and the same network is enough
Prevalence COMMON Very frequently found in applications
Detectability AVERAGE Basic flaws are easy, subtle ones are not
Technical Impact SEVERE Account takeover, impersonation
Business Impact MODERATE Privacy violation, reputational damage

⚠️ Compare with M4: M4's exploitability was DIFFICULT; M5's is EASY. Exploiting this doesn't require Frida, reverse engineering, or a custom exploit. Being on the same café Wi-Fi as the victim and setting up a proxy is enough.

To identify basic flaws, you can observe the network traffic on the phone. However, detecting more subtle flaws requires a closer look at the application's design and configuration.


The Scope of M5: What's In, What's Out

This distinction matters because teams often look at the wrong item.

✅ In scope

  • TLS setup and validation failures
  • Weak cipher suites
  • Accepting invalid certificates
  • Plaintext (HTTP) traffic
  • Bluetooth, NFC, WiFi Direct security
  • Sensitive data over SMS/MMS
  • Sensitive data in push notification payloads
  • Mixed SSL sessions

❌ Out of scope

  • Data stored on the device → M9: Insecure Data Storage
  • Weak/predictable session ID, when the channel is secure → M3: Insecure Authentication
  • Weak encryption algorithm outside of transport → M10: Insufficient Cryptography

If the data is being stored locally in the device itself, that's Insecure Data. If the session details are communicated securely (e.g., via a strong TLS connection) but the session identifier itself is bad (perhaps it is predictable, low entropy, etc.), then that's an Insecure Authentication problem, not a communication problem.

Three core risks

The usual risks of insecure communication are around data integrity, data confidentiality, and origin integrity.

Risk Question Example violation
Confidentiality Can someone else read it? Plaintext HTTP, weak cipher
Integrity Can it be changed in transit? Response manipulation via MITM
Origin integrity Is the other side really who it claims? Certificate not validated

If the data can be changed while in transit, without the change being detectable (e.g., via a man-in-the-middle attack) then that is a good example of this risk. If confidential data can be exposed, learned, or derived by observing the communications as it happens (i.e., eavesdropping) or by recording the conversation as it happens and attacking it later (offline attack), that's also an insecure communication problem.


Threat Agents

Most modern mobile applications exchange data with one or more remote servers. When the data transmission takes place, it typically goes through the mobile device's carrier network and the internet; a threat agent listening on the wire can intercept and modify the data if it is transmitted in plaintext or using a deprecated encryption protocol.

📡 An adversary sharing your local network (compromised or monitored Wi-Fi)

  • Café, hotel, airport Wi-Fi
  • Rogue access point ("Free_Airport_WiFi")
  • MITM on the same network via ARP spoofing

📶 Rogue carrier or network devices (routers, cell towers, proxies, etc.)

  • IMSI catcher / fake base station
  • Compromised corporate proxy
  • Router performing DNS hijacking

🦠 Malware on the mobile device

  • An app with VPN permission logging all traffic
  • Social engineering a user into installing a CA cert

Motives vary: stealing sensitive information, conducting espionage, identity theft, and more.


Attack Vectors

While modern applications do rely on cryptographic protocols such as SSL/TLS, they can sometimes have flaws in their implementations.

1. Deprecated protocols and bad configuration

❌ SSLv2, SSLv3, TLS 1.0, TLS 1.1  → Deprecated
⚠️  TLS 1.2                        → Acceptable (with correct ciphers)
✅ TLS 1.3                         → Preferred
Enter fullscreen mode Exit fullscreen mode

Weak cipher suites (RC4, 3DES, NULL cipher, EXPORT grade) are still enabled on many servers.

2. Accepting bad certificates

Accepting self-signed, revoked, expired, or wrong-host certificates. This usually happens when a "temporary workaround" added during development leaks into production.

3. Inconsistency

This is the sneakiest one. The app uses TLS only on select workflows — login over HTTPS but profile images over HTTP, or the main API over HTTPS but the analytics SDK over HTTP.

// This pattern is surprisingly common in real projects
const API_BASE = 'https://api.example.com';        // ✅
const CDN_BASE = 'http://cdn.example.com';         // ❌ Why?
const ANALYTICS = 'http://analytics.vendor.com';   // ❌ Third party
Enter fullscreen mode Exit fullscreen mode

Mixed SSL sessions may expose the user's session ID.


The Communication Surface in React Native

In M4 we listed "trust boundaries." The M5 equivalent is every channel your app talks out on:

  • 🌐 fetch / axios / XMLHttpRequest — the most visible, and usually the only one considered
  • 🖼️ WebView traffic — a separate network stack; mixedContentMode is critical
  • 📦 <Image source={{uri}} /> and video players — loaded natively, subject to ATS/NSC rules
  • 🔌 WebSockets (ws:// vs wss://) — chat, live data; frequently overlooked
  • 📊 Third-party SDKs — analytics, ads, crash reporting, payments. Not your code but your traffic (overlaps with M2)
  • 🔄 OTA updates (CodePush, expo-updates) — a JS bundle is downloaded; is it signature-verified?
  • 🔔 Push notification payloads — passes through third-party servers
  • 📱 SMS / MMS — unencrypted, exposed on the carrier network
  • 📡 Bluetooth / BLE / NFC — IoT integrations, payment terminals
  • 🛠️ Metro dev server (development) — plaintext HTTP; must not leak into production

The rule: Each of these channels must be audited separately. Moving fetch to HTTPS closes exactly one item on the list.


OWASP Example Attack Scenarios

There are a few common scenarios that penetration testers frequently discover when inspecting a mobile app's communication security.

Scenario #1 — Lack of certificate inspection

The mobile app and an endpoint successfully connect and perform a TLS handshake to establish a secure channel. However, the mobile app fails to inspect the certificate offered by the server and the mobile app unconditionally accepts any certificate offered to it by the server. This destroys any mutual authentication capability between the mobile app and the endpoint. The mobile app is susceptible to man-in-the-middle attacks through a TLS proxy.

Scenario #2 — Weak handshake negotiation

The mobile app and an endpoint successfully connect and negotiate a cipher suite as part of the connection handshake. The client successfully negotiates with the server to use a weak cipher suite that results in weak encryption that can be easily decrypted by the adversary. This jeopardizes the confidentiality of the channel between the mobile app and the endpoint.

Scenario #3 — Privacy information leakage

The mobile app transmits personally identifiable information to an endpoint via non-secure channels instead of over SSL/TLS. This jeopardizes the confidentiality of any privacy-related data between the mobile app and the endpoint.

Scenario #4 — Credential information leakage

The mobile app transmits user credentials to an endpoint via non-secure channels instead of over SSL/TLS. This allows an adversary to intercept those credentials in cleartext.

Scenario #5 — Two-factor authentication bypass

The mobile app receives a session identifier from an endpoint via non-secure channels instead of over SSL/TLS. This allows an adversary to bypass two-factor authentication by using the intercepted session identifier.

💡 Note scenario #5: The entire authentication architecture you built in M3 collapses the moment a session ID travels over a plaintext channel. The layers are connected.


Technical and Business Impacts

Technical Impacts — SEVERE

This flaw can expose user data which might lead to account takeover, user impersonation, PII data leaks and more; for instance an attacker might intercept user credentials, session, 2FA tokens which can open the door for more elaborate attacks.

  • 🔴 Account takeover
  • 🔴 User impersonation
  • 🔴 PII data leakage
  • 🔴 Credential interception
  • 🔴 Session token interception
  • 🔴 2FA token interception → door to more elaborate attacks

Business Impacts — MODERATE

At a minimum, interception of sensitive data through a communication channel will result in a privacy violation.

Category Description
Identity theft Acting as the user with intercepted PII
Fraud Financial fraud with intercepted details
Reputational damage Public fallout from a privacy violation
Legal consequences GDPR/CCPA: failing to protect data in transit is a clear violation

ℹ️ Note: OWASP rates the business impact here as MODERATE — one notch below the SEVERE of M3 and M4. The reasoning is that a single MITM attack usually affects a single user: targeted leakage rather than a bulk breach. But at scale (hundreds of users on public Wi-Fi) that distinction disappears.


Prevention Strategies

OWASP's general best practices:

  1. Assume the network layer is not secure and is susceptible to eavesdropping
  2. Apply SSL/TLS to every transport channel the app uses to transmit data to a backend API or web service
  3. Account for outside entities like third-party analytics companies and social networks; avoid mixed SSL sessions as they may expose the user's session ID
  4. Use strong, industry standard cipher suites with appropriate key lengths
  5. Use certificates signed by a trusted CA provider
  6. NEVER allow bad certificates (self-signed, expired, untrusted root, revoked, wrong host...)
  7. Consider certificate pinning
  8. Always require SSL chain verification
  9. Only establish a secure connection after verifying the identity of the endpoint server using trusted certificates in the key chain
  10. Alert users through the UI if the app detects an invalid certificate
  11. Do not send sensitive data over alternate channels (SMS, MMS, or notifications)
  12. If possible, apply a separate layer of encryption to any sensitive data before it is given to the SSL channel — a secondary defense if SSL vulnerabilities are discovered
  13. During development, avoid overriding SSL verification methods to allow untrusted certificates; use self-signed certificates or a local development CA instead
  14. During security assessments, analyze application traffic to see if any goes through plaintext channels

Platform-specific notes

iOS: Default classes in the latest version of iOS handle SSL cipher strength negotiation very well. Trouble comes when developers temporarily add code to bypass these defaults to accommodate development hurdles.

Android: Remove all code after the development cycle that may allow the application to accept all certificates such as AllowAllHostnameVerifier or SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER. These are equivalent to trusting all certificates. Avoid overriding onReceivedSslError to allow invalid SSL certificates.

In React Native, these two warnings translate to the ATS and Network Security Config settings we'll cover next.


React Native Specific Security

1. Disable plaintext traffic at the platform level

This is the first and most important step against M5. It protects at the OS level regardless of what you write in JavaScript.

iOS — App Transport Security (ATS)

When you create a React Native project, Info.plist usually ships with a localhost exception. Check what state it's in for your production build.

<!-- ios/YourApp/Info.plist -->
<!-- ❌ DANGEROUS — allows all HTTP traffic -->
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>
Enter fullscreen mode Exit fullscreen mode
<!-- ✅ SECURE — exception only for the Metro dev server -->
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <false/>
  <key>NSExceptionDomains</key>
  <dict>
    <key>localhost</key>
    <dict>
      <key>NSExceptionAllowsInsecureHTTPLoads</key>
      <true/>
    </dict>
  </dict>
</dict>
Enter fullscreen mode Exit fullscreen mode

⚠️ A release build shouldn't even contain the localhost exception. It's only needed during development to reach the Metro bundler. Use separate Info.plist files for Debug and Release in Xcode, or strip it with a build script.

If NSAllowsArbitraryLoads is enabled, App Store review will ask you to justify it — which is already a warning sign.

Android — Network Security Config

<!-- android/app/src/main/res/xml/network_security_config.xml -->
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <!-- Default: no plaintext anywhere -->
  <base-config cleartextTrafficPermitted="false">
    <trust-anchors>
      <!-- System CAs only — don't trust user-installed CAs -->
      <certificates src="system" />
    </trust-anchors>
  </base-config>

  <!-- Exception for Metro, debug builds only -->
  <debug-overrides>
    <trust-anchors>
      <certificates src="system" />
      <certificates src="user" />
    </trust-anchors>
  </debug-overrides>
</network-security-config>
Enter fullscreen mode Exit fullscreen mode
<!-- android/app/src/main/AndroidManifest.xml -->
<application
  android:networkSecurityConfig="@xml/network_security_config"
  android:usesCleartextTraffic="false"
  ...>
Enter fullscreen mode Exit fullscreen mode

It's critical that <certificates src="user" /> appears only inside <debug-overrides>. If that line sits in base-config, the app trusts any CA the user installed on their device — that is, any proxy — which opens the door to MITM.

Expo projects

In Expo these settings are managed through app.json / app.config.js:

// app.config.js
export default {
  expo: {
    ios: {
      infoPlist: {
        NSAppTransportSecurity: {
          NSAllowsArbitraryLoads: false,
        },
      },
    },
    android: {
      usesCleartextTraffic: false,
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

2. Certificate / Public Key Pinning

Platform configuration says "there must be a valid certificate." Pinning says "it must be this certificate." The difference is whether a proxy CA installed on the user's device (Burp, Charles, a corporate MITM box) can read your traffic.

Which library?

Library Approach Note
react-native-ssl-public-key-pinning Public key hash pinning Covers standard networking APIs automatically
@bam.tech/react-native-ssl-pinning Expo module + plugin Installed via Expo config plugin
react-native-ssl-pinning Provides its own fetch Only that fetch is protected

The most important difference: some libraries give you their own fetch, others cover the whole network layer. With the former, code using axios or <Image> is not protected.

All network requests done through the standard Networking APIs will have the certificate pinning configuration automatically enabled after initialization.

Public key pinning implementation

// services/sslPinning.js
import { initializeSslPinning } from 'react-native-ssl-public-key-pinning';

export async function setupSslPinning() {
  // You may want pinning off in development —
  // but gate it ONLY behind __DEV__
  if (__DEV__) {
    console.log('SSL pinning disabled (dev build)');
    return;
  }

  await initializeSslPinning({
    'api.mycompany.com': {
      includeSubdomains: true,
      publicKeyHashes: [
        // Public key hash of the current certificate
        'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
        // ✅ BACKUP PIN — mandatory for rotation
        'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=',
      ],
    },
  });
}

// Call in App.tsx BEFORE any network request happens
useEffect(() => {
  setupSslPinning();
}, []);
Enter fullscreen mode Exit fullscreen mode

The most common pinning mistakes

Mistake 1: A single pin. When your certificate is renewed, the app breaks completely and users get no service until they update. At least one backup pin is mandatory.

Mistake 2: Pinning the leaf certificate. The leaf changes most often (every 90 days with Let's Encrypt). Pinning the intermediate CA's public key is far more stable.

Mistake 3: No rotation plan. Add the new pin to the app and ship it before renewing the certificate; change the server certificate only after users have updated. Reverse that order and the app breaks.

Mistake 4: Embedding certificates in JS. The hashes aren't secret anyway (they're derived from public keys), but having the pinning logic on the JS side makes it easier to bypass with Frida. Prefer libraries that operate at the native layer.

Mistake 5: Disabling in debug and never testing production. If you wrote if (__DEV__) return;, you have not tested pinning in a release build. Always produce a release build and try it against a proxy.

The limits of pinning

Pinning makes MITM harder but doesn't solve it. A determined attacker on a rooted/jailbroken device can bypass the pinning check with Frida. Position pinning as "a layer against casual MITM and corporate proxies," not as an unbreakable shield.


3. Consistency: audit every channel

This is the most commonly missed area. You moved the main API to HTTPS — what about the rest?

// utils/urlAudit.js
// A simple guard that catches plaintext URLs during development

const isHttp = (url) => typeof url === 'string' && url.startsWith('http://');

export function assertSecureUrl(url, context = 'request') {
  if (isHttp(url)) {
    const message = `Insecure URL (${context}): ${url}`;
    if (__DEV__) {
      throw new Error(message);  // Fail loudly in dev
    }
    console.error(message);      // Log in prod
    return false;
  }
  return true;
}
Enter fullscreen mode Exit fullscreen mode
// Central check via an Axios interceptor
apiClient.interceptors.request.use((config) => {
  const fullUrl = `${config.baseURL ?? ''}${config.url ?? ''}`;
  assertSecureUrl(fullUrl, 'axios');
  return config;
});
Enter fullscreen mode Exit fullscreen mode

WebView traffic

<WebView
  source={{ uri: url }}
  // ✅ No mixed content — an HTTPS page can't load HTTP resources
  mixedContentMode="never"
  // ✅ Remember from M4: origin allowlist
  originWhitelist={['https://app.mycompany.com']}
  onShouldStartLoadWithRequest={handleShouldStartLoad}
/>
Enter fullscreen mode Exit fullscreen mode

mixedContentMode defaults to never on Android, but writing it explicitly documents the intent against someone flipping it to always later.

Images and media

// ❌ HTTP image — passes if ATS/NSC is off, leaks the user's profile photo
<Image source={{ uri: 'http://cdn.example.com/avatar.png' }} />

// ✅ The schema validation from M4 helps here too
const AvatarSchema = z.string().url().startsWith('https://');
Enter fullscreen mode Exit fullscreen mode

In M4 we wrote avatarUrl: z.string().url().startsWith('https://'). That validation was actually an M5 control — the layers reinforce each other.

WebSockets

// ❌ Unencrypted WebSocket
const ws = new WebSocket('ws://chat.example.com');

// ✅ Over TLS
const ws = new WebSocket('wss://chat.example.com');
Enter fullscreen mode Exit fullscreen mode

ws:// is easy to miss because neither ATS nor Network Security Config always blocks it — and the data carried in chat apps is highly sensitive.


4. Keep sensitive data off alternate channels

OWASP is explicit: do not send sensitive data over SMS, MMS, or notifications.

// ❌ Sensitive data in a push notification payload
{
  title: 'Payment Confirmation',
  body: 'Transfer of $5,000 to account ending 8413',
  data: {
    accountNumber: '1234567890',
    otpCode: '482915',          // ❌ NEVER
  }
}

// ✅ Send a reference only; fetch the data in-app over a secure channel
{
  title: 'Payment Confirmation',
  body: 'You have a new transaction',
  data: {
    type: 'PAYMENT',
    transactionId: 'TXN-8829301',   // Just an ID
  }
}
Enter fullscreen mode Exit fullscreen mode

Push notification payloads pass through Apple's (APNs) and Google's (FCM) servers and appear on the device lock screen. Those two facts are reason enough to keep sensitive data out of them.


5. An extra encryption layer for sensitive data

OWASP's 12th recommendation: where possible, apply a separate layer of encryption to sensitive data before handing it to the SSL channel. That way, if a vulnerability is discovered in SSL later, you have a secondary defense.

This isn't necessary for every app — but it's worth considering in flows carrying payments, health data, or identity documents.

// Example: encrypt a sensitive payload before sending
import { encryptPayload } from './crypto';

async function submitSensitiveData(data) {
  // TLS is already there; this is a second layer
  const encrypted = await encryptPayload(data, serverPublicKey);

  return apiClient.post('/sensitive-endpoint', {
    payload: encrypted,
    // Metadata can stay plain
    version: 2,
  });
}
Enter fullscreen mode Exit fullscreen mode

A caution: don't invent this layer yourself. Use a library, think through key management, or you'll land in M10 (Insufficient Cryptography).


6. Don't let development conveniences reach production

Most M5 violations come not from malice but from a convenience added during development and then forgotten.

// ❌ None of these lines should ship to production

// 1. Globally disabling certificate validation
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

// 2. Accepting self-signed certs for the QA server
const agent = new https.Agent({ rejectUnauthorized: false });

// 3. Logging sensitive data
console.log('Token:', accessToken);
console.log('API response:', JSON.stringify(response.data));
Enter fullscreen mode Exit fullscreen mode

The third is especially insidious: console.log output is readable via adb logcat on Android and Console.app on iOS. Anyone with physical access to the device — and in some cases another app — can read those logs.

// babel.config.js — strip console calls in production builds
module.exports = {
  presets: ['module:@react-native/babel-preset'],
  env: {
    production: {
      plugins: [
        ['transform-remove-console', { exclude: ['error', 'warn'] }],
      ],
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

Network inspectors in debug tools like Flipper and Reactotron should also be off in production builds. If you are building an iOS Expo development build and want to test out your pinning configuration, you will need to disable expo-dev-client's network inspector as it interferes with the pinning setup. The network inspector is automatically disabled on production builds.


7. Third-party SDK traffic

In M2 we discussed supply chain security. From an M5 perspective the question is: where and how do these SDKs talk?

# Audit the network behaviour of your dependencies
# 1. Run the app through a proxy, list every host it contacts
# 2. Investigate every host you didn't expect
Enter fullscreen mode Exit fullscreen mode

Checklist:

  • Does the SDK use HTTPS, or does it fall back to HTTP "for performance"?
  • Does the SDK do its own certificate validation, or use the system stack?
  • Does the telemetry it sends contain sensitive data?
  • Do the SDK's hosts require an ATS/NSC exception? (If so, that's a warning sign.)

Testing Strategies

The good news about M5: it's easier to test than the other items. Set up a proxy and look at the traffic.

Traffic inspection with a proxy

# 1. Install mitmproxy
pip install mitmproxy
mitmproxy --listen-port 8080

# 2. Point the device at the proxy (Wi-Fi settings)
# 3. Install the mitmproxy CA certificate on the device
# 4. Run the app and watch the traffic
Enter fullscreen mode Exit fullscreen mode

Expected results:

Scenario Without pinning With pinning
Proxy CA not installed Connection fails Connection fails
Proxy CA installed ⚠️ Traffic visible ✅ Connection refused

The second row is the critical one: if you can read traffic while the proxy CA is installed, pinning isn't working.

Scanning for plaintext traffic

# Any HTTP in the app's traffic?
mitmdump -s flow_filter.py
Enter fullscreen mode Exit fullscreen mode
# flow_filter.py — report plaintext requests
def request(flow):
    if flow.request.scheme == "http":
        print(f"⚠️  PLAINTEXT: {flow.request.pretty_url}")
Enter fullscreen mode Exit fullscreen mode

Server-side TLS configuration

# Comprehensive TLS audit with testssl.sh
docker run --rm -ti drwetter/testssl.sh https://api.mycompany.com

# What to check:
# - Are TLS 1.0/1.1 disabled?
# - Are weak ciphers (RC4, 3DES, NULL) disabled?
# - Is the certificate chain complete?
# - Is the HSTS header present?
Enter fullscreen mode Exit fullscreen mode

For a publicly reachable endpoint, SSL Labs is an easier alternative — and it's also where you can grab the public key hashes needed for pinning.

Automated tests

// __tests__/network.security.test.js

describe('URL security audit', () => {
  it('should have no HTTP URLs in configuration', () => {
    const config = require('../src/config/endpoints');
    const urls = Object.values(config).filter(v => typeof v === 'string');

    urls.forEach(url => {
      expect(url).not.toMatch(/^http:\/\//);
    });
  });

  it('WebSocket URL should be wss://', () => {
    const { WS_URL } = require('../src/config/endpoints');
    expect(WS_URL).toMatch(/^wss:\/\//);
  });
});
Enter fullscreen mode Exit fullscreen mode
# Search the source for plaintext URLs in CI
grep -rn "http://" src/ --include="*.ts" --include="*.tsx" \
  | grep -v "localhost" \
  | grep -v "127.0.0.1" \
  && echo "❌ Plaintext URL found" && exit 1
Enter fullscreen mode Exit fullscreen mode

Manual test scenarios

Test Method Expected
Certificate validation Connect to a server with an invalid cert Connection refused
Pinning Run the app on a device with the proxy CA installed Connection refused
Plaintext Scan all traffic in the proxy No HTTP requests
Mixed content Open a page with HTTP resources in the WebView Resource not loaded
Release build Check ATS/NSC settings in the release APK/IPA NSAllowsArbitraryLoads=false
Log leakage Search for tokens with adb logcat No tokens visible

Tools and Resources

Traffic analysis

Tool Use Case Note
mitmproxy CLI proxy, scriptable Ideal for automated testing
Burp Suite Comprehensive security testing The standard for mobile testing
Charles Proxy GUI proxy Easy to use
Wireshark Packet-level analysis For layers below TLS

TLS configuration auditing

Tool Use Case
testssl.sh Server TLS configuration scanning
SSL Labs Web-based, for public endpoints
Mozilla SSL Config Generator Generating server configuration

React Native libraries

Library Purpose
react-native-ssl-public-key-pinning Public key pinning, covers the whole network layer
@bam.tech/react-native-ssl-pinning Expo module + config plugin
babel-plugin-transform-remove-console Strips logs in production

Useful resources

Resource URL
OWASP M5 owasp.org/www-project-mobile-top-10
OWASP MASVS-NETWORK mas.owasp.org
Transport Layer Security Cheat Sheet cheatsheetseries.owasp.org
Android Network Security Config developer.android.com/training/articles/security-config
Apple ATS documentation developer.apple.com

Conclusion

M5 is too broad an item to close with the sentence "we use HTTPS." The real question isn't whether you use HTTPS, but whether you use it consistently across every channel and with the right configuration.

🎯 Security Roadmap

1. Beginner level

  • ATS: NSAllowsArbitraryLoads = false (no exceptions in release)
  • Android: usesCleartextTraffic = false + network_security_config
  • All endpoints HTTPS, WebSockets wss://
  • Strip console.log in production
  • No sensitive data in push/SMS payloads

2. Intermediate level

  • Certificate/public key pinning (with a backup pin)
  • WebView mixedContentMode="never"
  • Audit third-party SDK traffic
  • Scan for plaintext URLs in CI
  • Proxy-test the release build

3. Enterprise level

  • Pin rotation procedure and automation
  • Extra encryption layer for sensitive payloads
  • Server-side TLS hardening (TLS 1.3, HSTS)
  • Continuous traffic monitoring and anomaly detection
  • Penetration testing and bug bounty

Key Takeaways

  1. Exploitability is EASY. Exploiting this needs no special skill — the same Wi-Fi and a proxy is enough. That's why it belongs high in your priority list.

  2. Consistency is everything. One HTTP endpoint can devalue the ninety-nine you moved to HTTPS.

  3. Platform configuration comes before JavaScript. ATS and Network Security Config are the last line of defense against mistakes in your code.

  4. Pinning is a layer, not a solution. Effective against corporate proxies and casual MITM; a delay against a determined attacker.

  5. Don't pin without a backup pin. Pinning without thinking through certificate rotation is the fastest way to lock yourself out.

  6. Development conveniences are the biggest source of risk. rejectUnauthorized: false, NSAllowsArbitraryLoads, debug logs — all added in good faith and forgotten.

  7. M5 is intertwined with the other items. An intercepted session token breaks M3; a WebView loading HTTP content overlaps with M4; SDK traffic connects to M2.

Next Steps

In our next article, we'll examine M6: Inadequate Privacy Controls. We'll cover the responsibilities of mobile apps in collecting, processing, storing, and sharing personal data, along with permission management, data minimization, and privacy-by-design principles.


References


This article is the fifth in the OWASP Mobile Top 10 2024 series. Previous articles covered M1: Improper Credential Usage, M2: Inadequate Supply Chain Security, M3: Insecure Authentication/Authorization, and M4: Insufficient Input/Output Validation. Follow along for the rest of the series!

Top comments (0)