Security

    Rotating exposed secrets in mobile apps: what to do

    A 2026 view of rotating an exposed API key found in a shipped app: revoke the old key, issue a new one, move it server-side, and ship an update that does not embed it

    When you find an API key or credential embedded in your shipped app, the uncomfortable truth is that it is already compromised, and you cannot take it back. The binary is on devices and in the store, so anyone can extract the key, and removing it from a future build does nothing about the versions already out there. The only real fix is to rotate the secret, revoke the exposed one and issue a new one, and make sure the replacement does not get re-embedded the same way. Here is why rotation is mandatory after exposure and the steps to do it without repeating the mistake.

    Short answer

    If a secret was shipped inside your app, it is exposed and must be rotated, because anyone can extract it from the binary and you cannot recall the versions already installed. Per OWASP MASVS, the response is to revoke the exposed key and issue a new one immediately, then move the secret off the client so the replacement is not re-exposed, assess what the key could access and check for abuse, and ship an updated app that does not embed it. Rotating the key but embedding the new one in the next build just resets the problem, so the durable fix is to keep real secrets on your backend.

    What you should know

    • An embedded secret is already compromised: it can be extracted from the binary.
    • You cannot recall shipped versions: removing it later does not help old installs.
    • Rotate immediately: revoke the exposed key and issue a new one.
    • Do not re-embed the new key: move it server-side, or you repeat the problem.
    • Check for abuse: assess what the key could reach and whether it was used.

    Why must an exposed app key be rotated?

    Because exposure is permanent once a key ships in a binary. An app distributed through the store, or sideloaded, is in users' hands, and its contents can be extracted by decompiling or inspecting it, so any secret compiled in is recoverable. Crucially, you cannot un-ship it: even after you remove the key from a new build, every previously installed version still contains it, and copies of old binaries persist, so the exposed key has to be treated as known to attackers indefinitely. That is why simply deleting the key from your source and shipping an update is not a fix, the old key remains valid and exposed. Rotation, invalidating the exposed key so it no longer works and replacing it with a new one, is the only action that actually closes the exposure.

    What are the rotation steps?

    Revoke, replace, relocate, and review. The table lays them out.

    StepAction
    RevokeInvalidate the exposed key so it stops working
    ReplaceIssue a new key to take over the functionality
    RelocateMove the new secret to your backend, off the client
    UpdateShip an app build that does not embed the secret
    ReviewAssess what the key could access and check for misuse

    The order matters: revoke the exposed key promptly to stop ongoing abuse, issue a replacement, and place that replacement on your server rather than back in the app. Then ship an app update that calls your backend instead of holding the secret, and review your logs and the key's scope to understand what it could have reached and whether it was abused while exposed. Where a key was over-privileged, take the chance to scope the new one down.

    How do you avoid re-exposing the new key?

    Keep it off the client entirely. The mistake that makes rotation pointless is embedding the new key in the next build, which simply re-exposes it the same way, so the durable fix is architectural: real secrets live on your backend, and the app authenticates to your server, which holds the key and performs the privileged operation on the app's behalf. For values that genuinely must live in the app, recognize that they cannot be secret, a public client identifier or a Supabase anon key, for example, is meant to be public, so the protection has to come from server-side rules, like Row Level Security, not from hiding the key. Scope the new key to the minimum it needs, so even if something is exposed again, the blast radius is small. The principle is that a secret you ship is not a secret, so the replacement should never be shipped.

    What to watch out for

    The first trap is removing the key from the source and shipping an update without revoking it, which leaves the exposed key valid for every old install; you must rotate, not just delete. The second is rotating and then embedding the new key in the next build, re-creating the exposure. The third is ignoring what the key could access, when you should review for abuse and scope the replacement down. A pre-submission scan such as PTKD.com (https://ptkd.com) reads the compiled APK, AAB, or IPA against OWASP MASVS and surfaces hardcoded secrets in your build, so you find an exposed key before, or after, it ships and know to rotate it and move it server-side. Finding it is what triggers the rotation.

    What to take away

    • A secret shipped inside your app is already compromised and cannot be recalled, so removing it from a future build does not fix the exposure.
    • Rotate it: revoke the exposed key, issue a new one, move the new secret to your backend, ship an app update that does not embed it, and review for abuse.
    • Do not re-embed the new key, and for values that must live in the app, rely on server-side rules rather than secrecy, scoping keys to the minimum.
    • Use a pre-submission scan such as PTKD.com to find exposed secrets in your build so you know to rotate and relocate them.
    • #secrets-rotation
    • #hardcoded-secrets
    • #api-keys
    • #key-management
    • #owasp-masvs
    • #app-security
    • #mobile

    Frequently asked questions

    If I remove a hardcoded key, is the exposure fixed?
    No. Removing the key from your source and shipping an update does not help the versions already installed, which still contain the key, and copies of old binaries persist. The exposed key remains valid and recoverable, so it must be treated as known to attackers indefinitely. The only action that closes the exposure is rotation: revoking the exposed key so it stops working and issuing a new one, not just deleting it from a future build.
    Why is a key shipped in an app considered compromised?
    Because an app's binary is in users' hands and its contents can be extracted by decompiling or inspecting it, so any secret compiled in is recoverable. And you cannot un-ship it: previously installed versions still contain it and old binaries persist. So a secret you ship is effectively public, which is why embedding a real secret in an app is a problem and why exposure has to be treated as permanent for that key.
    What are the steps to rotate an exposed secret?
    Revoke the exposed key promptly so it stops working, issue a replacement, move the new secret to your backend rather than back into the app, ship an app update that calls your server instead of holding the secret, and review your logs and the key's scope to understand what it could reach and whether it was abused. Where the key was over-privileged, scope the new one down so a future exposure has a smaller blast radius.
    How do I avoid re-exposing the new key?
    Keep it off the client entirely. Embedding the new key in the next build just re-exposes it, so the fix is architectural: keep real secrets on your backend and have the app authenticate to your server, which holds the key and performs the privileged operation. For values that must live in the app, like a public client ID or a Supabase anon key, recognize they cannot be secret and rely on server-side rules such as Row Level Security for protection.
    How do I find exposed secrets in my app?
    Scan the build. A pre-submission scan such as PTKD.com reads the compiled APK, AAB, or IPA against OWASP MASVS and surfaces hardcoded secrets present, so you find an exposed key, before or after it ships, and know to rotate it. Finding it is what triggers the response: revoke and replace the key, move the new one to your backend, and ship an update that does not embed it, then review for any abuse while it was exposed.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free