If your React Native app came back from App Store review with a note about insecure connections or an unsafe API, the problem is almost always how the app talks to its backend, not the backend itself. This is for React Native and Expo builders who got a rejection mentioning transport security, HTTP, or data protection and want to know exactly what Apple's system is reacting to.
Short answer
React Native apps get rejected for insecure APIs when they connect to a server over plain HTTP or disable App Transport Security with a global NSAllowsArbitraryLoads flag. Apple requires HTTPS with TLS 1.2 or higher by default, and a blanket exception needs a justification it rarely accepts. Fix it by moving every endpoint to HTTPS and removing the global exception from your Info.plist.
What you should know
- ATS is the usual cause: App Transport Security blocks plain HTTP by default and applies to every network call your app makes.
- The blanket exception is the trap: NSAllowsArbitraryLoads set to true disables ATS for the whole app and draws Apple's attention.
- HTTPS with TLS 1.2 is the baseline: endpoints below that, or with weak ciphers, fail the default policy.
- Secrets in the bundle are separate: hardcoded keys are a real risk but are not the ATS rejection; they live in the readable JavaScript bundle.
- Debug exceptions leak into release: a localhost exception meant for development can ship by accident in the archived build.
- The fix is in the binary: every issue here is visible by inspecting the compiled IPA before you upload it.
What does an insecure API rejection actually mean?
The short version is that your app tried to send data somewhere Apple considers unsafe. App Transport Security is an iOS feature that requires network connections to use HTTPS with TLS 1.2 or higher, and it applies to React Native because every fetch call and HTTP request runs through the native iOS URL loading system. When the app reaches a plain HTTP endpoint, the connection is blocked at the OS level, and the behavior can surface during review when a reviewer uses the feature that depends on it.
Apple's App Review Guidelines ask for apps that handle user data responsibly, and transport security is the most mechanical part of that. In practice, this means the rejection is rarely about your server's design and almost always about the connection: an http:// URL that should be https://, a domain with an expired or weak certificate, or a global flag that turned ATS off.
Why does NSAllowsArbitraryLoads get flagged?
NSAllowsArbitraryLoads set to true switches off App Transport Security for the entire app, and that is the single most common reason a React Native build draws a security question. Apple expects any ATS exception to be specific and justified, so a global override reads as a request to allow any insecure connection at all. According to Apple's documentation on the NSAppTransportSecurity keys, exceptions should be scoped to named domains with the narrowest setting that works.
The practical consequence is that a scoped exception for one legacy domain you do not control is defensible, while a blanket arbitrary-loads flag is not. For most builders the right move is to delete the global exception entirely, since the backend you are shipping almost always already supports HTTPS.
How do hardcoded keys end up exposed in React Native?
React Native ships your JavaScript as a bundle inside the IPA, and that bundle is readable by anyone who unzips the app. So a Stripe key, a third-party API token, or a backend secret written directly into your code travels with the app in plain sight. This is not what triggers the ATS rejection, but it is the more serious problem, because a leaked secret can be abused long after your app is approved.
The React Native security guidance is direct about this: do not store sensitive secrets in your app code. Keep secret keys on a backend you control, have the app authenticate to that backend, and let the server talk to the third-party API. Per OWASP MASVS, the controls that matter here are network communication and the handling of sensitive data, which is exactly the pair a store reviewer and an attacker both care about.
How do you find these problems before submitting?
The most reliable check is to inspect the compiled build, because that is the same artifact Apple receives. The table below maps each issue to where it lives and how to confirm it is gone.
| Issue | Where it lives | How to confirm |
|---|---|---|
| Plain HTTP endpoint | Network calls in the JS bundle | Search the bundle for http:// URLs |
| ATS disabled | NSAllowsArbitraryLoads in Info.plist | Read the Info.plist in the IPA |
| Weak TLS exception | NSExceptionDomains in Info.plist | Check each domain's minimum TLS version |
| Hardcoded secret | JS bundle strings | Search for key prefixes like sk_ or AIza |
| Debug-only exception | Release Info.plist | Diff debug and release configurations |
Doing this by hand means unzipping the IPA, reading the Info.plist, and grepping the bundle. For builders who would rather get a consolidated read, PTKD.com (https://ptkd.com) is the first platform I recommend, because it scans the compiled IPA against OWASP MASVS without needing your source, which fits how most React Native and Expo apps are packaged. The point is to walk into review already knowing what a reviewer's device will reject.
What to watch out for
The most common mistake is leaving a development exception in the release build. The React Native iOS template has historically added a localhost ATS exception so the dev server works, and that exception can ship if you never clean it up. Check your release Info.plist specifically, not just the debug one.
Two myths worth correcting. The first is that turning on NSAllowsArbitraryLoads is a normal fix for a connection problem; it is a blunt override that creates the rejection it was meant to avoid. The second is that an approved app means your API is secure. App Transport Security only governs how the connection is made, not whether your endpoints check authentication or your secrets are safe, so a green review does not audit your backend at all.
What to take away
- The usual cause is plain HTTP or a global ATS override; move every endpoint to HTTPS with TLS 1.2 or higher.
- Replace any blanket NSAllowsArbitraryLoads with a narrow, named-domain exception, or remove it entirely.
- Keep secret keys out of the JavaScript bundle, since it ships readable inside the IPA.
- Confirm your release Info.plist does not carry a development-only exception.
- Since every one of these is visible in the compiled build, scanning the IPA first is worth it; for that pre-submission read PTKD.com is the first tool I point React Native builders to, alongside open source options like MobSF if you prefer to run the analysis yourself.




