{
 "month": "2024-11",
 "generated": "2026-10-06T12:05+00:00",
 "majors": {
  "14": {
   "counts": {
    "announced": 14,
    "certain": 14,
    "probable": 0,
    "not_published": 0,
    "not_covered": 0,
    "awaiting": 0
   },
   "advisories": [
    {
     "cve": "CVE-2024-29779",
     "osv_id": "ASB-A-329701910",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds the SetAttestationIdsKM3 (0xc001) legacy Trusty Keymaster message to the is_trusty_provisioning_code and is_trusty_provisioning_req predicates in platform/system/keymint wire/src/legacy.rs, so it is classified as a provisioning request like SetAttestationIds (0xc000).",
      "confidence": "medium",
      "backport_notes": [
       "Single-file change that only adds lines. It applies to trees where TrustyKeymasterOperation already defines SetAttestationIdsKM3 = 0xc001, which the pre-fix Android 14 code does (it appears as a context line in the diff).",
       "The code that uses is_trusty_provisioning_{code,req} is not in the material. Backporters should find the consumer in their own tree and confirm that it calls these predicates for non-secure-port messages."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 10,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/system/keymint",
       "sha": "1f6bf0cae40c1076faa39707c56d3994e73d01e2",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/system/keymint"
     ]
    },
    {
     "cve": "CVE-2024-34719",
     "osv_id": "ASB-A-242996380",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds Objects.requireNonNull() on the caller-supplied AttributionSource in four Bluetooth permission-check helpers in Utils.java, so a null AttributionSource can no longer produce a stub attribution chain that checks only Bluetooth's own permissions. It also updates UtilsTest to stop passing null.",
      "confidence": "high",
      "backport_notes": [
       "The change is self-contained: four one-line wraps in Utils.java plus test updates. When porting, confirm that java.util.Objects is imported and find every Builder(context.getAttributionSource()).setNext(attributionSource) site in the target branch. Also update any tests that pass a null AttributionSource.",
       "Bluetooth is an updatable mainline module from Android 13 onward (general platform knowledge). The bulletin lists 12, 12L, 13 and 14 as affected, but the material shows only the Android 14 commit."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r11",
      "date": "2024-08-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "b0e4375577ba7e21bd40edac5990bea418ecdc8c",
       "tag": "android-security-14.0.0_r11",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 88,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2024-40660",
     "osv_id": "ASB-A-347307756",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Makes SurfaceFlinger::setTransactionState sanitize the DisplayState entries in place (iterate by reference over a non-const Vector<DisplayState>) so that permission-stripping applies to the display states actually used, instead of to discarded copies.",
      "confidence": "high",
      "backport_notes": [
       "Single functional change, but it alters the ISurfaceComposer::setTransactionState virtual signature. Every override and forwarding wrapper (BpSurfaceComposer, SurfaceFlinger, FakeSurfaceComposer in Surface_test.cpp, TestableSurfaceFlinger.h, surfaceflinger_fuzzers_utils.h) and every caller that passes a temporary (doUncacheBufferTransaction) must be updated together, or the build breaks.",
       "Three cherry-picks with the same diff landed on the Android 14 security branch (two Change-Ids). Their content is identical."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r12",
      "date": "2024-09-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/native",
       "sha": "064ce6e3235b6318be1e41f1bac9595a98e4aafa",
       "tag": "android-security-14.0.0_r12",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/frameworks/native",
       "sha": "24bddbdd6d19d49f6fddd09d59f9e9f8bf42fd5e",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/frameworks/native",
       "sha": "eb7cf7e9df61f4d5e031c69ddba2444bb0e6ba31",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 3,
     "first_commit_before_announcement_days": 59,
     "multi_tag_fix": true,
     "projects": [
      "platform/frameworks/native"
     ]
    },
    {
     "cve": "CVE-2024-40661",
     "osv_id": "ASB-A-308138085",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "AdminRestrictedPermissionsUtils.mayAdminGrantPermission now takes the permission group name and no longer returns true early when either the permission itself or any platform permission in its group is an admin-restricted sensor permission. This stops an admin without sensor-grant authority from granting into a sensor permission group through a permission that is not itself on the restricted list.",
      "confidence": "high",
      "backport_notes": [
       "Single commit with a small core change (two source files). A backport must update every caller of mayAdminGrantPermission to pass the group name, and needs PermissionMapping.getPlatformPermissionNamesOfGroup to exist in the target branch."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 6,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r12",
      "date": "2024-09-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r12",
      "date": "2024-09-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Permission",
       "sha": "ffd81f212b5594b498f0ba07645c7a181540e494",
       "tag": "android-security-14.0.0_r12",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 59,
     "projects": [
      "platform/packages/modules/Permission"
     ]
    },
    {
     "cve": "CVE-2024-43080",
     "osv_id": "ASB-A-330722900",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "In Settings' AppRestrictionsFragment, the custom restrictions Intent received from an app's broadcast result extras is no longer launched as the raw deserialized object; startActivityForResult is given a fresh copy (new Intent(restrictionsIntent)) instead.",
      "confidence": "medium",
      "backport_notes": [
       "One-line change with no dependencies shown: in RestrictionsResultReceiver.onReceive make sure the Intent handed to startActivityForResult is a Settings-created copy (new Intent(...)). If the branch already launches a vetted copy returned by assertSafeToStartCustomActivity, as at 14 r29, the copy is already in place."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/apps/Settings",
       "sha": "26ce013dfd7e59a451acc66e7f05564e0884d46b",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/packages/apps/Settings"
     ]
    },
    {
     "cve": "CVE-2024-43081",
     "osv_id": "ASB-A-341256043",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "InstallPackageHelper.installExistingPackageAsUser now rejects --install-existing requests that carry INSTALL_INSTANT_APP when the target package is a device admin for the user or a protected package, returning INSTALL_FAILED_INVALID_URI as it already did for system and updated-system apps.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained hunk; it depends only on mPm.isPackageDeviceAdmin(String, int) and mPm.mProtectedPackages.isPackageStateProtected(int, String) being available from InstallPackageHelper."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "31c098c4271ad4fdfb3809e05017ead8d9f6580f",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-43083",
     "osv_id": "ASB-A-348352288",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds input validation in WifiConfigurationUtil.validate() for many previously unchecked WifiConfiguration fields (dhcpServer, defaultGwMacAddress, security params list, Passpoint fields, NetworkSelectionStatus, WEP keys on non-WEP configs, DPP key byte arrays) and makes WifiServiceImpl.addOrUpdateNetwork reject a BSSID allowlist from callers that are not privileged, system or admin.",
      "confidence": "medium",
      "backport_notes": [
       "The change uses these framework-side Wifi API symbols: WifiConfiguration.SECURITY_TYPE_NUM, getSecurityParamsList(), getBssidAllowlistInternal(), getDppConnector()/getDppCSignKey()/getDppPrivateEcKey()/getDppNetAccessKey(), and PasspointConfiguration.MAX_NUMBER_OF_OI/MAX_OI_VALUE/MAX_URL_BYTES/MAX_STRING_LENGTH. Confirm these exist on the target branch before porting. Wifi is a mainline module whose framework and service halves ship together (general platform knowledge).",
       "The fix is a single commit (Change-Id I8998340ae557660036895dd906808d682b83c6f0) touching WifiConfigurationUtil and WifiServiceImpl. Apply it as one unit."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 6,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Wifi",
       "sha": "62f61e19524e9a55cadd1116c9448ff34b977e50",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/packages/modules/Wifi"
     ]
    },
    {
     "cve": "CVE-2024-43084",
     "osv_id": "ASB-A-281044385",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Extends Notification.visitUris so that each Person's own URI (mUri) is visited along with its icon URI, including the senders of MessagingStyle messages, and so that RemoteViews nested inside two list/collection adapter actions are visited, for URI permission grant handling.",
      "confidence": "medium",
      "backport_notes": [
       "The security commit combines three upstream changes. The diff relies on RemoteViews.Action.visitUris being overridable (@Override) and on Notification.visitUris already visiting the Person and Message extras; a branch without these needs them first. At 14.0.0_r29, EXTRA_MESSAGES is read with getParcelableArrayFromBundle(extras, EXTRA_MESSAGES, Bundle.class), which differs from the diff context, so adjust the loop context when applying."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 10,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "50eec20b570cd4cbbe8c5971af4c9dda3ddcb858",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-43085",
     "osv_id": "ASB-A-353712853",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "In UsbDeviceManager's USB function-switch timeout handling, when the current function is FUNCTION_ACCESSORY the fix now calls notifyAccessoryModeExit (which sets FUNCTION_NONE, notifies the permission manager of accessory removal and clears mCurrentAccessory) instead of re-enabling the screen-unlocked default USB functions.",
      "confidence": "high",
      "backport_notes": [
       "Single-commit, self-contained change in UsbDeviceManager.java: the accessory check in the timeout handler plus the private->protected change on notifyAccessoryModeExit. The Android 15 TextUtils import reorder is cosmetic."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 7,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "2457d4e459ee6ffd099b9ff7cce9c83119c3ce66",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-43086",
     "osv_id": "ASB-A-343440463",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an else-if branch to the authenticator validation loop in AccountManagerService so that when a TABLE_META entry (type -> uid) still has an installed uid but the currently registered authenticator for that type belongs to a different uid, the stale type is marked obsolete, its meta row is deleted, and accounts of that type are purged.",
      "confidence": "high",
      "backport_notes": [
       "Single 4-line insertion with no dependencies beyond the existing loop variables (knownUid, knownUids, uid, type, obsoleteAuthType, accountsDb.deleteMetaByAuthTypeAndUid); place it as an else-if directly after the `if (!knownUids.get(uid))` purge branch. Bulletin lists 12, 12L and 13 as affected; the same hunk should apply there if the loop shape matches (older code not shown in the material)."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "55a3d36701bb874358f685d3ac3381eda10fcff0",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-43087",
     "osv_id": "ASB-A-353700779",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Removes the deduplication in Settings' AccessibilitySettings that dropped an installed accessibility service from the accessibility preference list whenever an accessibility shortcut activity in the same package had the same label, so every installed service is now listed.",
      "confidence": "high",
      "backport_notes": [
       "Pure deletion with no dependencies: remove the removeIf(...) call, the containsTargetNameInList helper and the ServiceInfo import in AccessibilitySettings.java. On older branches (12/12L/13, which the bulletin lists as affected), find the same removeIf/containsTargetNameInList pattern. The surrounding lines may differ."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 3,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/apps/Settings",
       "sha": "6253b87704bb097ad9963941bdddf3b86906a73e",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/packages/apps/Settings"
     ]
    },
    {
     "cve": "CVE-2024-43088",
     "osv_id": "ASB-A-326057017",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Settings AppInfoBase.retrieveAppEntry now calls finish() when the launching intent's EXTRA_USER_HANDLE names a user other than the current one and the initial calling package does not hold INTERACT_ACROSS_USERS_FULL.",
      "confidence": "high",
      "backport_notes": [
       "Single-commit fix. It relies on SettingsActivity.getInitialCallingPackage() existing in the target tree. If that accessor is missing in an older or customized Settings, the check must be adapted to whatever records the launching package. The test change (hasInteractAcrossUsersPermission override in TestFragment) is needed to keep extraUserHandleInIntent_retrieveAppEntryWithMyUserId passing."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 4,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/apps/Settings",
       "sha": "975c28535419be1cc45f66712f41e4a7a40e6001",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/packages/apps/Settings"
     ]
    },
    {
     "cve": "CVE-2024-43089",
     "osv_id": "ASB-A-304280682",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an enforceCallingPermission(uri, extras, true) call before the shared `break` of the movement switch in MediaProvider.java (visible cases IMAGES_MEDIA_ID, DOWNLOADS_ID, FILES_ID), so that the caller's permissions to do placement are checked before a file rename/move through MediaProvider.update.",
      "confidence": "medium",
      "backport_notes": [
       "Single two-line addition. Apply it to the movement switch in the update path of MediaProvider.java, placing the call immediately before the `break` shared by the IMAGES_MEDIA_ID, DOWNLOADS_ID and FILES_ID cases. enforceCallingPermission(Uri, Bundle, boolean) must already exist in the branch. MediaProvider is a mainline module, so the fix may also arrive via a module update (general platform knowledge)."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 8,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/providers/MediaProvider",
       "sha": "33ff6a663eea1fcdd2b422b98722c1dee48a7f6a",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/packages/providers/MediaProvider"
     ]
    },
    {
     "cve": "CVE-2024-43091",
     "osv_id": "ASB-A-344620577",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "In SkEmbossMaskFilter::filterMask the 3-plane 3D mask buffer is now sized with dst->computeTotalImageSize() (0 means too big, so the function aborts) instead of multiplying the single-plane size by 3 without an overflow check.",
      "confidence": "high",
      "backport_notes": [
       "The SkMaskBuilder form (Android 15) depends on SkMaskBuilder, introduced by Iac8b937e516dbfbbcefef54360dd5b7300bacb67. Trees without it need the Android 14 form (dst->fImage, SkMask::AllocImage/FreeImage). Both forms call SkMask::computeTotalImageSize() after dst->fFormat has been set to k3D_Format.",
       "Google marked the 14 cherry-pick RESTRICT AUTOMERGE and noted it must be cherry-picked manually to each API level. Expect the same for other branches."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 7,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r14",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/external/skia",
       "sha": "0b628a960e74197ace9831ef0727f5ba7ab6ac10",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/external/skia"
     ]
    }
   ],
   "tags": [
    "android-security-14.0.0_r14"
   ],
   "unannounced": [
    {
     "bug_ids": [
      "205837340"
     ],
     "commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "86c2c60dd9bac269967222f6db3d4b94f5ee38e1",
       "subject": "RingtoneManager: allow video ringtone URI",
       "tag": "android-security-14.0.0_r14",
       "merged": "2024-09-12",
       "markers": []
      }
     ],
     "tags": [
      "android-security-14.0.0_r14"
     ],
     "tag": "android-security-14.0.0_r14"
    }
   ],
   "coverage": {
    "n_ingested_tags": 30,
    "first_ingested_tag": "android-security-14.0.0_r1",
    "latest_ingested_tag": "android-security-14.0.0_r30",
    "window_base_tag": "android-14.0.0_r1",
    "window_start": "2023-10-04",
    "partial_tags": []
   },
   "platform_update_tags": {},
   "briefs": {
    "CVE-2024-29779": {
     "cve": "CVE-2024-29779",
     "summary": "Adds the SetAttestationIdsKM3 (0xc001) legacy Trusty Keymaster message to the is_trusty_provisioning_code and is_trusty_provisioning_req predicates in platform/system/keymint wire/src/legacy.rs, so it is classified as a provisioning request like SetAttestationIds (0xc000).",
     "component": "platform/system/keymint, wire crate (legacy Trusty Keymaster message classification, wire/src/legacy.rs)",
     "weakness": "Incomplete list / missing classification of a security-relevant request type: SetAttestationIdsKM3 was left out of the provisioning-message predicates. The security effect depends on the consumers of these predicates, which the material does not show.",
     "root_cause": "The TrustyKeymasterOperation enum in wire/src/legacy.rs (non-secure port) defines two attestation-ID messages: SetAttestationIds = 0xc000 and SetAttestationIdsKM3 = 0xc001. The predicates is_trusty_provisioning_code(code) and is_trusty_provisioning_req(req) listed SetAttestationKey, AppendAttestationCertChain, ClearAttestationCertChain, SetWrappedAttestationKey and SetAttestationIds, but not SetAttestationIdsKM3. As a result, a SetAttestationIdsKM3 message was not reported as a provisioning message by either predicate.",
     "fix_analysis": [
      "wire/src/legacy.rs:is_trusty_provisioning_code: adds `| Some(TrustyKeymasterOperation::SetAttestationIdsKM3)` to the matches! pattern, so raw opcode 0xc001 is now reported as a provisioning code.",
      "wire/src/legacy.rs:is_trusty_provisioning_req: adds `| TrustyPerformOpReq::SetAttestationIdsKM3(_)` to the matches! pattern, so a decoded SetAttestationIdsKM3 request is now reported as a provisioning request.",
      "wire/src/legacy.rs:declare_req_rsp_enums!(TrustyKeymasterOperation): adds a comment and blank lines that group the provisioning-related variants (0x2000 to 0xc001) and note that changes there must be reflected in is_trusty_provisioning_{code,req}. The enum itself does not change functionally.",
      "Single commit, 5 added lines, no change for any other opcode. Test named in the commit message: trusty_keymaster_set_attestation_ids."
     ],
     "completeness": [
      "Both predicates that classify non-secure-port legacy messages (one by raw code, one by decoded request) are updated consistently. Every variant in the provisioning group of TrustyKeymasterOperation (0x2000, 0x3000, 0xa000, 0xb000, 0xc000, 0xc001) is now covered.",
      "The fix only changes classification. The material does not show any enforcement code that uses is_trusty_provisioning_* (the index search found no callers), so it cannot be judged whether all relevant paths call these predicates.",
      "The secure-port enum TrustyKeymasterSecureOperation (SetAttestationIds = 0xc000) and CuttlefishKeymasterOperation (SetAttestationIds = 38) are untouched. The material shows no provisioning predicate for them and no KM3 variant in them.",
      "matches! is not exhaustive, so the added comment is the only safeguard against the same omission when new provisioning opcodes are added."
     ],
     "behavior_changes": [
      "is_trusty_provisioning_code(0xc001) now returns true (previously false).",
      "is_trusty_provisioning_req on TrustyPerformOpReq::SetAttestationIdsKM3 now returns true (previously false).",
      "Any caller that relies on these predicates will now treat SetAttestationIdsKM3 as a provisioning message. The callers and what they do are not shown in the material. No other opcode is affected."
     ],
     "preconditions": [
      "The device uses the platform/system/keymint wire crate with legacy Trusty message support (TrustyPerformOpReq, non-secure port).",
      "An actor able to send a legacy Trusty Keymaster message with opcode 0xc001 to that port. Per index search, a userspace tool (system/core/trusty/keymaster/set_attestation_key/set_attestation_key.cpp, provision_ids) sends KM_SET_ATTESTATION_IDS through trusty_keymaster_send. The material does not show whether such messages reach this crate's code, whether the KM3 variant can be sent, or what privilege is required."
     ],
     "per_major": {
      "14": "same fix: commit 1f6bf0cae40c (cherry-pick, Ignore-AOSP-First) in android-security-14.0.0_r14. All 8 lines of the patched region are present at android-security-14.0.0_r29.",
      "15": "not affected (per the bulletin). The patched region is present (8/8 lines) at android-security-15.0.0_r17.",
      "16": "not affected (per the bulletin). The patched region is present (8/8 lines) at android-security-16.0.0_r8.",
      "17": "not affected (per the bulletin). The patched region is present (8/8 lines) at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Single-file change that only adds lines. It applies to trees where TrustyKeymasterOperation already defines SetAttestationIdsKM3 = 0xc001, which the pre-fix Android 14 code does (it appears as a context line in the diff).",
      "The code that uses is_trusty_provisioning_{code,req} is not in the material. Backporters should find the consumer in their own tree and confirm that it calls these predicates for non-secure-port messages."
     ],
     "confidence": "medium",
     "unknowns": [
      "Which code uses is_trusty_provisioning_code / is_trusty_provisioning_req and what restriction it enforces. Neither the material nor the index results show this.",
      "What SetAttestationIdsKM3Request contains compared with SetAttestationIdsRequest.",
      "How SetAttestationIdsKM3 messages reach the non-secure port on affected devices, and from which privilege level.",
      "The content of the test trusty_keymaster_set_attestation_ids."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 10,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-34719": {
     "cve": "CVE-2024-34719",
     "summary": "Adds Objects.requireNonNull() on the caller-supplied AttributionSource in four Bluetooth permission-check helpers in Utils.java, so a null AttributionSource can no longer produce a stub attribution chain that checks only Bluetooth's own permissions. It also updates UtilsTest to stop passing null.",
     "component": "platform/packages/modules/Bluetooth, Bluetooth app permission helpers (android/app/src/com/android/bluetooth/Utils.java)",
     "weakness": "Missing null check leading to a permission check against the wrong (service's own) identity; improper authorization",
     "root_cause": "Several Bluetooth permission helpers in Utils.java build an attribution chain with new AttributionSource.Builder(context.getAttributionSource()).setNext(attributionSource).build() and then query PermissionManager. checkPermissionForDataDelivery does this with checkPermissionForDataDeliveryFromDataSource(), per context. The attributionSource parameter comes from the Binder caller and was not null-checked. Per the commit message, when a caller passed null the result was a stub attribution chain that did not properly check the caller's permissions, so the checks validated only Bluetooth's own permissions. This allowed permission bypasses on multiple Binder-exposed Bluetooth methods.",
     "fix_analysis": [
      "android/app/src/com/android/bluetooth/Utils.java:checkPermissionForDataDelivery (hunk at ~line 534): .setNext(attributionSource) is replaced with .setNext(Objects.requireNonNull(attributionSource)). A null caller attribution source now throws NullPointerException before any PermissionManager query, instead of building the stub chain.",
      "android/app/src/com/android/bluetooth/Utils.java: the same one-line change is made in three more helpers (hunks at ~lines 809, 843 and 881). The hunk headers do not show their function names, but the test changes point to the location helpers checkCallerHasCoarseLocation and checkCallerHasCoarseOrFineLocation being among them. Each previously did Builder(context.getAttributionSource()).setNext(attributionSource) and now requires attributionSource to be non-null.",
      "android/app/tests/unit/src/com/android/bluetooth/UtilsTest.java: checkCallerHasCoarseLocation_doesNotCrash and checkCallerHasCoarseOrFineLocation_doesNotCrash previously called the helpers with a null AttributionSource. They now pass context.getAttributionSource().",
      "The diff adds no new imports, so java.util.Objects is presumably already imported in Utils.java on this branch."
     ],
     "completeness": [
      "Covers the four Builder(...).setNext(attributionSource) sites in Utils.java visible in the diff, and all four now reject null. At android-security-14.0.0_r29 all 8 lines of the patched region are present.",
      "The fix only rejects null. It does not check that a non-null AttributionSource belongs to the Binder caller: in all four hunks, attributionSource.enforceCallingUid() is still commented out under the STOPSHIP(b/188391719) note.",
      "checkPermissionForPreflight (Utils.java, shown in context) uses only context.getAttributionSource() and takes no caller attribution source. It is unchanged and does not follow the same pattern.",
      "Code paths outside Utils.java that build an attribution chain from a caller-supplied AttributionSource are not shown in the material, and this commit does not touch them."
     ],
     "behavior_changes": [
      "Calling any of the four patched helpers with a null AttributionSource now throws NullPointerException (from Objects.requireNonNull). Before the fix, the result was computed against a stub chain carrying Bluetooth's own identity.",
      "For Binder callers, that NullPointerException is raised in the Bluetooth process while it handles the transaction. Binder propagates NullPointerException back to the caller as an exception (general platform knowledge).",
      "Permission checks with a non-null AttributionSource are unchanged in the diff.",
      "The unit tests no longer pass null; they use the test context's own AttributionSource."
     ],
     "preconditions": [
      "An app calls a Bluetooth Binder API whose implementation passes the caller-supplied AttributionSource into one of the four patched Utils.java helpers.",
      "The caller supplies a null AttributionSource.",
      "For checkPermissionForDataDelivery, isInstrumentationTestMode() is false; otherwise the helper returns true before building the chain.",
      "For the helper at ~line 809, location must not be off: the diff shows a 'Location is off' check that returns false before the chain is built. The early-return conditions in the other two hunks are not shown."
     ],
     "per_major": {
      "14": "same fix: commit b0e4375577ba landed in android-security-14.0.0_r11 (resolved by bug_id). At android-security-14.0.0_r29 the patched region is fully present (8/8 lines).",
      "15": "not affected per the bulletin (not listed). At android-security-15.0.0_r17, 6/8 lines of the patched region are present. The material does not show which lines match or whether the requireNonNull checks are there.",
      "16": "not affected per the bulletin (not listed). At android-security-16.0.0_r8, 5/8 lines of the patched region are present. The material does not show which lines match.",
      "17": "not affected per the bulletin (not listed). At android-security-17.0.0_r1, 0/8 lines of the patched region are present. The material does not show where, or whether, the equivalent code exists."
     },
     "backport_notes": [
      "The change is self-contained: four one-line wraps in Utils.java plus test updates. When porting, confirm that java.util.Objects is imported and find every Builder(context.getAttributionSource()).setNext(attributionSource) site in the target branch. Also update any tests that pass a null AttributionSource.",
      "Bluetooth is an updatable mainline module from Android 13 onward (general platform knowledge). The bulletin lists 12, 12L, 13 and 14 as affected, but the material shows only the Android 14 commit."
     ],
     "confidence": "high",
     "unknowns": [
      "The hunk headers do not show the names of the three helpers patched at ~lines 809, 843 and 881. The test diff implies that checkCallerHasCoarseLocation and checkCallerHasCoarseOrFineLocation are among them.",
      "The material does not list which Binder-exposed Bluetooth methods the researcher used; the commit says only 'multiple methods'.",
      "Whether equivalent fixes shipped for Android 12, 12L and 13, and in which commits, is not shown.",
      "Which lines of the patched region match in Android 15 and 16, and where the equivalent code lives in Android 17, is not shown."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-40660": {
     "cve": "CVE-2024-40660",
     "summary": "Makes SurfaceFlinger::setTransactionState sanitize the DisplayState entries in place (iterate by reference over a non-const Vector<DisplayState>) so that permission-stripping applies to the display states actually used, instead of to discarded copies.",
     "component": "platform/frameworks/native, SurfaceFlinger transaction handling (services/surfaceflinger/SurfaceFlinger.cpp, libs/gui ISurfaceComposer)",
     "weakness": "Ineffective permission check (sanitization applied to a copy, CWE-862 style missing authorization on DisplayState changes)",
     "root_cause": "In SurfaceFlinger::setTransactionState the per-caller permissions computed by LayerStatePermissions::getTransactionPermissions were applied to display states with `for (DisplayState display : displays) { display.sanitize(permissions); }`. The loop variable is a by-value copy and the `displays` parameter was `const Vector<DisplayState>&`, so sanitize() changed a temporary and the original, unsanitized DisplayState entries stayed in the vector. Composer states were handled correctly (`for (auto& composerState : states)`); only the display loop was wrong. As the new test shows, a caller without the required permission could therefore have display-level changes such as a setDisplayProjection orientation change applied.",
     "fix_analysis": [
      "services/surfaceflinger/SurfaceFlinger.cpp:SurfaceFlinger::setTransactionState: the loop becomes `for (DisplayState& display : displays)`, so DisplayState::sanitize(permissions) changes the actual elements of the vector.",
      "libs/gui/include/gui/ISurfaceComposer.h:ISurfaceComposer::setTransactionState and services/surfaceflinger/SurfaceFlinger.h: the `displays` parameter changes from `const Vector<DisplayState>&` to `Vector<DisplayState>&` so that in-place sanitization is allowed. The same signature change is made in libs/gui/ISurfaceComposer.cpp:BpSurfaceComposer::setTransactionState, where the proxy still only reads and serializes the vector.",
      "libs/gui/SurfaceComposerClient.cpp:SurfaceComposerClient::doUncacheBufferTransaction: a temporary `{}` can no longer bind to a non-const reference, so the code now creates a named empty `Vector<DisplayState> displayStates` and passes it.",
      "Test doubles updated to the new signature: libs/gui/tests/Surface_test.cpp:FakeSurfaceComposer::setTransactionState, plus the forwarding wrappers in services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h and services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h.",
      "services/surfaceflinger/tests/Credentials_test.cpp: the new DisplayTransactionPermissionTest checks that a setDisplayProjection transaction from AID_BIN leaves the display orientation unchanged, while the same transaction from AID_SYSTEM changes it."
     ],
     "completeness": [
      "The fix covers the single DisplayState sanitization loop in SurfaceFlinger::setTransactionState, which is the only place in the material where display states are sanitized. The ComposerState loop was already by reference and is untouched.",
      "This commit does not change DisplayState::sanitize itself (which fields are cleared for which permissions), and the material does not show its body. What exactly is now blocked is only shown for the projection/orientation case in the test.",
      "The Binder server side (BnSurfaceComposer::onTransact deserializing into the Vector passed to setTransactionState) is not shown. The fix depends on that path passing a mutable vector, which the non-const signature now enforces at compile time."
     ],
     "behavior_changes": [
      "DisplayState::sanitize now strips display-level transaction changes from callers that lack the relevant transaction permission. The transaction otherwise goes through: there is no new error code, and the test expects it to 'fail silently'.",
      "ISurfaceComposer::setTransactionState signature change: `displays` is now a non-const lvalue reference, so callers can no longer pass a braced temporary. Any out-of-tree implementer or caller of this libgui interface must be updated."
     ],
     "preconditions": [
      "The caller sends a transaction to SurfaceFlinger through libgui (SurfaceComposerClient::Transaction::apply), and the permissions computed for its pid/uid lack those that DisplayState::sanitize checks (the test uses AID_BIN as the untrusted caller). The full set of callers able to reach this path is not shown in the material.",
      "The transaction includes at least one DisplayState entry (for example one built with Transaction::setDisplayProjection) targeting a valid display token, as in the new CredentialsTest."
     ],
     "per_major": {
      "14": "same fix: commit 064ce6e3235b in android-security-14.0.0_r12 (Change-Id I500ff9a5...). The same diff landed again as 24bddbdd6d19 (same Change-Id) and as eb7cf7e9df61 (Change-Id Ia86633ba...), both in android-security-14.0.0_r14. At android-security-14.0.0_r29, 7/8 lines of the patched region are present, and the context shows the by-reference loop and the non-const signature.",
      "15": "same fix: commit 95185d7fe46c in android-security-15.0.0_r2. The functional diff is identical, plus a test-only lambda capture change (`[=, this]`) in Credentials_test.cpp:CaptureLayersTest. At android-security-15.0.0_r17, 7/8 lines of the patched region are present.",
      "16": "not affected (not listed by the bulletin); 3/8 lines of the patched region present at android-security-16.0.0_r8.",
      "17": "not affected (not listed by the bulletin); 3/8 lines of the patched region present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Single functional change, but it alters the ISurfaceComposer::setTransactionState virtual signature. Every override and forwarding wrapper (BpSurfaceComposer, SurfaceFlinger, FakeSurfaceComposer in Surface_test.cpp, TestableSurfaceFlinger.h, surfaceflinger_fuzzers_utils.h) and every caller that passes a temporary (doUncacheBufferTransaction) must be updated together, or the build breaks.",
      "Three cherry-picks with the same diff landed on the Android 14 security branch (two Change-Ids). Their content is identical."
     ],
     "confidence": "high",
     "unknowns": [
      "Body of DisplayState::sanitize, and which DisplayState fields and permissions it enforces (not in the material).",
      "Why Android 16/17 are not listed by the bulletin, and what the equivalent code looks like there (only partial line matches are reported).",
      "Which public AOSP 14 release tags carry the fix. Per index search, android-14.0.0_r75 still shows the const signature, but the index may be incomplete or stale.",
      "Exactly which callers can reach setTransactionState with display states, given the header comment mentioning ACCESS_SURFACE_FLINGER."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-40661": {
     "cve": "CVE-2024-40661",
     "summary": "AdminRestrictedPermissionsUtils.mayAdminGrantPermission now takes the permission group name and no longer returns true early when either the permission itself or any platform permission in its group is an admin-restricted sensor permission. This stops an admin without sensor-grant authority from granting into a sensor permission group through a permission that is not itself on the restricted list.",
     "component": "platform/packages/modules/Permission, PermissionController (admin runtime permission grant path, PermissionControllerServiceImpl / AdminRestrictedPermissionsUtils)",
     "weakness": "Incomplete authorization check (the restriction was keyed on the individual permission name, while the grant runs through the permission group)",
     "root_cause": "In PermissionControllerServiceImpl (the grant-state handler around line 563), the PERMISSION_GRANT_STATE_GRANTED branch allowed the grant only if AdminRestrictedPermissionsUtils.mayAdminGrantPermission(perm.getName(), canAdminGrantSensorsPermissions, isManagedProfile, dpm) returned true. That method returned true early for any permission whose exact name was not in ADMIN_RESTRICTED_SENSORS_PERMISSIONS (location, camera, record audio, activity recognition, body sensors, plus the S and T additions), and it ignored the permission group. The grant then runs through the AppPermissionGroup (perm.setPolicyFixed(true) and group.grantRuntimePermissions(...)). So a permission in a restricted sensor group (for example android.permission-group.MICROPHONE) that was not itself on the list passed the check even when canAdminGrantSensorsPermissions was false.",
     "fix_analysis": [
      "PermissionController/src/.../permission/utils/v31/AdminRestrictedPermissionsUtils.java:mayAdminGrantPermission: the signature gains a String permissionGroup parameter. A new boolean, isAdminRestrictedSensorPermissionGroup, is computed as permissionGroup != null && PermissionMapping.getPlatformPermissionNamesOfGroup(permissionGroup).stream().anyMatch(ADMIN_RESTRICTED_SENSORS_PERMISSIONS::contains). The early 'return true' now applies only if the permission is not in ADMIN_RESTRICTED_SENSORS_PERMISSIONS and the group is not a restricted sensor group. Otherwise the method continues to the remaining check, which the diff does not show. The new test shows that result depends on canAdminGrantSensorsPermissions. The pre-S 'return true' and the managed-profile READ_SMS case still run first.",
      "PermissionController/src/.../permission/service/PermissionControllerServiceImpl.java (GRANTED branch of the grant-state switch): the call site now passes group.getName() as the new second argument, so the check covers the AppPermissionGroup that performs the grant.",
      "PermissionController/tests/mocking/Android.bp: adds platform-test-annotations to the test module's dependency list, which @AsbSecurityTest needs.",
      "PermissionController/tests/mocking/.../AdminRestrictedPermissionsUtilsTest.kt: new parameterized test (cveBugId 308138085). An unknown permission with an unknown or null group is allowed. RECORD_AUDIO in an unknown group is denied. An unknown permission in the MICROPHONE group is denied. RECORD_AUDIO in MICROPHONE is denied when canAdminGrantSensorsPermissions=false and allowed when it is true."
     ],
     "completeness": [
      "The fix covers the PERMISSION_GRANT_STATE_GRANTED branch of the grant-state handler, the only branch that grants. The DENIED and DEFAULT branches are unchanged and do not grant.",
      "Group membership comes from PermissionMapping.getPlatformPermissionNamesOfGroup, so only platform-defined permission groups are checked. A null group name is tolerated and falls back to the per-permission check.",
      "The pre-S early 'return true' and the managed-profile READ_SMS path are unchanged.",
      "The material does not show whether mayAdminGrantPermission has other callers that still pass only a permission name. The signature change would make any such caller fail to compile.",
      "Per-major facts report 7/8 lines of the patched region present at android-security-14.0.0_r29 and at the latest 15, 16 and 17 tags. The material does not show which line differs."
     ],
     "behavior_changes": [
      "Admins that may not grant sensor permissions (canAdminGrantSensorsPermissions=false) are now also refused when the target permission belongs to a platform permission group that contains a restricted sensor permission. In that case the code takes the else branch and calls perm.setPolicyFixed(false) instead of granting and setting policy-fixed.",
      "The public static method AdminRestrictedPermissionsUtils.mayAdminGrantPermission has a new signature (added permissionGroup argument).",
      "AdminRestrictedPermissionsUtils now depends on PermissionMapping.",
      "The test build gains a platform-test-annotations dependency."
     ],
     "preconditions": [
      "A caller sets a runtime permission grant state to GRANTED through the path that reaches the grant-state handler in PermissionControllerServiceImpl. The class comment refers to Profile Owner and Device Owner admins; the external callers are not shown.",
      "canAdminGrantSensorsPermissions is false and SdkLevel.isAtLeastS() is true (before S the method returns true unconditionally).",
      "The target permission resolves to an AppPermissionGroup that is not null and not system-fixed, and whose platform permissions include an ADMIN_RESTRICTED_SENSORS_PERMISSIONS entry, while the permission name itself is not on that list."
     ],
     "per_major": {
      "14": "same fix: commit ffd81f212b55 (RESTRICT AUTOMERGE, cherry-picked through 682c92ee1e47 and 7b959874bb34) in android-security-14.0.0_r12; 7/8 lines of the patched region present at android-security-14.0.0_r29.",
      "15": "not affected per the bulletin; 7/8 lines of the patched region present at android-security-15.0.0_r17, which suggests the fixed code is present.",
      "16": "not affected per the bulletin; 7/8 lines of the patched region present at android-security-16.0.0_r8.",
      "17": "not affected per the bulletin; 7/8 lines of the patched region present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Single commit with a small core change (two source files). A backport must update every caller of mayAdminGrantPermission to pass the group name, and needs PermissionMapping.getPlatformPermissionNamesOfGroup to exist in the target branch."
     ],
     "confidence": "high",
     "unknowns": [
      "Which line of the 8-line patched region differs at the latest security tags.",
      "Whether mayAdminGrantPermission has callers other than the PermissionControllerServiceImpl site shown.",
      "The rest of mayAdminGrantPermission after the early return is not in the diff.",
      "How AppPermissionGroup.grantRuntimePermissions handles a grant of one permission in a sensor group; its internals are not in the material.",
      "Whether the fix is also delivered through a Permission module update; the material shows only the platform security tag."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 6,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-43080": {
     "cve": "CVE-2024-43080",
     "summary": "In Settings' AppRestrictionsFragment, the custom restrictions Intent received from an app's broadcast result extras is no longer launched as the raw deserialized object; startActivityForResult is given a fresh copy (new Intent(restrictionsIntent)) instead.",
     "component": "platform/packages/apps/Settings, users / app restrictions (AppRestrictionsFragment.RestrictionsResultReceiver)",
     "weakness": "Use of an untrusted, deserialized Intent object for an activity launch by Settings; the precise mechanism is described only in the referenced bug, which is not provided.",
     "root_cause": "RestrictionsResultReceiver.onReceive in src/com/android/settings/users/AppRestrictionsFragment.java reads an Intent (CUSTOM_RESTRICTIONS_INTENT) out of the result extras Bundle returned by the target app's restrictions broadcast and, when invokeIfCustom is set and the fragment is resumed, passed that exact object to AppRestrictionsFragment.this.startActivityForResult(restrictionsIntent, requestCode). Settings therefore launched an Intent object deserialized from another app's result rather than one it constructed itself. The commit message states only that a copy must be used instead of the raw Intent (\"See bug\"); the bug text is not part of the material.",
     "fix_analysis": [
      "src/com/android/settings/users/AppRestrictionsFragment.java : RestrictionsResultReceiver.onReceive: the single changed line replaces startActivityForResult(restrictionsIntent, requestCode) with startActivityForResult(new Intent(restrictionsIntent), requestCode), so the launched Intent is a copy constructed by Settings via the Intent copy constructor rather than the Parcelable object taken from the result Bundle.",
      "In the android-security-14.0.0_r29 code the region differs: assertSafeToStartCustomActivity(restrictionsIntent) creates new Intent(intent), resolves it with mPackageManager.resolveActivity, throws SecurityException unless the resolved activity's package equals packageName, and returns a vetted copy; onReceive then launches vettedIntent. This also launches a Settings-created copy rather than the raw object."
     ],
     "completeness": [
      "The fix covers the only startActivityForResult call in the shown region (custom restrictions activity launch in RestrictionsResultReceiver.onReceive).",
      "The committed change is only the copy; it does not add or change any resolution or package check. The vetting visible at r29 (assertSafeToStartCustomActivity returning vettedIntent) is present in that tree, but the material does not show its form at r14.",
      "The other branch of onReceive (restrictions != null && restrictionsIntent == null -> setApplicationRestrictions) is untouched and does not launch an Intent."
     ],
     "behavior_changes": [
      "The Intent passed to startActivityForResult is a Settings-constructed copy instead of the deserialized object; the diff adds no new error path or check."
     ],
     "preconditions": [
      "An app for the target user must respond to Settings' restrictions broadcast with result extras containing CUSTOM_RESTRICTIONS_INTENT (Intent parcelable).",
      "The app restrictions UI (AppRestrictionsFragment) must be open, with invokeIfCustom set and the fragment resumed.",
      "Settings runs as a privileged system app (general platform knowledge)."
     ],
     "per_major": {
      "14": "same fix: commit 26ce013dfd7e (Change-Id Id74e4b7ae261f2916eedaef04a679f83409a4b67, cherry-picked twice) in android-security-14.0.0_r14. At android-security-14.0.0_r29 the region differs (3/4 lines present): the launch uses vettedIntent returned by assertSafeToStartCustomActivity, which makes the copy internally.",
      "15": "not affected per bulletin; at android-security-15.0.0_r17, 3/4 lines of the patched region are present (exact form not shown).",
      "16": "not affected per bulletin; at android-security-16.0.0_r8, 3/4 lines of the patched region are present (exact form not shown).",
      "17": "not affected per bulletin; at android-security-17.0.0_r1, 3/4 lines of the patched region are present (exact form not shown)."
     },
     "backport_notes": [
      "One-line change with no dependencies shown: in RestrictionsResultReceiver.onReceive make sure the Intent handed to startActivityForResult is a Settings-created copy (new Intent(...)). If the branch already launches a vetted copy returned by assertSafeToStartCustomActivity, as at 14 r29, the copy is already in place."
     ],
     "confidence": "medium",
     "unknowns": [
      "The exact reason a copy is required (what differs between the raw deserialized Intent and its copy at launch) is only in bug 330722900, which is not provided.",
      "Whether assertSafeToStartCustomActivity existed, and in what form, at android-security-14.0.0_r14, and which later commit changed the launch to vettedIntent.",
      "The exact code form of the patched region in 15, 16 and 17."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-43081": {
     "cve": "CVE-2024-43081",
     "summary": "InstallPackageHelper.installExistingPackageAsUser now rejects --install-existing requests that carry INSTALL_INSTANT_APP when the target package is a device admin for the user or a protected package, returning INSTALL_FAILED_INVALID_URI as it already did for system and updated-system apps.",
     "component": "platform/frameworks/base, PackageManagerService (services/core/java/com/android/server/pm/InstallPackageHelper.java)",
     "weakness": "Missing authorization/state check (incomplete validation of which existing packages may be re-installed as an instant app)",
     "root_cause": "In InstallPackageHelper.installExistingPackageAsUser, when the caller set INSTALL_INSTANT_APP, the only guard was `instantApp && (pkgSetting.isSystem() || pkgSetting.isUpdatedSystemApp())`. An already-installed package that is a device admin for the target user, or one reported protected by mPm.mProtectedPackages.isPackageStateProtected, could therefore be re-installed for a user as an instant app; the commit message states such packages should be prevented from being reinstalled with --install-existing as instant.",
     "fix_analysis": [
      "services/core/java/com/android/server/pm/InstallPackageHelper.java:installExistingPackageAsUser - before taking mPm.mLock, computes `isPackageDeviceAdmin = mPm.isPackageDeviceAdmin(packageName, userId)` and `isProtectedPackage = mPm.mProtectedPackages != null && mPm.mProtectedPackages.isPackageStateProtected(userId, packageName)`.",
      "Same function - extends the existing instant-app rejection to `instantApp && (pkgSetting.isSystem() || pkgSetting.isUpdatedSystemApp() || isPackageDeviceAdmin || isProtectedPackage)`, returning Pair.create(PackageManager.INSTALL_FAILED_INVALID_URI, intentSender) for the new cases. Single commit, one file, 5 insertions / 1 deletion."
     ],
     "completeness": [
      "Covers only the INSTALL_INSTANT_APP branch of installExistingPackageAsUser; a --install-existing request without the instant flag for a device admin or protected package is unchanged by this commit.",
      "The device-admin and protected checks are evaluated for the single target userId passed in and are computed outside the synchronized(mPm.mLock) block; the subsequent pkgSetting lookup happens under the lock.",
      "The protected-package check is skipped when mPm.mProtectedPackages is null (null guard), in which case only the device-admin check adds protection.",
      "Whether other install paths that accept INSTALL_INSTANT_APP in InstallPackageHelper enforce equivalent checks is not shown in the material."
     ],
     "behavior_changes": [
      "installExistingPackageAsUser returns INSTALL_FAILED_INVALID_URI (instead of proceeding) when INSTALL_INSTANT_APP is requested for a package that is a device admin for the target user or is a protected package.",
      "Two additional lookups (mPm.isPackageDeviceAdmin, mProtectedPackages.isPackageStateProtected) are performed on every installExistingPackageAsUser call that reaches that point, regardless of the instant flag."
     ],
     "preconditions": [
      "Caller holds android.permission.INSTALL_PACKAGES or android.permission.INSTALL_EXISTING_PACKAGES (checked at the top of installExistingPackageAsUser) and passes enforceCrossUserPermission for the target userId.",
      "Target user is not restricted by UserManager.DISALLOW_INSTALL_APPS.",
      "The target package already has a PackageSetting with a parsed package (pkgSetting != null && pkgSetting.getPkg() != null) and is not a system or updated-system app.",
      "installFlags include PackageManager.INSTALL_INSTANT_APP, and the package is a device admin for userId or a protected package for userId."
     ],
     "per_major": {
      "14": "same fix: commit 31c098c4271a landed in android-security-14.0.0_r14; patched region present (7/8 lines) at android-security-14.0.0_r29.",
      "15": "not listed by the bulletin; 7/8 lines of the patched region present at android-security-15.0.0_r17 (differing line not shown).",
      "16": "not listed by the bulletin; 7/8 lines of the patched region present at android-security-16.0.0_r8.",
      "17": "not listed by the bulletin; 7/8 lines of the patched region present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Single self-contained hunk; it depends only on mPm.isPackageDeviceAdmin(String, int) and mPm.mProtectedPackages.isPackageStateProtected(int, String) being available from InstallPackageHelper."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show how re-installing a device admin or protected package as instant was abused or what concrete privilege was gained; only the bulletin rating (High, EoP) is known.",
      "The 7/8-line match in the later security tags is not explained; the one differing line is not shown.",
      "Whether sibling install paths accepting INSTALL_INSTANT_APP have equivalent device-admin/protected checks is not shown.",
      "Where installExistingPackageAsUser lives on the other affected branches (12, 12L, 13) and how the fix was applied there is not shown."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-43083": {
     "cve": "CVE-2024-43083",
     "summary": "Adds input validation in WifiConfigurationUtil.validate() for many previously unchecked WifiConfiguration fields (dhcpServer, defaultGwMacAddress, security params list, Passpoint fields, NetworkSelectionStatus, WEP keys on non-WEP configs, DPP key byte arrays) and makes WifiServiceImpl.addOrUpdateNetwork reject a BSSID allowlist from callers that are not privileged, system or admin.",
     "component": "platform/packages/modules/Wifi, WifiService (WifiConfigurationUtil / WifiServiceImpl.addOrUpdateNetwork)",
     "weakness": "Missing input validation (improper validation of caller-supplied WifiConfiguration fields; missing privilege gate on a config field)",
     "root_cause": "Before the fix, the visible part of WifiConfigurationUtil.validate() checked SSID, BSSID, bit sets, key management, WEP keys (only when the security type was WEP), a PSK-type check and IP configuration. These caller-controlled WifiConfiguration fields were not checked there: dhcpServer, defaultGwMacAddress, the SecurityParams list, FQDN, providerFriendlyName, roamingConsortiumIds, updateIdentifier, NetworkSelectionStatus connectChoice and BSSID, wepKeys on non-WEP configs, and the DPP connector, CSign, private EC and net access key byte arrays. Separately, any app that passed addOrUpdateNetwork's existing checks could also supply a BSSID allowlist. The bulletin classifies the impact as DoS. The material does not show which consumer fails on the oversized or malformed values.",
     "fix_analysis": [
      "service/java/com/android/server/wifi/WifiConfigurationUtil.java:validate(): config.dhcpServer and config.defaultGwMacAddress are now passed through validateBssid() alongside config.BSSID.",
      "WifiConfigurationUtil.java:validate() -> new validateSecurityParameters(config.getSecurityParamsList()): rejects any SecurityParams whose getSecurityType() is < 0 or > SECURITY_TYPE_NUM, and rejects duplicate security types in the list.",
      "WifiConfigurationUtil.java:validate() -> new validatePasspoint(config): FQDN and providerFriendlyName are limited to PasspointConfiguration.MAX_STRING_LENGTH via validateStringField(). roamingConsortiumIds is limited to MAX_NUMBER_OF_OI entries, each in [0, MAX_OI_VALUE] (validateRoamingConsortiumIds). updateIdentifier must be empty or parse with Integer.valueOf (validateUpdateIdentifier).",
      "WifiConfigurationUtil.java:validate() -> new validateNetworkSelectionStatus(config.getNetworkSelectionStatus()): returns false if status is null. connectChoice is limited to the new local MAX_STRING_LENGTH (512), and getNetworkSelectionBSSID() must pass validateBssid().",
      "WifiConfigurationUtil.java:validate(): WEP key handling is restructured. For WEP security types the previous check is kept (wepKeys != null -> validateWepKeys(wepKeys, wepTxKeyIndex, isAdd)). For non-WEP security types, validateWepKeys(config.wepKeys, config.wepTxKeyIndex, false) is now always called (test testWepKeyOnNonWepConfig).",
      "WifiConfigurationUtil.java:validate(): after validateIpConfiguration, rejects the config if getDppConnector(), getDppCSignKey(), getDppPrivateEcKey() or getDppNetAccessKey() is longer than PasspointConfiguration.MAX_URL_BYTES.",
      "service/java/com/android/server/wifi/WifiServiceImpl.java:addOrUpdateNetwork(): after computing isAdmin/isSystem/isPrivileged, returns -1 (with a log line) when the caller is not privileged, system or admin and config.getBssidAllowlistInternal() != null. This check runs before the isTargetSdkLessThanQOrPrivileged gate.",
      "Tests: WifiConfigurationUtilTest adds testWepKeyOnNonWepConfig, testInvalidFqdnAndFriendlyName, testInvalidDhcpAndGtw, testInvalidSecurityParameter, testInvalidUserConnectChoice and testInvalidDppConfig. WifiServiceImplTest adds testAddOrUpdateNetworkWithBssidAllowListIsNotAllowedForAppsNotPrivileged."
     ],
     "completeness": [
      "Covers: dhcpServer, defaultGwMacAddress, SecurityParams list bounds and uniqueness, FQDN, providerFriendlyName, roamingConsortiumIds, updateIdentifier, NetworkSelectionStatus connectChoice and BSSID, WEP keys on non-WEP configs, the four DPP byte arrays, and the BSSID allowlist privilege gate in addOrUpdateNetwork.",
      "Leaves out: WifiEnterpriseConfig fields are still not validated here. The comment 'TBD: Validate some enterprise params as well in the future here' remains in validate().",
      "The DPP length check only bounds the four getters listed. Other WifiConfiguration string or array fields not named in the diff are unchanged.",
      "The BSSID allowlist gate is only added in WifiServiceImpl.addOrUpdateNetwork. The material does not show whether other entry points that accept a WifiConfiguration apply the same gate.",
      "All field checks are inside WifiConfigurationUtil.validate(), so any path that stores a WifiConfiguration without calling validate() is not covered by this change. The material does not show the callers of validate()."
     ],
     "behavior_changes": [
      "validate() now returns false (so add or update fails) for configs with: FQDN or providerFriendlyName longer than PasspointConfiguration.MAX_STRING_LENGTH; connectChoice longer than 512 chars; invalid dhcpServer, defaultGwMacAddress or networkSelectionBSSID strings; too many or out-of-range roamingConsortiumIds; a non-numeric updateIdentifier; out-of-range or duplicate security types; WEP keys on non-WEP configs that fail validateWepKeys; or DPP key arrays longer than MAX_URL_BYTES.",
      "validate() now returns false when getNetworkSelectionStatus() is null.",
      "addOrUpdateNetwork returns -1 and logs 'addOrUpdateNetwork with allow bssid list is not allowed' when a caller that is not privileged, system or admin supplies a BSSID allowlist. Per the new test, this includes an empty list."
     ],
     "preconditions": [
      "The caller reaches WifiServiceImpl.addOrUpdateNetwork: it must pass enforceChangePermission(packageName) (CHANGE_WIFI_STATE app op) and, on the pre-existing path, isTargetSdkLessThanQOrPrivileged. The new allowlist gate applies to callers that are not privileged, system or admin.",
      "For the WifiConfigurationUtil.validate() changes: a WifiConfiguration with the affected fields set must reach a code path that calls validate(). The material does not list those callers."
     ],
     "per_major": {
      "14": "same fix: commit 62f61e19524e in android-security-14.0.0_r14 (one commit made by chained internal cherry-picks, Change-Id I8998340ae557660036895dd906808d682b83c6f0). At android-security-14.0.0_r29, 8/8 lines of the patched region are present.",
      "15": "not affected (the bulletin does not list it). The patched region is fully present (8/8) at android-security-15.0.0_r17.",
      "16": "not affected (the bulletin does not list it). The patched region is fully present (8/8) at android-security-16.0.0_r8.",
      "17": "not affected (the bulletin does not list it). The patched region is fully present (8/8) at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "The change uses these framework-side Wifi API symbols: WifiConfiguration.SECURITY_TYPE_NUM, getSecurityParamsList(), getBssidAllowlistInternal(), getDppConnector()/getDppCSignKey()/getDppPrivateEcKey()/getDppNetAccessKey(), and PasspointConfiguration.MAX_NUMBER_OF_OI/MAX_OI_VALUE/MAX_URL_BYTES/MAX_STRING_LENGTH. Confirm these exist on the target branch before porting. Wifi is a mainline module whose framework and service halves ship together (general platform knowledge).",
      "The fix is a single commit (Change-Id I8998340ae557660036895dd906808d682b83c6f0) touching WifiConfigurationUtil and WifiServiceImpl. Apply it as one unit."
     ],
     "confidence": "medium",
     "unknowns": [
      "The material does not show the exact consumer that failed on the unvalidated fields (the DoS mechanism).",
      "The material does not show which call sites invoke WifiConfigurationUtil.validate(), and therefore which binder entry points beyond addOrUpdateNetwork are covered.",
      "The per-major facts do not cover the fix status in Android 12, 12L and 13, which the bulletin lists as affected.",
      "The material does not show the semantics of validateWepKeys when called with isAdd=false for non-WEP configs.",
      "The full pre-fix contents of validate() (for example SAE or enterprise checks) are not shown in the diff context."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 6,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-43084": {
     "cve": "CVE-2024-43084",
     "summary": "Extends Notification.visitUris so that each Person's own URI (mUri) is visited along with its icon URI, including the senders of MessagingStyle messages, and so that RemoteViews nested inside two list/collection adapter actions are visited, for URI permission grant handling.",
     "component": "platform/frameworks/base, Notification / Person / RemoteViews URI visiting (core/java/android/app, core/java/android/widget)",
     "weakness": "Incomplete enumeration of URIs embedded in notification payloads (URIs missed by the visitor used for URI permission handling)",
     "root_cause": "Notification.visitUris(Consumer<Uri>) enumerates the URIs referenced by a notification. The Person.visitUris javadoc says these URIs need URI permission grants so the recipient can render the content. For Person objects (EXTRA_PEOPLE_LIST, EXTRA_MESSAGING_PERSON, the senders of messages in EXTRA_MESSAGES and EXTRA_HISTORIC_MESSAGES, EXTRA_CALL_PERSON), it called only visitor.accept(getIconUri()), so the Person's mUri string was never visited. In RemoteViews, the action with tag SET_REMOTE_VIEW_ADAPTER_LIST_TAG (holding ArrayList<RemoteViews> list) and the action with tag SET_REMOTE_COLLECTION_ITEMS_ADAPTER_TAG (holding mItems) had no visitUris override, so URIs in their nested RemoteViews were not visited. The bulletin classifies the issue as information disclosure (ID).",
     "fix_analysis": [
      "core/java/android/app/Person.java: adds the hidden method Person.visitUris(Consumer<Uri>). It calls visitor.accept(getIconUri()), then calls visitor.accept(Uri.parse(mUri)) when mUri is non-null and non-empty.",
      "core/java/android/app/Notification.java: Notification.visitUris now calls p.visitUris(visitor) for each Person in EXTRA_PEOPLE_LIST, person.visitUris(visitor) for EXTRA_MESSAGING_PERSON and callPerson.visitUris(visitor) for EXTRA_CALL_PERSON. These replace the previous visitor.accept(...getIconUri()) calls.",
      "core/java/android/app/Notification.java: adds the hidden method MessagingStyle.Message.visitUris(Consumer<Uri>). It visits getDataUri() and, if mSender != null, delegates to mSender.visitUris(visitor). The EXTRA_MESSAGES and EXTRA_HISTORIC_MESSAGES loops now call message.visitUris(visitor) instead of inlining the data URI and the sender icon URI.",
      "core/java/android/widget/RemoteViews.java: the action returning SET_REMOTE_VIEW_ADAPTER_LIST_TAG gains an @Override visitUris that calls remoteViews.visitUris(visitor) for each RemoteViews in list.",
      "core/java/android/widget/RemoteViews.java: the action returning SET_REMOTE_COLLECTION_ITEMS_ADAPTER_TAG gains an @Override visitUris that calls mItems.visitUris(visitor) when mItems != null. A nested class holding mViews/mViewTypeCount gains a private visitUris that calls view.visitUris(visitor) for each view in mViews."
     ],
     "completeness": [
      "Covers every Person reference visited in Notification.visitUris (people list, messaging person, message senders for current and historic messages, call person): both the icon URI and mUri are now visited.",
      "Covers nested RemoteViews reachable through the two adapter actions (list, and mItems via mViews). The diff does not change any other RemoteViews action.",
      "Other extras in Notification.visitUris (EXTRA_AUDIO_CONTENTS_URI, EXTRA_BACKGROUND_IMAGE_URI, RemoteInputHistoryItem.getUri, icons) are not changed by this diff.",
      "Person.visitUris visits only the icon URI and mUri. Message.visitUris visits only getDataUri() and the sender Person."
     ],
     "behavior_changes": [
      "The URI visitor now receives additional URIs: Person.mUri (parsed with Uri.parse) for the Person objects listed above, and the URIs of RemoteViews nested in the two adapter actions. Whatever the visitor does with URIs now also applies to these.",
      "New hidden methods: Person.visitUris and Notification.MessagingStyle.Message.visitUris. Also added: a private visitUris on the collection-items class and two Action.visitUris overrides in RemoteViews."
     ],
     "preconditions": [
      "A notification contains a Person with a URI set (in EXTRA_PEOPLE_LIST, EXTRA_MESSAGING_PERSON, EXTRA_CALL_PERSON, or as a MessagingStyle message sender), or a RemoteViews that uses one of the two list/collection adapter actions with nested RemoteViews that reference URIs.",
      "Notification.visitUris is invoked on that notification by the code that handles URI permissions. That caller is not shown in the material."
     ],
     "per_major": {
      "14": "same fix: commit 50eec20b570c in android-security-14.0.0_r14 (cherry-pick of f47b41a138eb that includes changes from 57bf60dd7b6a and 47fa2f79584b). At android-security-14.0.0_r29, 6/8 lines of the patched region are present; the material does not show which lines differ.",
      "15": "not affected (not listed by the bulletin). 6/8 lines of the patched region are present at android-security-15.0.0_r17.",
      "16": "not affected (not listed by the bulletin). 6/8 lines of the patched region are present at android-security-16.0.0_r8.",
      "17": "not affected (not listed by the bulletin). 6/8 lines of the patched region are present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "The security commit combines three upstream changes. The diff relies on RemoteViews.Action.visitUris being overridable (@Override) and on Notification.visitUris already visiting the Person and Message extras; a branch without these needs them first. At 14.0.0_r29, EXTRA_MESSAGES is read with getParcelableArrayFromBundle(extras, EXTRA_MESSAGES, Bundle.class), which differs from the diff context, so adjust the loop context when applying."
     ],
     "confidence": "medium",
     "unknowns": [
      "The material does not show the consumer side: how the system uses the visited URIs (grant or check), or whether notifications can now be rejected.",
      "The exact disclosure scenario from bug 281044385 is not shown.",
      "The three upstream commits (f47b41a138eb, 57bf60dd7b6a, 47fa2f79584b) are not shown separately.",
      "Which 2 of the 8 patched-region lines differ at the latest tag of each major is not shown.",
      "The RemoteViews class names of the two modified actions and of the collection-items class are not shown in the diff."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 10,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-43085": {
     "cve": "CVE-2024-43085",
     "summary": "In UsbDeviceManager's USB function-switch timeout handling, when the current function is FUNCTION_ACCESSORY the fix now calls notifyAccessoryModeExit (which sets FUNCTION_NONE, notifies the permission manager of accessory removal and clears mCurrentAccessory) instead of re-enabling the screen-unlocked default USB functions.",
     "component": "platform/frameworks/base, services/usb (UsbDeviceManager, USB function switching and accessory mode)",
     "weakness": "Insecure fallback state on error: on a function-switch timeout the code reverted to the default USB functions instead of a no-data-transfer state while in accessory mode (improper handling of an exceptional condition)",
     "root_cause": "In services/usb/java/com/android/server/usb/UsbDeviceManager.java, the handler case for the function-switch timeout (the case containing 'operationId = sUsbOperationCount.incrementAndGet(); if (msg.arg1 != 1)') unconditionally called setEnabledFunctions(mScreenUnlockedFunctions, false, operationId), with the comment that the default function may be selected from Developer options. If the timeout occurred while mCurrentFunctions == UsbManager.FUNCTION_ACCESSORY, the device switched to those default functions rather than FUNCTION_NONE, and the accessory-exit bookkeeping in notifyAccessoryModeExit (usbAccessoryRemoved, clearing mCurrentAccessory) was not performed.",
     "fix_analysis": [
      "UsbDeviceManager.java, function-switch timeout handler case (msg.arg1 != 1 branch): adds 'if (mCurrentFunctions == UsbManager.FUNCTION_ACCESSORY)' and calls notifyAccessoryModeExit(operationId) in that case; otherwise keeps setEnabledFunctions(mScreenUnlockedFunctions, false, operationId).",
      "UsbDeviceManager.java, notifyAccessoryModeExit: visibility changed from private to protected (the diff does not state why). Per the r29 context (lines 822-834) it logs 'exited USB accessory mode', calls setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId), and if mCurrentAccessory != null calls mPermissionManager.usbAccessoryRemoved(mCurrentAccessory) (when mBootCompleted) and clears mCurrentAccessory.",
      "Net effect: a timeout while in accessory mode now ends in FUNCTION_NONE (no data transfer) with accessory state cleared, matching the existing non-timeout accessory-exit path (context lines 814-815) which already called notifyAccessoryModeExit."
     ],
     "completeness": [
      "Only the function-switch timeout handler case is changed; the normal accessory exit path (lines 814-815) already used notifyAccessoryModeExit and is untouched.",
      "The new condition is an exact equality test on mCurrentFunctions == UsbManager.FUNCTION_ACCESSORY; a combined mask including accessory with other bits would not match (USB functions are bit flags in UsbManager (general platform knowledge)). The material does not show whether such combinations can occur here.",
      "Other call sites of setEnabledFunctions(mScreenUnlockedFunctions, ...) are not shown in the material and are not modified by this commit.",
      "The fix does not change the timeout duration or the msg.arg1 == 1 branch."
     ],
     "behavior_changes": [
      "On a function-switch timeout while the current USB function is FUNCTION_ACCESSORY, USB functions are set to FUNCTION_NONE instead of the screen-unlocked default functions.",
      "In that case mPermissionManager.usbAccessoryRemoved(mCurrentAccessory) is invoked (if boot completed), mCurrentAccessory is cleared, and 'exited USB accessory mode' is logged.",
      "notifyAccessoryModeExit is now protected rather than private."
     ],
     "preconditions": [
      "Device is in USB accessory mode (mCurrentFunctions == UsbManager.FUNCTION_ACCESSORY); how this state is reached is not shown in the material.",
      "A function-switch timeout message is handled with msg.arg1 != 1.",
      "The difference matters when mScreenUnlockedFunctions is something other than FUNCTION_NONE (the code comment says it may be selected from Developer options)."
     ],
     "per_major": {
      "14": "same fix: commit 2457d4e459ee in android-security-14.0.0_r14 (cherry-pick of 7c6ec68537ba, Change-Id I698e9df0333cbb51dd9bd5917a94d81273a2784a); at android-security-14.0.0_r29 7/8 lines of the patched region are present; the shown context confirms notifyAccessoryModeExit is protected, the timeout-handler hunk is not in the shown context.",
      "15": "same fix with an additional cosmetic hunk: commit f46d19f31d8f in android-security-15.0.0_r2 also reorders the android.text.TextUtils import; at android-security-15.0.0_r17 8/8 lines of the patched region are present.",
      "16": "not affected (not listed by the bulletin); at android-security-16.0.0_r8 7/8 lines of the patched region are present.",
      "17": "not affected (not listed by the bulletin); at android-security-17.0.0_r1 6/8 lines of the patched region are present."
     },
     "backport_notes": [
      "Single-commit, self-contained change in UsbDeviceManager.java: the accessory check in the timeout handler plus the private->protected change on notifyAccessoryModeExit. The Android 15 TextUtils import reorder is cosmetic."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact message constant name for the function-switch timeout case is not shown in the diff.",
      "Why notifyAccessoryModeExit was made protected (e.g. subclass or test access) is not shown.",
      "Whether mCurrentFunctions can hold a combined mask including FUNCTION_ACCESSORY in this handler.",
      "Other callers of setEnabledFunctions(mScreenUnlockedFunctions, ...) and whether other paths have the same fallback.",
      "How accessory mode is entered and what access an attacker needs; which default function the EoP rating assumes."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 7,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-43086": {
     "cve": "CVE-2024-43086",
     "summary": "Adds an else-if branch to the authenticator validation loop in AccountManagerService so that when a TABLE_META entry (type -> uid) still has an installed uid but the currently registered authenticator for that type belongs to a different uid, the stale type is marked obsolete, its meta row is deleted, and accounts of that type are purged.",
     "component": "platform/frameworks/base, services/core AccountManagerService (accounts)",
     "weakness": "Incomplete cleanup / missing state check: stale authenticator registration and its account data were not purged when the account type was taken over by a different uid while the old package remained installed",
     "root_cause": "In services/core/java/com/android/server/accounts/AccountManagerService.java, the loop that reconciles persisted TABLE_META entries (authToUidEntry: type -> uid) against the currently cached authenticators (knownAuth) only purged an entry when the old uid no longer had any installed or updated package (!knownUids.get(uid)). If the old uid's package was still present (for example the authenticator was disabled rather than uninstalled, per the commit title) and a different uid now registered an authenticator for the same type, the entry fell through without action: the type was not added to obsoleteAuthType, the meta row was not deleted, and the existing accounts of that type were kept while the new authenticator uid was written by insertOrReplaceMetaAuthTypeAndUid. The bulletin rates this High / ID (information disclosure).",
     "fix_analysis": [
      "services/core/java/com/android/server/accounts/AccountManagerService.java, authenticator reconciliation loop (iterates authToUidEntry against knownAuth; method name not shown in the material): after the existing `if (!knownUids.get(uid))` purge branch, a new `else if (knownUid != null && knownUid != uid)` branch is added.",
      "The new branch logs Slog.w(TAG, \"authenticator no longer exist for type \" + type), adds the type to obsoleteAuthType, and calls accountsDb.deleteMetaByAuthTypeAndUid(type, uid) for the old uid, mirroring the existing purge path.",
      "Downstream, the existing account loop deletes every account whose type is in obsoleteAuthType (\"deleting account ... because type ...'s registered authenticator no longer exist.\"), and the loop over knownAuth.entrySet() records the new (type, newUid) mapping via insertOrReplaceMetaAuthTypeAndUid, so the type no longer keeps the accounts created under the old authenticator."
     ],
     "completeness": [
      "Covers the case where the type's registered authenticator uid changed (knownUid != null && knownUid != uid) while the old uid is still installed.",
      "Does not change the case knownUid == null with the old uid still installed (type has no current authenticator but the package is still present): data is still retained, consistent with the existing comment that this is an imperfect signal the package may be updating.",
      "Does not change the pre-existing caveat noted in the code comment that an authenticator sharing a uid with other apps is not wiped while any app with that uid remains.",
      "Single-file, single-hunk change; no other call sites or sibling paths are touched in the material."
     ],
     "behavior_changes": [
      "When an account type's authenticator moves to a different uid, all existing accounts of that type are now deleted during validation (new Slog.w warnings for the type and each deleted account).",
      "The old (type, uid) TABLE_META row is removed before the new mapping is inserted.",
      "Purge now triggers even when the old uid still has an installed or updated package on the device."
     ],
     "preconditions": [
      "A TABLE_META entry exists for an account type with some uid, and that uid still has an installed or updated package for the user (knownUids.get(uid) is true).",
      "The currently cached authenticator for that same type is registered by a different uid (knownUid != null && knownUid != uid), e.g. the original authenticator was disabled and another package provides the type.",
      "The reconciliation loop runs; per the code comment it is triggered when an authenticator is thought to have been removed or is being updated."
     ],
     "per_major": {
      "14": "same fix: commit 55a3d36701bb in android-security-14.0.0_r14 (cherry-pick of ddfc078af7e8); patched region fully present (3/3 lines) at android-security-14.0.0_r29.",
      "15": "not affected per the bulletin (Android 15 not listed); patched region present (3/3 lines) at android-security-15.0.0_r17.",
      "16": "not affected per the bulletin; patched region present (3/3 lines) at android-security-16.0.0_r8.",
      "17": "not affected per the bulletin; patched region present (3/3 lines) at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Single 4-line insertion with no dependencies beyond the existing loop variables (knownUid, knownUids, uid, type, obsoleteAuthType, accountsDb.deleteMetaByAuthTypeAndUid); place it as an else-if directly after the `if (!knownUids.get(uid))` purge branch. Bulletin lists 12, 12L and 13 as affected; the same hunk should apply there if the loop shape matches (older code not shown in the material)."
     ],
     "confidence": "high",
     "unknowns": [
      "The enclosing method name is not shown in the provided code context.",
      "The exact trigger scenario and what information is disclosed are not described in the material beyond the commit title and the bulletin's ID classification.",
      "No automated test accompanies the change (Test: manual).",
      "The loop shape on Android 12, 12L and 13 is not shown."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-43087": {
     "cve": "CVE-2024-43087",
     "summary": "Removes the deduplication in Settings' AccessibilitySettings that dropped an installed accessibility service from the accessibility preference list whenever an accessibility shortcut activity in the same package had the same label, so every installed service is now listed.",
     "component": "platform/packages/apps/Settings, accessibility settings UI (AccessibilitySettings fragment)",
     "weakness": "Improper UI presentation / incorrect filtering: package name + label match criteria used to suppress display of an installed accessibility service (service hiding).",
     "root_cause": "In AccessibilitySettings, the method that builds the installed accessibility preference list (around line 416) copied a11yManager.getInstalledAccessibilityServiceList() into installedServiceList and then called installedServiceList.removeIf(target -> containsTargetNameInList(installedShortcutList, target)). containsTargetNameInList compared the service's ServiceInfo.packageName and loadLabel() with each AccessibilityShortcutInfo's ActivityInfo.packageName and loadLabel(). When they matched, the service was removed from the list shown to the user. An app that declared an accessibility shortcut activity with the same label as its accessibility service could therefore have the service left off the Accessibility settings list.",
     "fix_analysis": [
      "src/com/android/settings/accessibility/AccessibilitySettings.java (preference list builder around line 416): deletes the installedServiceList.removeIf(... containsTargetNameInList(...)) call. The list passed to preferenceHelper.createAccessibilityServicePreferenceList(installedServiceList) is now the full, unfiltered copy of a11yManager.getInstalledAccessibilityServiceList().",
      "src/com/android/settings/accessibility/AccessibilitySettings.java: removes the private helper containsTargetNameInList(List<AccessibilityShortcutInfo>, AccessibilityServiceInfo) and the import android.content.pm.ServiceInfo, which is no longer used.",
      "Activity preferences are still built from installedShortcutList via preferenceHelper.createAccessibilityActivityPreferenceList. Only the service-side filtering is removed. The material shows a single commit (RESTRICT AUTOMERGE cherry-pick, Change-Id Ia8d43229d277dd4442173166ae0402f05096da4b)."
     ],
     "completeness": [
      "The fix removes the label/package based hiding path in AccessibilitySettings. No code left in the diffed region removes services from the displayed list.",
      "The fix only touches the main Accessibility list in the Settings app. The material does not show other Settings screens or other consumers of getInstalledAccessibilityServiceList, so it cannot show whether a similar deduplication exists elsewhere.",
      "The fix does not change the a11y framework (AccessibilityManager) or the shortcut list. It only changes what Settings displays."
     ],
     "behavior_changes": [
      "Accessibility settings now lists every installed accessibility service, even when the same package also exposes an accessibility shortcut activity with the same label. Such a package now shows two entries (one activity, one service) where before only the activity entry appeared.",
      "The containsTargetNameInList helper and the ServiceInfo import are removed. There are no new error paths."
     ],
     "preconditions": [
      "An installed app that declares both an accessibility service and an accessibility shortcut activity (AccessibilityShortcutInfo) in the same package with the same label.",
      "The user opens the Accessibility screen in Settings (AccessibilitySettings fragment), which builds the installed a11y list."
     ],
     "per_major": {
      "14": "same fix: commit 6253b87704bb (RESTRICT AUTOMERGE cherry-pick) in android-security-14.0.0_r14. At android-security-14.0.0_r29 all 8/8 lines of the patched region are present.",
      "15": "not affected per the bulletin. At android-security-15.0.0_r17 the patched region is present (8/8 lines), so the branch already carries the fixed code.",
      "16": "not affected per the bulletin. At android-security-16.0.0_r8 the patched region is present (8/8 lines).",
      "17": "not affected per the bulletin. At android-security-17.0.0_r1 the patched region is present (8/8 lines)."
     },
     "backport_notes": [
      "Pure deletion with no dependencies: remove the removeIf(...) call, the containsTargetNameInList helper and the ServiceInfo import in AccessibilitySettings.java. On older branches (12/12L/13, which the bulletin lists as affected), find the same removeIf/containsTargetNameInList pattern. The surrounding lines may differ."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact commits used for Android 12, 12L and 13 are not in the material. Only the Android 14 cherry-pick is shown.",
      "The bulletin's affected-version list includes '15-next', but the per-major facts say Android 15 is not listed. The material does not explain the difference.",
      "The material does not show whether other Settings code paths (e.g. search indexing or other accessibility screens) apply a similar package+label deduplication.",
      "The material does not show the permissions an app needs to declare these components.",
      "The PoC APK behaviour referenced in the commit message (bug 353700779) is not included in the material."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 3,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-43088": {
     "cve": "CVE-2024-43088",
     "summary": "Settings AppInfoBase.retrieveAppEntry now calls finish() when the launching intent's EXTRA_USER_HANDLE names a user other than the current one and the initial calling package does not hold INTERACT_ACROSS_USERS_FULL.",
     "component": "platform/packages/apps/Settings, applications (AppInfoBase / app info fragments)",
     "weakness": "missing permission check (cross-user intent extra trusted without authorization)",
     "root_cause": "In src/com/android/settings/applications/AppInfoBase.java, retrieveAppEntry() read Intent.EXTRA_USER_HANDLE from the launching intent and used it directly as mUserId, without checking whether the caller was allowed to interact across users. The fragment could therefore be pointed at a package in a different user.",
     "fix_analysis": [
      "AppInfoBase.java:retrieveAppEntry(): after taking mUserId from EXTRA_USER_HANDLE, if mUserId != UserHandle.myUserId() and hasInteractAcrossUsersPermission() is false, it logs 'Intent not valid.', calls finish() and returns an empty string, so mPackageInfo/mAppEntry are never filled in for the foreign user.",
      "AppInfoBase.java:hasInteractAcrossUsersPermission() (new, @VisibleForTesting protected): returns false unless getActivity() is a SettingsActivity. It then gets ((SettingsActivity) activity).getInitialCallingPackage() and returns false if that is empty, or if mPm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingPackageName) != PERMISSION_GRANTED. Otherwise it returns true.",
      "tests/robotests/.../AppInfoWithHeaderTest.java: TestFragment overrides hasInteractAcrossUsersPermission() to return true so existing cross-user tests still pass. The new TestFragmentWithoutPermission returns false, and the new test noCrossUserPermission_retrieveAppEntry_fail asserts that mAppEntry stays null."
     ],
     "completeness": [
      "The fix covers only the EXTRA_USER_HANDLE path in AppInfoBase.retrieveAppEntry(). Intents without that extra are unchanged and default to UserHandle.myUserId().",
      "The check fails closed: a host activity that is not a SettingsActivity, or an empty initial calling package, both lead to finish().",
      "The permission check is by package name through PackageManager.checkPermission, keyed on SettingsActivity.getInitialCallingPackage(). It does not check the calling uid. Its correctness therefore depends on how SettingsActivity records the initial calling package, which the material does not show.",
      "The same-user case (mUserId == myUserId) is still allowed without any check, as before the fix.",
      "The material does not show whether other Settings fragments outside AppInfoBase consume EXTRA_USER_HANDLE in a similar way."
     ],
     "behavior_changes": [
      "App-info fragments derived from AppInfoBase now call finish() (and log a 'Intent not valid.' warning) when launched with EXTRA_USER_HANDLE for another user by a caller that lacks INTERACT_ACROSS_USERS_FULL.",
      "Fragments hosted in an activity that is not a SettingsActivity are now also finished for cross-user intents, because hasInteractAcrossUsersPermission() returns false in that case.",
      "New warning logs appear when the calling package cannot be determined or lacks the permission."
     ],
     "preconditions": [
      "A Settings screen whose fragment extends AppInfoBase is launched with an intent carrying Intent.EXTRA_USER_HANDLE for a user id different from the current user.",
      "Before the fix, retrieveAppEntry() required no permission from the caller before using the foreign user id."
     ],
     "per_major": {
      "14": "same fix: commit 975c28535419 in android-security-14.0.0_r14; patched region 8/8 lines present at android-security-14.0.0_r29.",
      "15": "not affected (not listed by the bulletin); patched region 8/8 lines present at android-security-15.0.0_r17.",
      "16": "not affected (not listed by the bulletin); patched region 8/8 lines present at android-security-16.0.0_r8.",
      "17": "not affected (not listed by the bulletin); patched region 8/8 lines present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Single-commit fix. It relies on SettingsActivity.getInitialCallingPackage() existing in the target tree. If that accessor is missing in an older or customized Settings, the check must be adapted to whatever records the launching package. The test change (hasInteractAcrossUsersPermission override in TestFragment) is needed to keep extraUserHandleInIntent_retrieveAppEntryWithMyUserId passing."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show how SettingsActivity.getInitialCallingPackage() is implemented or how reliably it reflects the actual launching caller.",
      "The material does not show which concrete AppInfoBase subclasses and exported Settings entry points could be reached with EXTRA_USER_HANDLE, or by which callers.",
      "The bulletin lists 12, 12L and 13 as affected, but the material gives no fix commit or tag status for those branches."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 4,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-43089": {
     "cve": "CVE-2024-43089",
     "summary": "Adds an enforceCallingPermission(uri, extras, true) call before the shared `break` of the movement switch in MediaProvider.java (visible cases IMAGES_MEDIA_ID, DOWNLOADS_ID, FILES_ID), so that the caller's permissions to do placement are checked before a file rename/move through MediaProvider.update.",
     "component": "platform/packages/providers/MediaProvider, MediaProvider.update (file placement / rename path)",
     "weakness": "missing permission check (authorization bypass on file rename via ContentProvider update)",
     "root_cause": "In MediaProvider.java, a switch that decides whether a URI type may be \"moved\" (otherwise it throws IllegalArgumentException \"Movement of \" + uri) accepted cases including DOWNLOADS_ID and FILES_ID without checking the caller's permissions to do placement. Per the commit message, malicious apps could use MediaProvider.update to rename files in the lower file system that they had no access to. They could not update the MediaProvider DB this way. But they could create fake records in the DB and then rename the file to the same name as their record, which gave them access to the file. Per the commit message, IMAGES_MEDIA_ID, AUDIO_MEDIA_ID and VIDEO_MEDIA_ID URIs were already guarded, and this fix covers all other Media URIs.",
     "fix_analysis": [
      "src/com/android/providers/media/MediaProvider.java, movement switch in the update path: before the `break` shared by the visible cases IMAGES_MEDIA_ID, DOWNLOADS_ID and FILES_ID, the fix adds a call to `enforceCallingPermission(uri, extras, true)`, with the comment 'Check if the caller has the required permissions to do placement'. The `default` branch still throws IllegalArgumentException for URI types that may not be moved."
     ],
     "completeness": [
      "Covers the movement switch in the update path for the case labels that share the patched `break`. Other URI types already threw in the `default` branch.",
      "The fix is one call site. The material does not show other rename/move entry points (e.g. FUSE-driven renames or other update sub-paths), so whether they have equivalent checks cannot be judged from the material.",
      "The exact semantics of the third argument (`true`) to enforceCallingPermission are not shown in the material."
     ],
     "behavior_changes": [
      "MediaProvider.update requests that imply a file move/rename for the affected URI types (e.g. DOWNLOADS_ID, FILES_ID) now go through enforceCallingPermission first. If the caller lacks the required permissions, the request fails instead of renaming the file in the lower file system. The exact exception type is not shown in the material.",
      "Callers that pass the permission check should see no change."
     ],
     "preconditions": [
      "Caller is an app that can reach MediaProvider.update with a single-item media URI of an affected type (e.g. DOWNLOADS_ID or FILES_ID) and values that trigger file placement/rename.",
      "The target file is one the caller has no access to. Per the commit message, the caller must also be able to create its own record in the MediaProvider DB."
     ],
     "per_major": {
      "14": "same fix: commit 33ff6a663eea (cherry-pick of d3d22856bfd4, Change-Id I91e9966c012fe292cebc0b544f77032613516fac) merged in android-security-14.0.0_r14; 3/3 patched lines present at android-security-14.0.0_r29.",
      "15": "not affected per the bulletin; patched region present (3/3 lines) at android-security-15.0.0_r17.",
      "16": "not affected per the bulletin; patched region present (3/3 lines) at android-security-16.0.0_r8.",
      "17": "not affected per the bulletin; patched region present (3/3 lines) at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Single two-line addition. Apply it to the movement switch in the update path of MediaProvider.java, placing the call immediately before the `break` shared by the IMAGES_MEDIA_ID, DOWNLOADS_ID and FILES_ID cases. enforceCallingPermission(Uri, Bundle, boolean) must already exist in the branch. MediaProvider is a mainline module, so the fix may also arrive via a module update (general platform knowledge)."
     ],
     "confidence": "medium",
     "unknowns": [
      "The enclosing method name of the patched switch is not shown in the hunk header (only the class is shown).",
      "Which case labels precede IMAGES_MEDIA_ID in the same group is not shown.",
      "The implementation of enforceCallingPermission, the meaning of its third boolean argument, and which exception it throws are not in the material.",
      "Where the existing guard for IMAGES/AUDIO/VIDEO_MEDIA_ID lives, and whether other rename entry points exist, is not shown.",
      "Only 'Test: Manual' is recorded; no regression test is included in the commit."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 8,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-43091": {
     "cve": "CVE-2024-43091",
     "summary": "In SkEmbossMaskFilter::filterMask the 3-plane 3D mask buffer is now sized with dst->computeTotalImageSize() (0 means too big, so the function aborts) instead of multiplying the single-plane size by 3 without an overflow check.",
     "component": "platform/external/skia, src/effects/SkEmbossMaskFilter.cpp (emboss mask filter, 3D mask allocation)",
     "weakness": "Integer overflow in allocation size computation leading to undersized heap buffer (missing overflow check)",
     "root_cause": "After blurring the source A8 mask, SkEmbossMaskFilter::filterMask sets dst->fFormat = SkMask::k3D_Format and allocates a larger buffer for 'the other two channels'. The old code took planeSize = dst->computeImageSize() (single-plane size, 0 meaning too big), checked only that planeSize != 0, and then called SkMask::AllocImage(planeSize * 3). Nothing checked the multiplication by 3 for overflow. For a large enough mask, planeSize could be valid while planeSize * 3 wrapped, so the allocation would be smaller than the three-plane 3D mask that the rest of the function works on.",
     "fix_analysis": [
      "src/effects/SkEmbossMaskFilter.cpp:SkEmbossMaskFilter::filterMask: computes size_t totalSize = dst->computeTotalImageSize() first. dst->fFormat has already been set to k3D_Format, so the total is intended to cover all planes. If totalSize is 0, the function returns false (\"too big to allocate, abort\").",
      "Only after that check does it compute planeSize = dst->computeImageSize(), used for the memcpy of the existing alpha plane. An added SkASSERT(planeSize != 0) documents that a non-overflowing total implies a non-overflowing plane size.",
      "The allocation becomes SkMask::AllocImage(totalSize) (SkMaskBuilder::AllocImage(totalSize) on Android 15). The buffer size now comes from the checked total instead of an unchecked planeSize * 3."
     ],
     "completeness": [
      "The fix covers the single allocation site in SkEmbossMaskFilter::filterMask that creates the 3D mask. The overflow check now covers the full multi-plane size.",
      "The later memcpy(dst->fImage, alphaPlane, planeSize) and memcpy(dst->fImage, src.fImage, src.computeImageSize()) are unchanged. They copy one plane each into the checked buffer.",
      "No other allocation paths are touched. The diff and context show no other site with a similar unchecked multiplication.",
      "The commit notes 'Test: N/A -- unclear if even reachable', so no regression test comes with the change."
     ],
     "behavior_changes": [
      "filterMask now returns false (filter aborted) when computeTotalImageSize() reports the total size as too big (returns 0). Before, it would have continued with a possibly wrapped allocation size. For normal sizes the allocation is expected to be equivalent, but the material does not show the implementation of computeTotalImageSize().",
      "A debug-only SkASSERT(planeSize != 0) is added."
     ],
     "preconditions": [
      "A drawing operation with a Paint whose mask filter is an emboss mask filter. Per index search, app code can create one through the deprecated android.graphics.EmbossMaskFilter (EmbossMaskFilter.java nativeConstructor; MaskFilter.cpp contains createEmboss) and set it through Paint.setMaskFilter (Paint.cpp setMaskFilter). The excerpt is truncated and does not show the full native path to SkEmbossMaskFilter.",
      "The source mask must be kA8_Format with a non-null fImage. The blurred dst mask must be large enough that a single plane size is valid but the three-plane total overflows. The commit itself says it is unclear whether this is reachable."
     ],
     "per_major": {
      "14": "adapted fix: commit 0b628a960e74 in android-security-14.0.0_r14, a RESTRICT AUTOMERGE cherry-pick changed for the pre-SkMaskBuilder API (SkMask* dst, dst->fImage, SkMask::AllocImage/FreeImage). At android-security-14.0.0_r29, 4/7 lines of the patched region are present. The code context at r29 (lines 104-115) shows the fixed allocation.",
      "15": "fixed by commit b8081964ce86 in android-security-15.0.0_r2, in the SkMaskBuilder form (SkMaskBuilder* dst, dst->image(), SkMaskBuilder::AllocImage(totalSize)). At android-security-15.0.0_r17, 4/7 lines of the patched region are present.",
      "16": "not listed by the bulletin (not affected per the bulletin). At android-security-16.0.0_r8 only 1/7 lines of the patched region are present. The material does not show the current form of this code.",
      "17": "not listed by the bulletin (not affected per the bulletin). At android-security-17.0.0_r1 only 1/7 lines of the patched region are present. The material does not show the current form of this code."
     },
     "backport_notes": [
      "The SkMaskBuilder form (Android 15) depends on SkMaskBuilder, introduced by Iac8b937e516dbfbbcefef54360dd5b7300bacb67. Trees without it need the Android 14 form (dst->fImage, SkMask::AllocImage/FreeImage). Both forms call SkMask::computeTotalImageSize() after dst->fFormat has been set to k3D_Format.",
      "Google marked the 14 cherry-pick RESTRICT AUTOMERGE and noted it must be cherry-picked manually to each API level. Expect the same for other branches."
     ],
     "confidence": "high",
     "unknowns": [
      "Whether the overflowing size is reachable from an untrusted caller on a real device (the commit says 'unclear if even reachable'). The material does not show the mask dimension limits applied before filterMask.",
      "The form of the code in Android 16/17 (only 1/7 lines of the patched region present) and whether it was moved, rewritten or removed.",
      "The implementation of SkMask::computeTotalImageSize() is not in the material. The analysis relies on the diff comment that 0 means too big.",
      "How SkEmbossMask::Emboss uses the three planes is not shown.",
      "The full native path from android.graphics.EmbossMaskFilter to SkEmbossMaskFilter (the index excerpt is truncated)."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 7,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    }
   }
  },
  "15": {
   "counts": {
    "announced": 3,
    "certain": 3,
    "probable": 0,
    "not_published": 0,
    "not_covered": 0,
    "awaiting": 0
   },
   "advisories": [
    {
     "cve": "CVE-2024-40660",
     "osv_id": "ASB-A-347307756",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Makes SurfaceFlinger::setTransactionState sanitize the actual DisplayState entries of an incoming transaction (iterating by reference over a non-const Vector) instead of sanitizing throwaway copies, so permission-gated display changes from unprivileged callers are now stripped.",
      "confidence": "high",
      "backport_notes": [
       "Single commit. The essential change is `for (DisplayState& display : displays)` plus making `displays` non-const through the whole ISurfaceComposer/SurfaceFlinger signature chain. Every override and test double (ISurfaceComposer.cpp, SurfaceFlinger.h, Surface_test.cpp, TestableSurfaceFlinger.h, and on 14 also surfaceflinger_fuzzers_utils.h) must be updated, and any caller passing `{}` for displays (doUncacheBufferTransaction) needs a named lvalue."
      ],
      "meta": {
       "generated": "2026-10-03",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 5,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r2",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r2",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/native",
       "sha": "95185d7fe46c9d3d8ab8721c3a0acb4dcebdadb2",
       "tag": "android-security-15.0.0_r2",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/native"
     ]
    },
    {
     "cve": "CVE-2024-43085",
     "osv_id": "ASB-A-353712853",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "On a USB function switch timeout, UsbDeviceManager now checks whether the current function is FUNCTION_ACCESSORY and, if so, runs the accessory-mode exit path (no data transfer per the commit message) instead of unconditionally re-enabling mScreenUnlockedFunctions.",
      "confidence": "high",
      "backport_notes": [
       "Single-commit, self-contained change: add the mCurrentFunctions == UsbManager.FUNCTION_ACCESSORY branch in the function switch timeout handler and widen notifyAccessoryModeExit to protected as upstream does. The import reorder is optional. Forks with customized UsbDeviceManager handlers should look for the equivalent `msg.arg1 != 1` timeout branch that calls setEnabledFunctions(mScreenUnlockedFunctions, ...)."
      ],
      "meta": {
       "generated": "2026-10-03",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 7,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r2",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r2",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "f46d19f31d8f0e5b826d332c5d18f674be0f749d",
       "tag": "android-security-15.0.0_r2",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-43091",
     "osv_id": "ASB-A-344620577",
     "source": "osv",
     "announced": "2024-11-01",
     "severity": "High",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "SkEmbossMaskFilter::filterMask now sizes and checks the 3D mask allocation with dst->computeTotalImageSize() instead of checking only a single plane size and then allocating planeSize * 3 without an overflow check.",
      "confidence": "medium",
      "backport_notes": [
       "For trees older than SkMaskBuilder, follow the Android 14 variant (SkMask* dst, dst->fImage, SkMask::AllocImage). The fix relies on dst->computeTotalImageSize() being available and returning 0 when the size is too big."
      ],
      "meta": {
       "generated": "2026-10-03",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 7,
       "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
      }
     },
     "method": [
      "bug_id"
     ],
     "confidence": "certain",
     "first_fix": {
      "tag": "android-security-15.0.0_r2",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r2",
      "date": "2024-11-04",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/external/skia",
       "sha": "b8081964ce86f26b37361d4c91128edd98b516c5",
       "tag": "android-security-15.0.0_r2",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/external/skia"
     ]
    }
   ],
   "tags": [
    "android-security-15.0.0_r1",
    "android-security-15.0.0_r2"
   ],
   "unannounced": [],
   "coverage": {
    "n_ingested_tags": 18,
    "first_ingested_tag": "android-security-15.0.0_r1",
    "latest_ingested_tag": "android-security-15.0.0_r18",
    "window_base_tag": "android-15.0.0_r1",
    "window_start": "2024-09-03",
    "partial_tags": []
   },
   "platform_update_tags": {},
   "briefs": {
    "CVE-2024-40660": {
     "cve": "CVE-2024-40660",
     "summary": "Makes SurfaceFlinger::setTransactionState sanitize the actual DisplayState entries of an incoming transaction (iterating by reference over a non-const Vector) instead of sanitizing throwaway copies, so permission-gated display changes from unprivileged callers are now stripped.",
     "component": "platform/frameworks/native, SurfaceFlinger transaction handling (services/surfaceflinger, libs/gui ISurfaceComposer)",
     "weakness": "Ineffective permission sanitization (sanitize() applied to a by-value loop copy, so the original data stayed unmodified); missing authorization enforcement on DisplayState",
     "root_cause": "In services/surfaceflinger/SurfaceFlinger.cpp, SurfaceFlinger::setTransactionState computed the caller's permissions with LayerStatePermissions::getTransactionPermissions(originPid, originUid) and then ran `for (DisplayState display : displays) { display.sanitize(permissions); }`. Because `displays` was a `const Vector<DisplayState>&` and the loop variable was declared by value, sanitize() changed a temporary copy that was discarded at the end of each iteration, so the elements of `displays` were left unsanitized. The ComposerState loop just above it iterates `auto&` and sanitizes in place. The new test shows the effect: before the fix, an untrusted caller's setDisplayProjection (display orientation) change could take effect.",
     "fix_analysis": [
      "services/surfaceflinger/SurfaceFlinger.cpp:SurfaceFlinger::setTransactionState: the `displays` parameter becomes `Vector<DisplayState>&` (non-const) and the loop becomes `for (DisplayState& display : displays)`, so display.sanitize(permissions) now modifies the real elements.",
      "services/surfaceflinger/SurfaceFlinger.h and libs/gui/include/gui/ISurfaceComposer.h:setTransactionState: the virtual interface and override signatures change from `const Vector<DisplayState>&` to `Vector<DisplayState>&` to allow in-place mutation.",
      "libs/gui/ISurfaceComposer.cpp:BpSurfaceComposer::setTransactionState: the proxy signature is updated to match; its body (serializing `displays` into the Parcel) is unchanged.",
      "libs/gui/SurfaceComposerClient.cpp:SurfaceComposerClient::doUncacheBufferTransaction: the `{}` temporary passed as the displays argument is replaced by a named `Vector<DisplayState> displayStates` lvalue, because a temporary can no longer bind to the non-const reference.",
      "libs/gui/tests/Surface_test.cpp:FakeSurfaceComposer::setTransactionState and services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h:setTransactionState: test doubles are updated to the new signature.",
      "services/surfaceflinger/tests/Credentials_test.cpp: adds DisplayTransactionPermissionTest, which checks that a setDisplayProjection transaction from AID_BIN leaves the display orientation unchanged while the same transaction from AID_SYSTEM changes it. It also fixes a lambda capture ([=, this]) in CaptureLayersTest."
     ],
     "completeness": [
      "The fix covers the DisplayState sanitization loop in SurfaceFlinger::setTransactionState; after the fix every element of `displays` is sanitized in place.",
      "The ComposerState sanitization loop in the same function already iterated by reference (`for (auto& composerState : states)`) and is not changed.",
      "This commit does not modify DisplayState::sanitize(permissions) itself (which fields it clears and under which permission bits), and its body is not shown in the material.",
      "The inputWindowCommands and eEarlyWakeup flag checks that follow in the same function are untouched."
     ],
     "behavior_changes": [
      "DisplayState fields gated by DisplayState::sanitize are now silently dropped for callers without the required permission. The test shows no error is returned; the display orientation simply does not change.",
      "ISurfaceComposer::setTransactionState signature change (the displays parameter is now a non-const reference): callers passing temporaries such as `{}` must pass an lvalue instead, as done in doUncacheBufferTransaction.",
      "Privileged callers (AID_SYSTEM in the test) can still change the display orientation."
     ],
     "preconditions": [
      "The caller reaches SurfaceFlinger's setTransactionState (SET_TRANSACTION_STATE) with a transaction containing one or more DisplayState entries, for example via SurfaceComposerClient::Transaction::setDisplayProjection as in the new test.",
      "The caller lacks the permission bits that DisplayState::sanitize checks (the test uses AID_BIN as the untrusted identity and AID_SYSTEM as the trusted one). Permissions come from LayerStatePermissions::getTransactionPermissions(originPid, originUid).",
      "A display token for the target display is needed (the test gets it via getFirstDisplayToken)."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/native 064ce6e3235b in android-security-14.0.0_r12, with identical logic (reference iteration, signature change, doUncacheBufferTransaction lvalue, Credentials_test). It also updates the signature in services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h, which is not in the 15 commit. 7/8 lines of the patched region present at android-security-14.0.0_r29.",
      "15": "same fix: 95185d7fe46c in android-security-15.0.0_r2 (cherry-pick of f65da8a9d7b6). At android-security-15.0.0_r17 the code context shows `Vector<DisplayState>& displays` and `for (DisplayState& display : displays)` in SurfaceFlinger::setTransactionState (7/8 patched lines present).",
      "16": "not affected (not listed by the bulletin); 3/8 lines of the patched region present at android-security-16.0.0_r8.",
      "17": "not affected (not listed by the bulletin); 3/8 lines of the patched region present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Single commit. The essential change is `for (DisplayState& display : displays)` plus making `displays` non-const through the whole ISurfaceComposer/SurfaceFlinger signature chain. Every override and test double (ISurfaceComposer.cpp, SurfaceFlinger.h, Surface_test.cpp, TestableSurfaceFlinger.h, and on 14 also surfaceflinger_fuzzers_utils.h) must be updated, and any caller passing `{}` for displays (doUncacheBufferTransaction) needs a named lvalue."
     ],
     "confidence": "high",
     "unknowns": [
      "The body of DisplayState::sanitize(permissions), and exactly which DisplayState fields or flags it clears, are not in the material; the test only demonstrates the orientation (setDisplayProjection) effect.",
      "How the rest of setTransactionState uses `displays` after sanitization is not shown in the material.",
      "The concrete privilege-escalation impact behind the High/EoP rating is not shown.",
      "Why Android 16/17 only partially match the patched region is not shown."
     ],
     "meta": {
      "generated": "2026-10-03",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 5,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-43085": {
     "cve": "CVE-2024-43085",
     "summary": "On a USB function switch timeout, UsbDeviceManager now checks whether the current function is FUNCTION_ACCESSORY and, if so, runs the accessory-mode exit path (no data transfer per the commit message) instead of unconditionally re-enabling mScreenUnlockedFunctions.",
     "component": "platform/frameworks/base, services/usb (UsbDeviceManager, USB gadget function switching)",
     "weakness": "Improper handling of an exceptional condition (fail-open fallback state on timeout); the timeout path restored data-transfer functions regardless of the prior accessory state.",
     "root_cause": "In services/usb/java/com/android/server/usb/UsbDeviceManager.java, the handler case for the function switch timeout (the case preceding MSG_GADGET_HAL_REGISTERED) reacted to msg.arg1 != 1 by always calling setEnabledFunctions(mScreenUnlockedFunctions, false, operationId), i.e. it fell back to the default USB function (which, per the code comment, may have been selected from Developer options). It did not consider whether the current function was FUNCTION_ACCESSORY. Per the commit message, when the last function set was accessory, the recommended fallback is NONE (no data transfer), not the default USB function.",
     "fix_analysis": [
      "UsbDeviceManager.java, function switch timeout case (msg.arg1 != 1 branch): adds a check `if (mCurrentFunctions == UsbManager.FUNCTION_ACCESSORY)`. When it is true, the code calls notifyAccessoryModeExit(operationId). That method is unchanged, and its comment says it makes sure accessory mode is off and restores default functions; the commit message describes the outcome as setting the function to NONE (no data transfer). Otherwise the previous call, setEnabledFunctions(mScreenUnlockedFunctions, false, operationId), is kept.",
      "UsbDeviceManager.java: notifyAccessoryModeExit changed from private to protected (the material does not state the reason).",
      "Cosmetic: the `import android.text.TextUtils;` line is moved to its sorted position (Android 15 commit only)."
     ],
     "completeness": [
      "The fix only touches the function switch timeout branch (msg.arg1 != 1) and only when mCurrentFunctions equals UsbManager.FUNCTION_ACCESSORY exactly. Combined function sets that include accessory alongside other functions are not matched by the equality check (the material does not show whether such combinations can occur here).",
      "The non-accessory timeout path still falls back to mScreenUnlockedFunctions, unchanged.",
      "No change to notifyAccessoryModeExit itself or to other callers of setEnabledFunctions. The fix relies on the existing accessory exit path producing the no-data-transfer state."
     ],
     "behavior_changes": [
      "When a USB function switch times out while the current function is accessory, the device now goes through the accessory-exit path (no data transfer, per the commit message) instead of falling back to mScreenUnlockedFunctions.",
      "notifyAccessoryModeExit visibility widened from private to protected."
     ],
     "preconditions": [
      "The USB gadget function switch must time out or fail (handler message with msg.arg1 != 1 in the timeout case).",
      "mCurrentFunctions must be UsbManager.FUNCTION_ACCESSORY at that moment."
     ],
     "per_major": {
      "14": "same fix (same logic change, without the TextUtils import reorder): platform/frameworks/base 2457d4e459ee in android-security-14.0.0_r14; 7/8 patched-region lines present at android-security-14.0.0_r29 (the material does not say which line is missing).",
      "15": "same fix: platform/frameworks/base f46d19f31d8f in android-security-15.0.0_r2; 8/8 patched-region lines present at android-security-15.0.0_r17.",
      "16": "not affected per the bulletin (not listed); patched region present (8/8 lines) at android-security-16.0.0_r8.",
      "17": "not affected per the bulletin (not listed); patched region present (8/8 lines) at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Single-commit, self-contained change: add the mCurrentFunctions == UsbManager.FUNCTION_ACCESSORY branch in the function switch timeout handler and widen notifyAccessoryModeExit to protected as upstream does. The import reorder is optional. Forks with customized UsbDeviceManager handlers should look for the equivalent `msg.arg1 != 1` timeout branch that calls setEnabledFunctions(mScreenUnlockedFunctions, ...)."
     ],
     "confidence": "high",
     "unknowns": [
      "The bulletin lists 12, 12L and 13 as affected, but the material contains no fix commit for those branches.",
      "The material does not show the body of notifyAccessoryModeExit beyond its comment, the exact message name of the timeout case, or what concretely happens on the vulnerable path (the commit message only states that the recommended fallback is NONE).",
      "Why notifyAccessoryModeExit was made protected.",
      "How the timeout is triggered in practice (e.g. whether a physically attached USB host or accessory is needed)."
     ],
     "meta": {
      "generated": "2026-10-03",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 7,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    },
    "CVE-2024-43091": {
     "cve": "CVE-2024-43091",
     "summary": "SkEmbossMaskFilter::filterMask now sizes and checks the 3D mask allocation with dst->computeTotalImageSize() instead of checking only a single plane size and then allocating planeSize * 3 without an overflow check.",
     "component": "platform/external/skia, src/effects (SkEmbossMaskFilter, mask filter used by hwui/android.graphics)",
     "weakness": "Integer overflow in allocation size leading to undersized heap buffer (missing overflow check)",
     "root_cause": "In src/effects/SkEmbossMaskFilter.cpp, SkEmbossMaskFilter::filterMask, SkBlurMask::BoxBlur produced the blurred mask and dst->format() was then set to SkMask::k3D_Format. After that, the code computed planeSize = dst->computeImageSize(), checked only that planeSize was non-zero, and allocated SkMaskBuilder::AllocImage(planeSize * 3). The multiplication by 3 was not checked for overflow. For a large enough plane, the allocation could wrap to a size smaller than the three planes that SkEmbossMask::Emboss operates on.",
     "fix_analysis": [
      "src/effects/SkEmbossMaskFilter.cpp:SkEmbossMaskFilter::filterMask: compute totalSize = dst->computeTotalImageSize() (dst->format() is already k3D_Format at this point) and return false if it is 0 (comment: 'too big to allocate, abort').",
      "Then compute planeSize = dst->computeImageSize() only for the memcpy of the existing alpha plane. An SkASSERT(planeSize != 0) documents that this cannot overflow if totalSize did not.",
      "Allocate dst->image() = SkMaskBuilder::AllocImage(totalSize) instead of AllocImage(planeSize * 3)."
     ],
     "completeness": [
      "The fix covers the single allocation site in SkEmbossMaskFilter::filterMask. The following memcpy of the alpha plane, SkEmbossMask::Emboss and the final memcpy(dst->image(), src.fImage, src.computeImageSize()) are unchanged and rely on the new buffer size.",
      "Correctness depends on computeTotalImageSize() covering all three planes and returning 0 on overflow for k3D_Format. Its implementation is not in the material.",
      "The material shows no other uses of the planeSize * 3 pattern."
     ],
     "behavior_changes": [
      "filterMask now returns false (filter aborted) when computeTotalImageSize() returns 0. Before the fix, the code would go on with a possibly undersized allocation."
     ],
     "preconditions": [
      "An SkEmbossMaskFilter is applied to a mask with src.fFormat == SkMask::kA8_Format, SkBlurMask::BoxBlur succeeds, and src.fImage != nullptr.",
      "The blurred mask must be large enough that planeSize * 3 overflows size_t.",
      "Per index search, the deprecated android.graphics.EmbossMaskFilter constructor (nativeConstructor), SkMaskFilterGlue::createEmboss in frameworks/base/libs/hwui/jni/MaskFilter.cpp and Paint.setMaskFilter exist in Android 15. The exact JNI binding and the draw path to filterMask are not shown."
     ],
     "per_major": {
      "14": "adapted fix: commit 0b628a960e74 (RESTRICT AUTOMERGE) in android-security-14.0.0_r14. Same logic written for the older API (SkMask* dst, dst->fImage, SkMask::AllocImage/FreeImage). At android-security-14.0.0_r29, 4/7 lines of the patched region are present.",
      "15": "same fix: commit b8081964ce86 in android-security-15.0.0_r2, using the SkMaskBuilder API. At android-security-15.0.0_r17, 4/7 lines of the patched region match, and the code context shows the fixed code.",
      "16": "not affected (not listed by the bulletin). At android-security-16.0.0_r8, 4/7 lines of the patched region are present.",
      "17": "not affected (not listed by the bulletin). At android-security-17.0.0_r1, 4/7 lines of the patched region are present."
     },
     "backport_notes": [
      "For trees older than SkMaskBuilder, follow the Android 14 variant (SkMask* dst, dst->fImage, SkMask::AllocImage). The fix relies on dst->computeTotalImageSize() being available and returning 0 when the size is too big."
     ],
     "confidence": "medium",
     "unknowns": [
      "The implementation of computeTotalImageSize() and its overflow handling for k3D_Format are not shown.",
      "Whether the overflow is reachable in practice: the commit message says 'unclear if even reachable'.",
      "How Android 16/17 code came to contain the fixed lines, and why only 4/7 lines of the patched region match in each tag.",
      "The exact JNI binding from EmbossMaskFilter.nativeConstructor to SkMaskFilterGlue::createEmboss."
     ],
     "meta": {
      "generated": "2026-10-03",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 7,
      "note": "AI-generated from the bulletin, the fixing diffs and their code context, then checked claim by claim by a second model. Statements marked '(general platform knowledge)' are not taken from the material."
     }
    }
   }
  },
  "16": {
   "counts": {
    "announced": 0,
    "certain": 0,
    "probable": 0,
    "not_published": 0,
    "not_covered": 0,
    "awaiting": 0
   },
   "advisories": [],
   "tags": [],
   "unannounced": [],
   "coverage": {
    "n_ingested_tags": 9,
    "first_ingested_tag": "android-security-16.0.0_r1",
    "latest_ingested_tag": "android-security-16.0.0_r9",
    "window_base_tag": "android-16.0.0_r2",
    "window_start": "2025-06-10",
    "partial_tags": []
   },
   "platform_update_tags": {},
   "briefs": {}
  },
  "17": {
   "counts": {
    "announced": 0,
    "certain": 0,
    "probable": 0,
    "not_published": 0,
    "not_covered": 0,
    "awaiting": 0
   },
   "advisories": [],
   "tags": [],
   "unannounced": [],
   "coverage": {
    "n_ingested_tags": 2,
    "first_ingested_tag": "android-security-17.0.0_r1",
    "latest_ingested_tag": "android-security-17.0.0_r2",
    "window_base_tag": "android-17.0.0_r1",
    "window_start": "2026-06-16",
    "partial_tags": []
   },
   "platform_update_tags": {},
   "briefs": {}
  }
 },
 "bulletin": {
  "url": "https://source.android.com/docs/security/bulletin/2024-11-01",
  "latest_version": "1.0",
  "latest_revision": {
   "version": "1.0",
   "date": "November 4, 2024",
   "notes": "Bulletin Published."
  },
  "revisions": [
   {
    "version": "1.0",
    "date": "November 4, 2024",
    "notes": "Bulletin Published."
   }
  ],
  "tracked_since": "2026-09-30",
  "changes_since_tracking": [],
  "out_of_scope_rows": {
   "Imagination Technologies": 7,
   "Kernel": 2,
   "MediaTek components": 2,
   "Qualcomm closed-source components": 4,
   "Qualcomm components": 8
  },
  "note": "changes are only visible from `tracked_since`; earlier revisions of the bulletin cannot be reconstructed. Out-of-scope rows (vendor closed-source, kernel) have no public AOSP code to resolve."
 }
}