---
title: "Ship no secrets in the app package · Agent Wranglers"
url: https://agentwranglers.se/playbook/mobile-apps/data-on-the-device/no-secrets-in-app
updated: 2026-10-21
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Ship no secrets in the app package

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Data on the device](https://agentwranglers.se/playbook/mobile-apps/data-on-the-device.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers). Updated 2026-10-21.

- ID: MOB-20
- Level: Required
- Chapter: [Data on the device](https://agentwranglers.se/playbook/mobile-apps/data-on-the-device)
- Rule: The app package holds no secret keys, passwords or private certificates. Anything the app needs that must stay secret lives behind your own server.
- Risk: Money lost or taken twice
- How: Anyone can unpack an IPA or APK and read every string in it. Obfuscation slows that down but does not stop it. Remote config values are also readable by every install. Call paid services, such as payment or AI providers, from your server, as [keep secret keys on the server](https://agentwranglers.se/playbook/ai-assisted-development/apps-built-with-ai-builders/server-side-keys) says. Keys that must ship, such as a maps key, are public keys. Limit them in the provider's console to your app's bundle ID or signing certificate. Also strip staging addresses and source maps from release builds.
- Check: In CI, unpack the release IPA and APK and run a secret scanner, such as the one in [use TruffleHog to find leaked secrets](https://agentwranglers.se/playbook/stack/testing-and-code-quality/secret-scanner). It finds 0 secrets.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### TypeScript example

```ts
// Bad
const ai = new AiClient({ apiKey: 'sk-live-…' });
// Good
const reply = await fetch('https://api.example.com/coach/reply', { method: 'POST', headers: { Authorization: `Bearer ${sessionToken}` }, body });
```

### Kotlin example

```kotlin
// Bad
val ai = AiClient(apiKey = "sk-live-…")
// Good
val reply = api.post("https://api.example.com/coach/reply", body, bearer = sessionToken)
```

## Sources

- [OWASP MASWE-0004, Sensitive Data Hardcoded in the App Package](https://mas.owasp.org/MASWE/MASVS-STORAGE/MASWE-0004/)

## Related rules

- [Keep secret keys on the server](https://agentwranglers.se/playbook/ai-assisted-development/apps-built-with-ai-builders/server-side-keys) in AI development
- [Use TruffleHog to find leaked secrets](https://agentwranglers.se/playbook/stack/testing-and-code-quality/secret-scanner) in Software choices

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/mobile-apps/data-on-the-device/no-secrets-in-app">Agent Wranglers mobile apps playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Keep tokens and keys in the Keychain or Keystore](https://agentwranglers.se/playbook/mobile-apps/data-on-the-device/keychain-keystore)
- Next: [Check that requests come from your app](https://agentwranglers.se/playbook/mobile-apps/data-on-the-device/app-attestation)
- [Data on the device](https://agentwranglers.se/playbook/mobile-apps/data-on-the-device)
