CVE-2026-45520 AI-generated analysis
platform/packages/apps/Settings, biometrics/combination (CombinedBiometricSettingsActivity / BiometricsSettingsBase)
BiometricsSettingsBase now honors the EXTRA_USER_ID and gatekeeper password handle (EXTRA_KEY_GK_PW_HANDLE) intent extras only when the hosting SettingsActivity was launched by the Settings package itself. Otherwise it uses the current user and ignores the handle, so the device credential confirmation flow is enforced.
Root cause
In src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java, onAttach() always read Intent.EXTRA_USER_ID from the host activity's intent (mUserId = getActivity().getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId())). onCreate() read the gatekeeper password handle from the same intent through BiometricUtils.containsGatekeeperPasswordHandle()/getGatekeeperPasswordHandle() whenever it was present. Per the commit message, external callers launching CombinedBiometricSettingsActivity could therefore inject a target user ID and a gatekeeper password handle. This let them bypass device credential confirmation and change biometric settings (such as Watch Unlock) for arbitrary users.
How the fix works
- BiometricsSettingsBase.java:onAttach(Context): mUserId is now set to UserHandle.myUserId() and a new field, mAllowInternalExtras, is set to false. Only when the host activity is a SettingsActivity and SettingsActivity.getInitialCallingPackage() equals activity.getPackageName() is mAllowInternalExtras set to true and EXTRA_USER_ID read from the intent.
- BiometricsSettingsBase.java:onCreate(Bundle): the gatekeeper password handle is read only when mAllowInternalExtras && BiometricUtils.containsGatekeeperPasswordHandle(getIntent()). For external callers mGkPwHandle stays 0. The new test testExternalCaller_ignoresSensitiveExtras checks that launchChooseOrConfirmLock() is then called.
- Tests (CombinedBiometricProfileSettingsTest.java): the host activity changes from FragmentActivity to SettingsActivity. The ShadowPasswordUtils shadow is added, with setCallingAppPackageName(mActivity.getPackageName()) in setUp and reset() in tearDown. Two new tests cover an internal caller (extras honored) and an external caller (EXTRA_INITIAL_CALLING_PACKAGE set to a foreign package; extras ignored; confirm lock launched).
Completeness
- Both sensitive extras read by BiometricsSettingsBase (EXTRA_USER_ID in onAttach and the gatekeeper password handle in onCreate) depend on the same mAllowInternalExtras decision, so subclasses of BiometricsSettingsBase inherit the check.
- If the host activity is not a SettingsActivity, the extras are never honored: the code falls back to the current user and no handle.
- The gate depends entirely on SettingsActivity.getInitialCallingPackage() matching the Settings package name. Its implementation is not in the material, so this diff does not show how it determines the caller, or whether EXTRA_INITIAL_CALLING_PACKAGE (used in the test) is trusted or sanitized at the activity level.
- This commit does not touch biometric fragments or activities outside BiometricsSettingsBase that read EXTRA_USER_ID or EXTRA_KEY_GK_PW_HANDLE. The material does not show whether any exist.
Behavior changes
- When a SettingsActivity hosting a BiometricsSettingsBase fragment (such as CombinedBiometricSettingsActivity) is launched by a package other than Settings, EXTRA_USER_ID is ignored and the fragment uses UserHandle.myUserId().
- For such external launches, a supplied gatekeeper password handle is ignored (mGkPwHandle stays 0) and launchChooseOrConfirmLock() is called, as the new test checks.
- If the fragment is hosted by an activity that is not a SettingsActivity, the extras are now ignored even for internal launches.
- For launches by Settings itself, the user ID and gatekeeper handle are still honored.
Per major
- Android 14: Same fix: commit a88ca4587208 in android-security-14.0.0_r29. Same logic, plus an added android.app.Activity import. The test class is @Ignore on this branch. Patched region fully present (8/8 lines).
- Android 15: Same fix: commit 783b7806995f in android-security-15.0.0_r17. Same source logic, with no Activity import added. Test adapted to the branch context. Patched region fully present (8/8 lines).
- Android 16: Same fix: commit 23e5e4077bc9 in android-security-16.0.0_r8. Same source hunks, with surrounding context that includes the mBiometricsAuthenticationRequested field. Patched region fully present (8/8 lines).
- Android 17: Same fix: commit 759e75cec1c1 in android-security-17.0.0_r1. Same source hunks as 16. Patched region fully present (8/8 lines).
Unknowns
- How SettingsActivity.getInitialCallingPackage() is implemented and how it determines the caller. The test sets EXTRA_INITIAL_CALLING_PACKAGE, but the trust model at the activity level is not shown.
- The pre-fix logic in onCreate that decides whether to call launchChooseOrConfirmLock() based on mGkPwHandle, and the downstream code that uses mGkPwHandle/mUserId (the commit message mentions Watch Unlock).
- Whether CombinedBiometricSettingsActivity is exported in the manifest, and whether other Settings fragments read the same extras from externally launchable activities.