Fixing a security vulnerability in your app is only half the job, because the old, vulnerable version is still installed on every device that has it, and users do not all update on their own. You cannot recall a shipped version, so to actually close a vulnerability you need a way to move users onto the fixed build, and for a serious flaw, to require it. That capability, server-driven version gating and the ability to force a critical update, is something to build before you need it. Here is why fixing the vulnerability is not enough and how to get users onto the fixed version.
Short answer
When you fix a security vulnerability, old versions remain installed and still vulnerable, and you cannot recall them, so you need a way to move users onto the fixed version. Per Android's in-app updates guidance, the durable approach is a server-driven minimum-version check: the app asks your backend for the minimum supported version and prompts or requires an update when it is below that, and you can use the platform in-app update mechanisms to deliver it. For a critical flaw, you can require the update before the app functions, and deprecate the old behavior server-side so outdated clients stop working. Build this version-gating capability before you need it, since voluntary updates will not reliably close a vulnerability.
What you should know
- Old versions stay installed and vulnerable: you cannot recall them.
- Users do not all update voluntarily: a fix does not deploy itself.
- Use server-driven version gating: check a minimum supported version.
- Force critical updates: require the update before the app functions.
- Deprecate old behavior server-side: so outdated clients cannot function.
Why isn't fixing the vulnerability enough?
Because the fix only protects users who install it. When you patch a vulnerability and ship a new version, every device still running the old version remains exposed, and you cannot un-ship the old build or pull it from devices. Adoption of a new version is gradual, and a meaningful fraction of users may stay on old versions for a long time unless something prompts or requires them to update. So a security fix that relies on users voluntarily updating leaves the vulnerability live on many devices, sometimes the majority, for as long as those versions persist. The implication is that closing a vulnerability is a distribution problem as much as a code problem: you have to get the fixed version onto devices, which means having a mechanism to drive updates, especially for a serious flaw where waiting for organic adoption is not acceptable.
How do you get users onto the fixed version?
With server-driven version gating and the platform's update mechanisms. The table lists the levers.
| Mechanism | What it does |
|---|---|
| Minimum-version check | App asks your backend for the minimum supported version |
| Update prompt | Encourages users to update when below a recommended version |
| Forced update screen | Blocks the app until the user updates, for critical fixes |
| Platform in-app update | Delivers the update without leaving the app, on Android |
| Server-side deprecation | Disables old behavior so outdated clients stop working |
The foundation is the minimum-version check: your app reports its version to your backend, which tells it the minimum and recommended versions, so you can decide at runtime to prompt for an update or, for a critical security fix, block the app behind a forced-update screen until the user updates. On Android, the in-app update mechanisms can deliver the update in place. And deprecating the old API behavior server-side is the backstop: if outdated clients can no longer talk to your backend, they are effectively forced to update.
How do you force a critical update?
Gate the app on the server-supplied minimum version and back it with server-side deprecation. For a serious vulnerability, configure your backend to set the minimum supported version to the fixed one, so the app, on its version check, shows a forced-update screen and does not function until the user updates, ideally pointing them straight to the store or, on Android, an in-app update. Communicate why an update is required where appropriate, to reduce friction. As the backstop, retire the vulnerable behavior on the server, since if the old version's requests no longer succeed, it cannot keep operating insecurely regardless of whether the user sees the update prompt. Reserve forced updates for genuinely important cases, since they interrupt users, and use softer prompts for non-critical updates. The point is to have the lever ready: when a security fix matters, you can require it rather than hope for adoption.
What to watch out for
The first trap is assuming a security fix is done once you ship it, when old vulnerable versions persist on devices; you need to drive adoption. The second is having no mechanism to force an update when a critical flaw demands it; build version gating before you need it. The third is forcing updates for trivial changes, which annoys users; reserve it for important fixes. Distribution is separate from the binary's contents, so a pre-submission scan such as PTKD.com (https://ptkd.com), which reads the build against OWASP MASVS, is what catches the vulnerability in the first place, while forcing updates is how you deploy the fix. The two ends of the same job: find it, then make sure the fix reaches users.
What to take away
- Fixing a vulnerability is not enough, because old versions stay installed and vulnerable and you cannot recall them, and users do not all update voluntarily.
- Use a server-driven minimum-version check so the app can prompt for or require an update, and use the platform in-app update mechanisms to deliver it.
- For a critical fix, force the update before the app functions and deprecate the old behavior server-side so outdated clients stop working.
- Build version gating before you need it, and pair a pre-submission scan such as PTKD.com, which finds the vulnerability, with a way to push the fix to users.




