Hunting hybrid app bundle and config exposure: when the shipped app carries its own secrets
A mobile app is distributed as a package that lands on every user's device, and anyone can unpack it: the
code, the resources, the embedded web assets of a hybrid app, and the configuration files are all readable.
That is fine for everything a client is meant to hold, and a leak for anything that was meant to stay secret.
Developers ship secrets into the bundle anyway, a backend API key hardcoded in the code, a credential in a
resource file, signing or encryption material in the assets, a private internal endpoint in a configuration,
or a debug or feature flag left enabled that unlocks privileged behavior. Because the app is treated as though
its contents were private, these are shipped as if hidden, when in fact a distributed binary is fully
readable. The bug is not that the app has configuration; it is a secret or an abusable setting that anyone who
unpacks the package can recover and use. You hunt these by unpacking the shipped bundle and reading everything
in it as an attacker would.
When to use
- A mobile app is distributed as a package whose code, resources, and configuration you can unpack.
- A hybrid app embeds web assets and configuration files that may carry secrets or endpoints.
- The bundle may contain hardcoded keys, credentials, private endpoints, or debug and feature flags.
Scope check
Hunt bundle exposure only on apps you own or are authorized to assess, unpacking a package you are permitted
to analyze and proving any recovered secret is usable against test infrastructure rather than production. A
recovered key or credential authenticates or unlocks a real service, so keep every probe within scope and
treat recovered material as sensitive. If you can't name the authorization, stop.
The loop
Establish whether each recovered value is a live secret or an intended client value first. For each
secret-looking string, endpoint, or flag in the bundle, determine whether it is material meant to stay
secret, a backend key, a credential, signing material, a private endpoint, or a privileged toggle, or a
value a client is legitimately meant to hold, a public identifier or a scoped client token that grants
nothing on its own. This is the false-positive killer: a public client identifier or a properly scoped
token that authorizes nothing sensitive is not a finding even though it is in the bundle. Name what the
value grants before claiming exposure.
Unpack the bundle and enumerate its contents. Extract the distributed package and list its code,
resources, embedded web assets, and configuration files. For a hybrid app, include the bundled web assets
and their configuration, which often carry endpoints and keys.
Search for credential and key material. Read the code, resources, and configuration for hardcoded API
keys, backend credentials, signing or encryption keys, and tokens. Note each and what service or capability
it would authenticate to.
Search for private endpoints and settings. Read the configuration and assets for internal or private
endpoints, hosts, and service addresses the app talks to, and for feature or debug flags that unlock
behavior a production user should not have.
Check what each recovered value grants. For each secret, endpoint, or flag, determine whether it is
usable, whether the key authenticates to a live service, the endpoint is reachable, or the flag actually
enables privileged behavior when set, so the exposure has real impact rather than being an inert artifact.
Confirm and record. Confirm by using a recovered secret or setting against test infrastructure you are
permitted to reach, showing the key authenticates, the private endpoint responds, or the flag unlocks
behavior, without acting against production. Kill the lead if every recovered value is a public client
identifier or a scoped token that grants nothing sensitive, if endpoints are public, and if flags do not
enable privileged behavior. Record the value, where in the bundle it was found, what it grants, and the
proof, or set a kill_reason.
Where bundle exposure leaks
- What the value grants is the finding. A distributed bundle is fully readable; the bug is a value in it
that grants something sensitive, not merely a string that looks secret. Name what it unlocks.
- Hardcoded backend keys are live. An API key or credential compiled into the code or a resource
authenticates to the backend for anyone who extracts it, so the client is not a safe place to keep it.
- Hybrid web assets carry endpoints and keys. A hybrid app's embedded web assets and their configuration
often hold service endpoints and keys in plain view, unpacked with the rest of the bundle.
- Private endpoints are disclosed by shipping them. An internal host or service address in the
configuration is revealed to anyone who reads the bundle, mapping the backend for an attacker.
- Shipped debug and feature flags unlock behavior. A debug mode or feature flag left enabled, or settable,
in the bundle can unlock privileged behavior a production user should never reach.
Worked example (a confirm and a kill)
Confirm. A hybrid app's embedded web-asset configuration contains a backend API key and a private
administrative endpoint. Extracting the bundle recovers both, and the key authenticates to the endpoint on
test infrastructure, granting access a client should not have. Confirmed secret and private-endpoint
exposure in the shipped bundle, high, remediation = remove backend keys and private endpoints from the
bundle, have the client obtain scoped short-lived tokens from an authenticated service, and gate privileged
endpoints server-side rather than by a shipped key.
Kill. The same bundle contains only a public client identifier and a token scoped so it authorizes
nothing without a server-side session, the endpoints in the configuration are the public API, and no debug
or feature flag in the bundle enables privileged behavior. Every recovered value grants nothing sensitive on
its own. Killed, kill_reason = "the bundle carries only a public identifier and a scoped token that
authorizes nothing alone, public endpoints, and no privileged flag; nothing recovered from the package grants
sensitive access."
Rationalizations to reject
- "The key is inside the compiled app." -> A compiled app is unpacked and read routinely; compilation is not
concealment, so a key in the binary is a published key.
- "It is only used by our own app." -> Anyone who extracts the bundle can use the same key or endpoint; the
client cannot enforce that only the genuine app holds it.
- "That endpoint is internal." -> Shipping its address in the bundle discloses it, and if it is reachable
the disclosure maps the backend; confirm reachability rather than assuming internal means hidden.
- "The debug flag is off by default." -> If it is settable in the bundle or the configuration, an attacker
on a controlled device can turn it on; confirm the privileged behavior is gated server-side, not by a flag.
- "It is just an obfuscated string." -> Obfuscation slows recovery, it does not prevent it; treat an
obfuscated live secret as exposed.
Executing this in practice
You need the unpacked bundle with its code, resources, embedded web assets, and configuration, every
secret-looking value, endpoint, and flag in it, and for each what it authenticates to or unlocks. For each,
decide whether it is a live secret, a reachable private endpoint, or a privileged flag, or an inert client
value. Reading the unpacked contents settles most leads; using a recovered value against permitted test
infrastructure to show it grants sensitive access settles the rest.
Related
hunting-mobile-secret-and-storage-exposure - the runtime and at-rest secret hunt, of which a secret
compiled into the shipped bundle is the build-time case.
auditing-mobile-backend-and-firebase-exposure - a backend key or endpoint recovered from the bundle feeds
directly into the backend exposure that skill audits.
hunting-firmware-secrets-and-debug-interfaces - the embedded-device analogue, where secrets and debug
interfaces ship inside a readable firmware image.
hunting-mobile-tls-pinning-and-trust-gaps - a private endpoint disclosed by the bundle is reached over a
connection whose transport trust that skill audits.
- FINDING-SCHEMA.md - source = the secret or abusable setting shipped in the bundle,
sink = unpacking the distributed app, evidence = a recovered secret authenticating, a private endpoint
responding, or a flag unlocking behavior on test infrastructure.
1---2name: hunting-hybrid-app-bundle-and-config-exposure3description: Hunt secrets and abusable configuration shipped inside a mobile app bundle, where the installable package carries hardcoded API keys, backend credentials, signing or encryption material, private endpoints, or feature and debug flags in its code, resources, web assets, or configuration files, so anyone who unpacks the distributed app recovers them, because the bundle is treated as private when a distributed binary is fully readable. Use when reviewing what a shipped mobile app package contains, including a hybrid app's embedded web assets and configuration. Covers hardcoded credentials and keys, embedded private endpoints, bundled web-asset secrets, and shipped debug or feature flags. The secret or abusable setting shipped in the bundle is the source, unpacking the distributed app is the sink, and recovering usable material or a privileged toggle from the package is the bug.4license: MIT5---67# Hunting hybrid app bundle and config exposure: when the shipped app carries its own secrets89A mobile app is distributed as a package that lands on every user's device, and anyone can unpack it: the10code, the resources, the embedded web assets of a hybrid app, and the configuration files are all readable.11That is fine for everything a client is meant to hold, and a leak for anything that was meant to stay secret.12Developers ship secrets into the bundle anyway, a backend API key hardcoded in the code, a credential in a13resource file, signing or encryption material in the assets, a private internal endpoint in a configuration,14or a debug or feature flag left enabled that unlocks privileged behavior. Because the app is treated as though15its contents were private, these are shipped as if hidden, when in fact a distributed binary is fully16readable. The bug is not that the app has configuration; it is a secret or an abusable setting that anyone who17unpacks the package can recover and use. You hunt these by unpacking the shipped bundle and reading everything18in it as an attacker would.1920## When to use2122- A mobile app is distributed as a package whose code, resources, and configuration you can unpack.23- A hybrid app embeds web assets and configuration files that may carry secrets or endpoints.24- The bundle may contain hardcoded keys, credentials, private endpoints, or debug and feature flags.2526## Scope check2728Hunt bundle exposure only on apps you own or are authorized to assess, unpacking a package you are permitted29to analyze and proving any recovered secret is usable against test infrastructure rather than production. A30recovered key or credential authenticates or unlocks a real service, so keep every probe within scope and31treat recovered material as sensitive. If you can't name the authorization, stop.3233## The loop34351. **Establish whether each recovered value is a live secret or an intended client value first.** For each36 secret-looking string, endpoint, or flag in the bundle, determine whether it is material meant to stay37 secret, a backend key, a credential, signing material, a private endpoint, or a privileged toggle, or a38 value a client is legitimately meant to hold, a public identifier or a scoped client token that grants39 nothing on its own. This is the false-positive killer: a public client identifier or a properly scoped40 token that authorizes nothing sensitive is not a finding even though it is in the bundle. Name what the41 value grants before claiming exposure.42432. **Unpack the bundle and enumerate its contents.** Extract the distributed package and list its code,44 resources, embedded web assets, and configuration files. For a hybrid app, include the bundled web assets45 and their configuration, which often carry endpoints and keys.46473. **Search for credential and key material.** Read the code, resources, and configuration for hardcoded API48 keys, backend credentials, signing or encryption keys, and tokens. Note each and what service or capability49 it would authenticate to.50514. **Search for private endpoints and settings.** Read the configuration and assets for internal or private52 endpoints, hosts, and service addresses the app talks to, and for feature or debug flags that unlock53 behavior a production user should not have.54555. **Check what each recovered value grants.** For each secret, endpoint, or flag, determine whether it is56 usable, whether the key authenticates to a live service, the endpoint is reachable, or the flag actually57 enables privileged behavior when set, so the exposure has real impact rather than being an inert artifact.58596. **Confirm and record.** Confirm by using a recovered secret or setting against test infrastructure you are60 permitted to reach, showing the key authenticates, the private endpoint responds, or the flag unlocks61 behavior, without acting against production. Kill the lead if every recovered value is a public client62 identifier or a scoped token that grants nothing sensitive, if endpoints are public, and if flags do not63 enable privileged behavior. Record the value, where in the bundle it was found, what it grants, and the64 proof, or set a `kill_reason`.6566## Where bundle exposure leaks6768- **What the value grants is the finding.** A distributed bundle is fully readable; the bug is a value in it69 that grants something sensitive, not merely a string that looks secret. Name what it unlocks.70- **Hardcoded backend keys are live.** An API key or credential compiled into the code or a resource71 authenticates to the backend for anyone who extracts it, so the client is not a safe place to keep it.72- **Hybrid web assets carry endpoints and keys.** A hybrid app's embedded web assets and their configuration73 often hold service endpoints and keys in plain view, unpacked with the rest of the bundle.74- **Private endpoints are disclosed by shipping them.** An internal host or service address in the75 configuration is revealed to anyone who reads the bundle, mapping the backend for an attacker.76- **Shipped debug and feature flags unlock behavior.** A debug mode or feature flag left enabled, or settable,77 in the bundle can unlock privileged behavior a production user should never reach.7879## Worked example (a confirm and a kill)8081> **Confirm.** A hybrid app's embedded web-asset configuration contains a backend API key and a private82> administrative endpoint. Extracting the bundle recovers both, and the key authenticates to the endpoint on83> test infrastructure, granting access a client should not have. **Confirmed** secret and private-endpoint84> exposure in the shipped bundle, `high`, remediation = remove backend keys and private endpoints from the85> bundle, have the client obtain scoped short-lived tokens from an authenticated service, and gate privileged86> endpoints server-side rather than by a shipped key.87>88> **Kill.** The same bundle contains only a public client identifier and a token scoped so it authorizes89> nothing without a server-side session, the endpoints in the configuration are the public API, and no debug90> or feature flag in the bundle enables privileged behavior. Every recovered value grants nothing sensitive on91> its own. **Killed**, `kill_reason` = "the bundle carries only a public identifier and a scoped token that92> authorizes nothing alone, public endpoints, and no privileged flag; nothing recovered from the package grants93> sensitive access."9495## Rationalizations to reject9697- *"The key is inside the compiled app."* -> A compiled app is unpacked and read routinely; compilation is not98 concealment, so a key in the binary is a published key.99- *"It is only used by our own app."* -> Anyone who extracts the bundle can use the same key or endpoint; the100 client cannot enforce that only the genuine app holds it.101- *"That endpoint is internal."* -> Shipping its address in the bundle discloses it, and if it is reachable102 the disclosure maps the backend; confirm reachability rather than assuming internal means hidden.103- *"The debug flag is off by default."* -> If it is settable in the bundle or the configuration, an attacker104 on a controlled device can turn it on; confirm the privileged behavior is gated server-side, not by a flag.105- *"It is just an obfuscated string."* -> Obfuscation slows recovery, it does not prevent it; treat an106 obfuscated live secret as exposed.107108## Executing this in practice109110You need the unpacked bundle with its code, resources, embedded web assets, and configuration, every111secret-looking value, endpoint, and flag in it, and for each what it authenticates to or unlocks. For each,112decide whether it is a live secret, a reachable private endpoint, or a privileged flag, or an inert client113value. Reading the unpacked contents settles most leads; using a recovered value against permitted test114infrastructure to show it grants sensitive access settles the rest.115116## Related117118- `hunting-mobile-secret-and-storage-exposure` - the runtime and at-rest secret hunt, of which a secret119 compiled into the shipped bundle is the build-time case.120- `auditing-mobile-backend-and-firebase-exposure` - a backend key or endpoint recovered from the bundle feeds121 directly into the backend exposure that skill audits.122- `hunting-firmware-secrets-and-debug-interfaces` - the embedded-device analogue, where secrets and debug123 interfaces ship inside a readable firmware image.124- `hunting-mobile-tls-pinning-and-trust-gaps` - a private endpoint disclosed by the bundle is reached over a125 connection whose transport trust that skill audits.126- [FINDING-SCHEMA.md](../../FINDING-SCHEMA.md) - source = the secret or abusable setting shipped in the bundle,127 sink = unpacking the distributed app, evidence = a recovered secret authenticating, a private endpoint128 responding, or a flag unlocking behavior on test infrastructure.