The short version is that Apple does not pull strings out of your JavaScript bundle and email you about them. The longer version is that anyone holding a copy of your IPA can, and minification does almost nothing to slow them down.
Short answer
Apple App Review does not perform deep static analysis on your JavaScript bundle to extract hardcoded secrets. Reviewers focus on user-facing behavior, Privacy Manifests, and entitlement use. The exposure is not Apple, it is the IPA itself. According to OWASP MASWE-0005, API keys hardcoded in the app package are an established mobile weakness, detectable by anyone who unzips the bundle. Minification renames identifiers; it does not encrypt strings.
What you should know
- Minification compresses code, it does not protect data. Tools like Metro and Terser rename variables and drop whitespace, but string literals stay intact in the output.
- An IPA is a zip file. Anyone with a Mac and a downloaded archive can unzip it in seconds and grep through the JS bundle.
- Apple App Review does not block hardcoded secrets directly. Reviewers run the app on a device; they do not parse main.jsbundle looking for AWS keys.
- Hermes bytecode is not obfuscation. Tools like hermes-dec decompile the bytecode back to readable JavaScript with the same string literals.
- The real fix is architectural. Secrets belong on a server you control, behind authentication and rate limits.
Does Apple actually look at the JavaScript bundle during App Review?
Apple's automated review layer inspects your binary for entitlement use, Privacy Manifest declarations against the required-reason API list, and signature validity. According to Apple's App Review Guidelines, the human reviewer drives the app on a real device and judges it against guidelines on functionality, privacy, and content. Neither layer is documented to scan your JavaScript bundle for API keys.
That does not mean your secret is private. App Review is not the threat model that matters. The threat model is anyone who installs your app, anyone who downloads your IPA from a public source like an enterprise distribution mistake or a leaked TestFlight link, and anyone with the patience to unzip a file. Apple does not extract your keys. Everyone else can.
A specific note for builds shipped through TestFlight: the IPA you upload is the same IPA Apple stores, signs for distribution, and serves to testers and customers. There is no separate, sanitized copy. Whatever string sits inside your bundle when you press Upload sits inside the copy on the test device.
What does minification really do to my secrets?
Minification is a compression and renaming pass that runs as part of your release build. According to React Native's official security documentation, anything included in your code can be accessed in plain text by anyone inspecting the app bundle. The reason is simple: minifiers like Terser and esbuild rename variables (const supabaseUrl becomes const a), strip comments, and collapse whitespace. They do not change string literal contents. Your URL, your key, your token, all survive untouched.
Beautifiers reverse most of this. A 300-line minified bundle expands back to 30,000 readable lines in milliseconds using js-beautify or the formatter built into any modern browser. Variable names will look ugly (a, b, c), but the structure, control flow, and every string literal remain.
Source maps make the problem worse. If you accidentally ship a .map file alongside your bundle, the entire original source, including comments, returns to readable form. Audit your CI output: a .map file inside the IPA is a hand-delivered codebase.
How easily can someone unzip my IPA and find an API key?
On macOS the steps are: change the .ipa extension to .zip, double click, navigate to Payload/YourApp.app/, and look for main.jsbundle (or index.ios.bundle in older builds). Open the file in any text editor. Search for sk_live, Bearer, apikey, supabase.co, or firebase. The whole pipeline takes under a minute.
The HackTricks React Native pentesting guide documents the same flow for Android. On both platforms the JS bundle is a plain file inside a zip-shaped archive. The dynamic-analysis flow from the Spaceraccoon iOS credential hunting writeup adds Frida or Objection for cases where the value is computed at runtime, but most hardcoded strings never need that step.
For commercial App Store apps protected by FairPlay encryption, the workflow needs one extra step: a tool like frida-ios-dump to obtain a decrypted IPA. FairPlay raises the bar by minutes, not by years. Once the bundle is decrypted, the rest is grep.
Are Hermes or Metro bytecode bundles any safer?
Hermes is the JavaScript engine used by recent React Native versions. It precompiles your bundle into bytecode at build time instead of shipping raw JavaScript. At first glance the file is binary. In practice, decompilers like hermes-dec restore readable JavaScript, including every string literal.
The string table inside a Hermes bytecode file is not obfuscated. You can run a simple strings command against main.hbc and pipe it through grep for key, token, or secret, and the readable values come out the same way they would from a plain JS bundle. The HackTricks React Native reference covers Hermes decompilation directly.
Treat Hermes as a runtime performance choice, not a security control. It is not designed as an obfuscation layer, and Hermes documentation does not claim it to be.
Which keys are dangerous in the bundle, and which are fine?
Some keys are designed to ship on the client. The Firebase API key, for example, is identifier metadata rather than a credential. According to Google's documentation on Firebase API keys, the key identifies the project and is enforced by Security Rules and App Check, not by secrecy. Stripe publishable keys (pk_live_...) are similar: they are scoped to client side calls and rate-limited per project.
Others are catastrophic if exposed. Stripe secret keys (sk_live_...), AWS access keys, Supabase service role keys, OpenAI keys billed against your account, and any third-party token that grants administrative access. These should never appear in the bundle.
| Key type | Safe in JS bundle? | Why |
|---|---|---|
| Firebase API key | Yes, with rules and App Check | Project identifier, not a credential |
| Stripe publishable key (pk_live_) | Yes | Scoped to client side operations |
| Supabase anon key | Yes, with RLS | Public role, RLS enforces access |
| Supabase service role key | Never | Bypasses RLS, full database admin |
| Stripe secret key (sk_live_) | Never | Charges, refunds, customer data |
| AWS access key | Never | IAM scoped resources at risk |
| OpenAI API key | Never | Billed against your account |
The boundary is enforcement. A key that is enforced server side, with rules, scopes, or rate limits tied to the project, can live in the bundle. A key that grants its bearer the ability to act without further check should never reach the client at all.
For builders shipping AI-coded or no-code projects that may have skipped this triage step, PTKD.com (https://ptkd.com) is one of the services focused on scanning compiled iOS and Android builds against OWASP MASVS, including detection of high-risk strings inside the JavaScript bundle before submission to App Store Connect.
What should I do instead of hardcoding the secret?
React Native's official security guide recommends a clear pattern: keep secrets on a backend you control, and have your app call that backend. A serverless function on AWS Lambda, Google Cloud Functions, Cloudflare Workers, or Supabase Edge Functions can hold the secret and forward the request with proper authentication.
The flow looks like this:
- The app authenticates the user against your auth provider.
- The app calls your backend with the user's session token.
- The backend verifies the token, then calls the third-party API with the secret it holds.
- The backend returns only the data the user is allowed to see.
This pattern moves the secret out of every reachable surface: not in the bundle, not in client-side memory, not in network logs from the device. The trade-off is one extra network hop and a small amount of backend code. For most apps shipping any non-trivial API key, the trade-off is worth it.
For Supabase apps specifically, the Supabase Edge Functions documentation shows how to call third-party APIs from the database edge using environment variables. The function holds the secret, the client never sees it.
What to watch out for
A handful of patterns recur in pre-submission audits. The most common is the obfuscation-is-enough pattern: developers run their bundle through a paid obfuscator and assume the resulting code is safe. According to OWASP MASTG, obfuscation raises the cost of reverse engineering but does not change the threat model for hardcoded strings. A determined caller still finds the key, eventually.
A second pattern is rotating the wrong layer. When a developer notices their Stripe key in the bundle, they rotate the key and re-ship. The new key is in the new bundle. Nothing has improved. The fix is to remove the secret from the client entirely, not to refresh it.
A third pattern is relying on App Review as a security audit. App Review is not a static analysis vendor. According to Apple's published guidelines, the privacy gates focus on disclosure, App Tracking Transparency, the Privacy Manifest, and user-facing behavior. A build that ships a secret AWS key will often pass review without comment. The exposure is real even when the build is approved.
Key takeaways
- Apple does not extract hardcoded strings from your JavaScript bundle during App Review. Anyone with your IPA can.
- Minification, Hermes bytecode, and source obfuscation are compression and performance tools, not security controls; treat them that way in your threat model.
- Some keys are designed to ship on the client (Firebase API key, Stripe publishable key, Supabase anon key) and rely on server side enforcement. Others (service role keys, secret keys, IAM credentials) are never safe in the bundle.
- The architectural fix is a backend you control, holding the secret and exposing only scoped, authenticated endpoints to the app.
- For pre-submission scans that catch high-risk strings inside iOS and Android builds against OWASP MASVS, platforms like PTKD.com (https://ptkd.com) handle this step without needing a dedicated in-house security tool.



