Skip to main content

Android security advice that expired: fourteen statements, and the version that ended each one

Fourteen statements about Android security that were correct when somebody learned them and are not correct now. Each one is paired with the API level, the Android Gradle Plugin version or the Google turndown that falsified it, the platform page it was read from, and that page's own last-updated stamp — because Google revises these pages independently and a claim without a stamp cannot be re-checked. Read 3 September 2026.

By Abhinav A & Siddarth G
September 3, 20269 min read

Almost everything below was correct when somebody learned it. That is what makes it dangerous: it was not picked up from a bad blog post, it was picked up from a good one, and the platform moved underneath it.

Fourteen statements follow. Each one is paired with the thing that falsified it — an API level, an Android Gradle Plugin version, or a Google turndown — and with the page it was read from and that page's own last-updated stamp. The stamps are not decoration. Google revises these pages independently of one another, and the spread across the nine pages behind this article runs from 2026-08-28 to 2025-03-10. A claim about the platform with no stamp attached cannot be re-checked by you, which is the whole failure mode being described here.

Read 3 September 2026, from raw pages rather than from a search result.

1 · The transport layer

1.1 “Android trusts certificates the user installs”

It stopped being the default for anything targeting API 24 or above. The Network Security Configuration page states it plainly: "By default, secure connections (using protocols like TLS and HTTPS) from all apps trust the pre-installed system CAs, and apps targeting Android 6.0 (API level 23) and lower also trust the user-added CA store by default."

Note what the boundary is. It is the level your app targets, not the version of Android the device runs. An app targeting API 24 or above on a device running Android 6 does not trust the user store either.

This is the single most consequential row in the list for anyone testing, because it is why an intercepting proxy that used to just work now needs a debug-overrides block or a rebuilt artefact — and why an app that appears to resist interception may simply be an app targeting API 24 or above.

Page stamp: 2026-08-28.

1.2 “Cleartext was switched off in Android 7”

Android 9, API level 28. The same page gives the whole history in two sentences: "Up to Android 8.1 (API level 27), cleartext support is enabled by default", and "Starting with Android 9 (API level 28), cleartext support is disabled by default."

The adjacent change is what makes this one easy to misremember. API 24 is where the default base-config stopped including the user CA store — compare the two default blocks on the same page — so a real change did happen there. It was a different change, to a different thing.

Page stamp: 2026-08-28.

1.3 “Android does not do certificate transparency”

True until API 36, and it is now three different answers depending on the level. Verbatim, in order:

  • "On Android 15 (API level 35) and lower, certificate transparency is not available."
  • "On Android 16 (API level 36), certificate transparency is disabled by default. Apps can opt in to the feature either globally or on a per-domain basis."
  • "Starting with Android 17 (API level 37), certificate transparency is enabled by default. Apps can opt out of the feature either globally or on a per-domain basis."

So the answer flips from unavailable to available but off to on unless you turn it off, across two releases. An assessment that reports "not supported on Android" is reporting the pre-API-36 platform.

One line beside it is worth carrying, because it catches people out during testing rather than in production: "Certificate transparency verification isn't performed on connections that use custom trust anchors."

Page stamp: 2026-08-28.

2 · The manifest and the components

2.1 “Leaving android:exported unset is a common finding”

It has not been possible to ship one since Android 12. The behaviour-changes page carries it as a warning: "If an activity, service, or broadcast receiver uses intent filters and doesn't have an explicitly-declared value for android:exported, your app can't be installed on a device that runs Android 12 or higher."

Two different conditions are doing work in that sentence and they are easy to run together. The declaration is required of apps that target Android 12 or higher; the install failure happens on devices that run Android 12 or higher. An unset attribute is therefore not a finding you report — it is a build that never reached a handset.

What replaced it as the real finding is android:exported="true" set deliberately, on a component that did not need it.

Page stamp: 2026-08-14.

2.2 “You can enumerate the installed packages to detect root tools”

Not since apps started targeting API 30. The package-visibility page: "When an app targets Android 11 (API level 30) or higher and queries for information about the other apps that are installed on a device, the system filters this information by default. This filtering behavior means that your app can't detect all the apps installed on a device."

Increased visibility is declarable — through the <queries> element, or, as Google frames it, "in the rare cases where the <queries> element doesn't provide adequate package visibility", through the QUERY_ALL_PACKAGES permission, whose use "is subject to approval" if you publish on Play.

Our reading, and it is a reading rather than a quotation: a package-name check written before this and never revisited does not throw and does not warn. It returns a clean result, on a filtered view, and reads as an absence. Whether that matters to you depends on what the check gates, which is a question about your app rather than about the platform.

Page stamp: 2026-08-14.

2.3 “Intent redirection is something you have to defend against yourself”

Android 16 does some of it by default. "Android 16 introduces a by-default security hardening solution to Intent redirection exploits. In most cases, apps that use intents normally won't experience any compatibility issues."

And there is an opt-out, which is the part worth knowing about, because an opt-out in a codebase is a decision somebody made: "In Android 16, you can opt out of security protections by using the removeLaunchSecurityProtection() method on the Intent object."

Page stamp: 2025-03-10 — the oldest of the nine, and the one to re-check first.

3 · The integrity signals

3.1 “Check SafetyNet”

There is nothing to check. "The SafetyNet Attestation API was deprecated in 2022 and fully turned down in January 2025."

Page stamp: 2026-03-06.

3.2 “Play Integrity tells you whether the device is rooted”

By default it does not return the labels people mean by that. MEETS_BASIC_INTEGRITY and MEETS_STRONG_INTEGRITY are among the "optional device labels" a developer has to opt in to receive: "If you opt in to receive additional labels in the integrity verdict, deviceRecognitionVerdict can contain the following additional labels."

An integration that was set up and never revisited is reading a narrower verdict than the conversation about it usually assumes.

Page stamp: 2026-05-01.

3.3 “MEETS_STRONG_INTEGRITY means the device is patched”

On some Android versions, and not on others — the same constant, two meanings. "On Android 13 and higher, the MEETS_STRONG_INTEGRITY verdict requires MEETS_DEVICE_INTEGRITY and security updates in the last year for all partitions of the device." And then: "On Android 12 and lower, the MEETS_STRONG_INTEGRITY verdict only requires hardware-backed proof of boot integrity and does not require the device to have a recent security update."

Google's own recommendation follows from it, and it is the useful half: "when using the MEETS_STRONG_INTEGRITY, it is recommended to also take into account the Android SDK version in the deviceAttributes field."

Page stamp: 2026-05-01.

3.4 “Our attestation verifier pins the Google root, so it is fine”

A second root certificate starts signing on 1 February 2026. From the key attestation page, above the certificate block: "Important: The following root certificate will begin signing attestation certificate chains on February 1, 2026."

This is the only row in the list with a date in front of it rather than behind it, and it is the only one that fails in a direction worth naming: a verifier that hard-codes the single earlier root does not degrade, it rejects. Genuine attestations from new devices are refused, and the refusals look exactly like the attack the verifier exists to stop.

Page stamp: 2026-07-09.

4 · The build

4.1 “Turn on R8 full mode”

The flag that exists is the opt-out, and it used to be the opt-in — the same flag, reversed. The version history states both ends of it. At AGP 7.0: "Full mode available: Introduced as an opt-in feature using android.enableR8.fullMode=true." At AGP 8.0: "Full mode by default: R8 full mode provides significantly more powerful optimization. It is enabled by default. You can opt out using android.enableR8.fullMode=false."

So android.enableR8.fullMode in a gradle.properties file means opposite things depending on when it was written and what it is set to. A line added in 2021 to switch full mode on may now be a line switching it off, if it was ever flipped while debugging and never flipped back. It is worth grepping for rather than reasoning about.

Page stamp: 2026-08-27.

4.2 “Add -repackageclasses to flatten the package structure”

Not needed from AGP 9.1. "Classes repackaged by default: R8 repackages classes (moving them to the unnamed package, at the top level) to compact DEX further, eliminating the need to specify -repackageclasses option."

Page stamp: 2026-08-27.

4.3 “Use getDefaultProguardFile('proguard-android.txt')”

Support for it was dropped at AGP 9.0, and the reason is the interesting part. "Support for getDefaultProguardFile("proguard-android.txt") has been dropped, because it includes -dontoptimize, which should be avoided. Instead, use "proguard-android-optimize.txt"."

Which means a project that used the default file was, by that default, not being optimised — a fact that sat inside a one-line build configuration for years and is worth knowing about any older codebase you inherit.

Page stamp: 2026-08-27.

5 · The Keystore

5.1 “Call isInsideSecurityHardware() to check the key is in hardware”

For anything targeting API 29 or above, the method to call is getSecurityLevel(). The Keystore page splits it by target SDK: "If your app targets Android 9 (API level 28) or lower, inspect the boolean return value of KeyInfo.isInsideSecurityHardware()", and elsewhere, "for apps targeting Android 10 (API level 29) or higher, KeyInfo.getSecurityLevel()".

The replacement is not a rename. The old method answers yes or no; the new one returns a level, and the page's own description of what counts as hardware is "Return values matching KeyProperties.SecurityLevelEnum.TRUSTED_ENVIRONMENT or KeyProperties.SecurityLevelEnum.STRONGBOX" — two values, not one.

Page stamp: 2026-03-06.

6 · How to check any of this without taking our word for it

Every claim above was read from a page you can open. The method is worth more than the list:

  1. Go to the platform page, not to a search result. All nine sources here are on developer.android.com. None of them is behind a login and none needed anything but a fetch.
  2. Read the page's own stamp. It is at the foot of every page on that site, in the form Last updated YYYY-MM-DD UTC. If a claim in front of you has no stamp behind it, that is the missing piece rather than a detail.
  3. Check whether the boundary is about targeting or about running. Most of the rows above turn on it, and most of the wrong versions of them get it backwards.
  4. Search the page for the constant, not for the concept. MEETS_STRONG_INTEGRITY, android.enableR8.fullMode, QUERY_ALL_PACKAGES, isInsideSecurityHardware. Concepts get paraphrased in both directions; identifiers do not.

7 · This page expires too

Everything above is true of this article. Nine pages were read on one day, and Google revises them independently: one of the nine already carries a 2025 stamp, and the difference between the newest and the oldest is more than seventeen months.

So the honest statement is not that this list is correct. It is that on 3 September 2026 each row matched the page it cites, character for character, and that the pages are named so you can do the same thing in less time than it took to read this.

If a row here disagrees with the page it cites, the page is right.

About the authors

Abhinav A

Lead — VAPT & Security Assessments

Leads Security Brigade's VAPT delivery team, having progressed from Security Consultant to Team Lead. Has executed advanced penetration tests across BFSI, fintech, QSR, and telecom — including ICICI Bank, Domino's, and Jubilant FoodWorks.

Siddarth G

Practice Director — Cybersecurity

Leads Security Brigade's offensive security practice with deep expertise in vulnerability research, penetration testing, and red team operations. Ranked Top 80 globally on Bugcrowd.

Continue reading

All articles →

What a Play Integrity verdict actually returns, and who it is evidence for

The Play Integrity API returns three families of verdict, and the labels most conversations about it are really about are not among the ones you get by default. This is what Google documents it returning, the limits Google publishes about its own product, and the reason every documented Android integrity primitive ends up producing evidence for a server rather than an answer for a device. Read 3 September 2026.

Google Play reads your manifest, not your code path

Google Play's restricted-permission rules are written against what an app declares, not against what it calls. An app that never invokes an API but carries the permission line in its merged manifest — because a library put it there — has a store problem before it has a runtime one. The SMS and Call Log groups, QUERY_ALL_PACKAGES, and the eight permissions barred outright from personal loan apps, read off Google's own policy pages. Read 3 September 2026.

Your Data safety form is a declaration about a binary, and the binary keeps changing

Google Play's Data safety form binds every developer with a published app, it covers data handled by third-party libraries and SDKs as well as your own code, and Google's position on who answers for it is one sentence long: you alone are responsible. Which makes it the rare store obligation that is checkable — a declaration and a merged manifest are two artefacts, and they can be read against each other. Read 3 September 2026.