{
 "month": "2025-03",
 "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-2025-0081",
     "osv_id": "ASB-A-347735428",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "Critical",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a null-pointer check at the top of dng_lossless_decoder::HuffDecode in external/dng_sdk, so a null Huffman table during lossless JPEG decoding triggers ThrowBadFormat instead of being dereferenced.",
      "confidence": "medium",
      "backport_notes": [
       "Self-contained 4-line insertion at the start of HuffDecode that uses the existing ThrowBadFormat call. The same diff was applied unchanged to 14 and 15."
      ],
      "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_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/external/dng_sdk",
       "sha": "4b02aff0777ba6d4ff37ef134d24855bae100b53",
       "tag": "android-security-14.0.0_r18",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/external/dng_sdk"
     ]
    },
    {
     "cve": "CVE-2025-0084",
     "osv_id": "ASB-A-291281168",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "Critical",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a guard in bta_hf_client_do_disc that aborts discovery when the HF client control block already owns an SDP discovery database, and a NULL check on p_ccb->p_db in process_service_search_attr_rsp that disconnects the SDP connection instead of continuing with no database.",
      "confidence": "high",
      "backport_notes": [
       "One commit with two independent hunks. The only difference between the 14 and 15 versions is the logging API (APPL_TRACE_ERROR/SDP_TRACE_WARNING on 14, log::error/log::warn on 15), so use whichever API the target branch has. The diffs shown contain no flag check for the flag named in the commit message.",
       "Bluetooth is a mainline module on these releases, so a device may receive this via the module update rather than the platform tag (general platform knowledge)."
      ],
      "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_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "c4d8043ef4ea65b63a02f277976d5d31c923a835",
       "tag": "android-security-14.0.0_r18",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2024-0032",
     "osv_id": "ASB-A-283962634",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Replaces FileSystemProvider's exact-match regex for /Android/{data,obb,sandbox} with an overridable shouldHideDocument(documentId) hook. ExternalStorageProvider implements the hook to hide those directories and their entire subtrees (on non-USB storage) from queryChildDocuments, querySearchDocuments and the open-tree flag. The fix also consolidates the queryChildDocuments variants around a single includeHidden parameter.",
      "confidence": "high",
      "backport_notes": [
       "Apply the frameworks/base and DownloadProvider commits together. The base change makes FileSystemProvider.queryChildDocumentsForManage final and removes shouldHide, shouldBlockFromTree and queryChildDocumentsShowAll. DownloadStorageProvider, and any OEM FileSystemProvider subclass that overrides those methods, fails to compile until it overrides the protected 4-arg queryChildDocuments(documentId, projection, sortOrder, includeHidden) and the renamed shouldHideDocument/shouldBlockDirectoryFromTree instead.",
       "Any subclass that depended on the base-class regex must now implement shouldHideDocument itself, since the base default returns false. Run ExternalStorageProviderTests (named in the commit) after porting."
      ],
      "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_r5",
      "date": "2024-02-05",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r5",
      "date": "2024-02-05",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "4af5db76f25348849252e0b8a08f4a517ef842b7",
       "tag": "android-security-14.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/packages/providers/DownloadProvider",
       "sha": "5acd646e0cf63e2c9c0862da7e03531ef0074394",
       "tag": "android-security-14.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 2,
     "public_before_announcement_days": 390,
     "projects": [
      "platform/frameworks/base",
      "platform/packages/providers/DownloadProvider"
     ]
    },
    {
     "cve": "CVE-2024-43090",
     "osv_id": "ASB-A-331180422",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "SystemUI's keyboard shortcut helper now strips any Icon carried in app-provided KeyboardShortcutInfo objects before the shortcuts are displayed. It does this through a new @hide KeyboardShortcutInfo.clearIcon(), called from a new KeyboardShortcuts.sanitiseShortcuts() helper.",
      "confidence": "medium",
      "backport_notes": [
       "The fix is a single frameworks/base commit, but it spans the framework (KeyboardShortcutInfo.clearIcon(); because it is @hide, no public API signature update is needed (general platform knowledge)) and SystemUI. Both halves must land together, because sanitiseShortcuts() calls the new method. On branches that already carry the flag-gated version (as on 15), apply the flag-removal variant instead.",
       "If the target branch's SystemUI also requests IME keyboard shortcuts, consider mirroring the Android 15 commit and sanitising that result path too. Per index search, requestImeKeyboardShortcuts exists in WindowManagerImpl on Android 14."
      ],
      "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/frameworks/base",
       "sha": "4677d3ee0ec2d31acc6108fea7be6cced971da37",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "first_announced": "2024-11-01",
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-43093",
     "osv_id": "ASB-A-341680936",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "ExternalStorageProvider replaces the regex string match used to hide Android/data, Android/obb and Android/sandbox (and their subtrees) with a filesystem identity check (Files.isSameFile). The check walks the resolved file path and its parents against the restricted directories that exist under the document's root, and fails closed on any error.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit touching one file. It relies on getRootFromDocId, getPathFromDocId, RootInfo.rootId and ROOT_ID_PRIMARY_EMULATED already existing in ExternalStorageProvider (referenced but not added by the diff). The commits for 12/12L/13 are not included in the material.",
       "No 'Fix in fork' section was provided, so no per-file fork verdict can be reported."
      ],
      "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/frameworks/base",
       "sha": "67d6e08322019f7ed8e3f80bd6cd16f8bcb809ed",
       "tag": "android-security-14.0.0_r14",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 117,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-49740",
     "osv_id": "ASB-A-308932906",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds server-side enforcement in PhoneInterfaceManager so that only the visual voicemail package (default dialer, system dialer or carrier VVM app) can enable or disable the visual voicemail SMS filter. It also limits the size of VisualVoicemailSmsFilterSettings fields in the Builder: clientPrefix at most 256 chars, originatingNumbers at most 100 entries of at most 256 chars each.",
      "confidence": "medium",
      "backport_notes": [
       "This is a three-commit fix across two projects. The frameworks/base Builder limits do not depend on the Telephony changes. Both Telephony commits are needed: enable in 095be0bb467e and disable in b2c88f00503a. They rely on an existing enforceVisualVoicemailPackage(String, int) helper in PhoneInterfaceManager, whose definition the material does not show.",
       "In trees where enableVisualVoicemailSmsFilter has extra checks (the index shows an enforceTelephonyFeatureWithException call in one snapshot), place enforceVisualVoicemailPackage after mAppOps.checkPackage and before Binder.clearCallingIdentity."
      ],
      "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_r16",
      "date": "2025-01-06",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "ea3337c88a8cb8922447065c16f464300d0b8465",
       "tag": "android-security-14.0.0_r16",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/packages/services/Telephony",
       "sha": "095be0bb467e9bde25726e9edf987c9a2bc0d00b",
       "tag": "android-security-14.0.0_r16",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/packages/services/Telephony",
       "sha": "b2c88f00503a748cea885d03b03c0ddb05a8c311",
       "tag": "android-security-14.0.0_r18",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 3,
     "first_commit_before_announcement_days": 54,
     "multi_tag_fix": true,
     "projects": [
      "platform/frameworks/base",
      "platform/packages/services/Telephony"
     ]
    },
    {
     "cve": "CVE-2025-0078",
     "osv_id": "ASB-A-382775095",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "servicemanager now calls setRequestingSid(true) on its own ServiceManager object before it registers itself as the \"manager\" service, so the flags on the self-registered object match the special flags used for the context object.",
      "confidence": "medium",
      "backport_notes": [
       "Single-line, self-contained change: insert manager->setRequestingSid(true); between sp<ServiceManager>::make(...) and the addService(\"manager\", ...) call in main()."
      ],
      "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_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/native",
       "sha": "1114faa38da8aa094c2b6b7336f838774907e0ec",
       "tag": "android-security-14.0.0_r18",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/native"
     ]
    },
    {
     "cve": "CVE-2025-0079",
     "osv_id": "ASB-A-345258562",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an encryption requirement (BTA_SEC_ENCRYPT / BTM_SEC_OUT_ENCRYPT) next to the existing authentication requirement for the AVDTP and AVCTP L2CAP PSM registrations and outgoing connect requests in the Bluetooth stack.",
      "confidence": "high",
      "backport_notes": [
       "One commit per branch. On a tree with different L2CAP API names (L2CA_Register2/L2CA_ConnectReq2 on 14, L2CA_RegisterWithSecurity/L2CA_ConnectReqWithSecurity on 15), only the sec_level argument at the six call sites needs the ENCRYPT flag OR-ed in. avdt_ad_open_req uses BTM_SEC_OUT_* constants while the other sites use BTA_SEC_* constants, so keep each site's constant family.",
       "Test mocks in system/test/mock/mock_stack_l2cap_api.cc pass sec_level through unchanged (per index search)."
      ],
      "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_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "6893799a69f233e9ec428015631a61e5f431dee0",
       "tag": "android-security-14.0.0_r18",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-0082",
     "osv_id": "ASB-A-376461551",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Replaces the Uri.getEncodedUserInfo()-based cross-user icon check in telecom StatusHints and TelecomServiceImpl (phone account registration) with a new StatusHints.getUserIdFromAuthority() helper that derives the user id from the URI authority (getAuthority()) and rejects any mismatch or unparsable user id.",
      "confidence": "high",
      "backport_notes": [
       "Two-repository dependency: the Telecomm change calls the new public static StatusHints.getUserIdFromAuthority() in frameworks/base, so the frameworks/base commit must be applied first or in the same build. No feature flag is involved (Flag: EXEMPT bugfix)."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 2,
       "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_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "24e31767630fbcfbf22501d62d8c8f5fa8e5417e",
       "tag": "android-security-14.0.0_r18",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/packages/services/Telecomm",
       "sha": "e1a0858925cbb9f6960cd50ddfaa720939463397",
       "tag": "android-security-14.0.0_r18",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 2,
     "projects": [
      "platform/frameworks/base",
      "platform/packages/services/Telecomm"
     ]
    },
    {
     "cve": "CVE-2025-0083",
     "osv_id": "ASB-A-376259166",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Replaces the Uri.getEncodedUserInfo()-based cross-user check on content-URI icons in StatusHints and in TelecomServiceImpl (phone account registration) with a new StatusHints.getUserIdFromAuthority() helper. The helper parses the user id from Uri.getAuthority() and rejects any icon whose user id differs from the caller's, including the percent-encoded test forms and non-numeric prefixes.",
      "confidence": "high",
      "backport_notes": [
       "Apply the frameworks/base StatusHints.java change first. The Telecomm change calls the new @hide StatusHints.getUserIdFromAuthority() and will not build without it (Telecomm is a platform app built against framework internals, general platform knowledge).",
       "The Telecomm hunk is the same on 14 and 15 apart from line offsets. Replace the whole getEncodedUserInfo()/parseInt block, and carry over the two new test cases in testRegisterPhoneAccountImageIconCrossUser."
      ],
      "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_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "24e31767630fbcfbf22501d62d8c8f5fa8e5417e",
       "tag": "android-security-14.0.0_r18",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/packages/services/Telecomm",
       "sha": "e1a0858925cbb9f6960cd50ddfaa720939463397",
       "tag": "android-security-14.0.0_r18",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 2,
     "projects": [
      "platform/frameworks/base",
      "platform/packages/services/Telecomm"
     ]
    },
    {
     "cve": "CVE-2025-0086",
     "osv_id": "ASB-A-364269936",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a check in AccountManagerService's getAuthToken result handler that rejects an authenticator response whose KEY_ACCOUNT_TYPE differs from the session's account type, returning ERROR_CODE_INVALID_RESPONSE instead of storing the token.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained hunk with no dependencies. Apply it inside the getAuthToken Session.onResult block right after the empty name/type check, using the existing mAccountType field. The bulletin lists Android 12, 12L and 13 as affected, but the material contains no commit for them."
      ],
      "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_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "b6dcda18039c89751cb293d04bc4a961371dee01",
       "tag": "android-security-14.0.0_r18",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2025-0092",
     "osv_id": "ASB-A-289375038",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "The fix resets a remote device's Message Access, Phonebook Access and SIM Access permissions to ACCESS_UNKNOWN whenever its bond state transitions to BOND_NONE, so that access granted while a device was bonded does not survive unbonding.",
      "confidence": "high",
      "backport_notes": [
       "The Android 14 commit message says it is a backport of ag/30386015 with minor logic changes. On 14 the reset lives in BondStateMachine.sendIntent and calls through mAdapterService. On 15 it lives in AdapterService's bond-state handler next to mDatabaseManager.handleBondStateChanged. When porting, use whichever of the two hook points exists in your tree.",
       "Bluetooth is a mainline (APEX) module on these releases, so the fix may arrive through a module update and not only through the platform security tag (general platform knowledge)."
      ],
      "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_r17",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r17",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "142acc56658c68b549cfa3827abad57741f49ef5",
       "tag": "android-security-14.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-0093",
     "osv_id": "ASB-A-289811388",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "When a device's bond state changes to BOND_NONE, the Bluetooth stack now resets that device's Message Access (MAP), Phonebook Access (PBAP) and SIM Access permissions to ACCESS_UNKNOWN, so access granted earlier does not survive unbonding.",
      "confidence": "high",
      "backport_notes": [
       "The fix is small and self-contained: 7 added lines on 14, 8 on 15, and it only calls existing AdapterService setters. On 14-style trees, add the BOND_NONE check in BondStateMachine's bond-state intent method before mAdapterService.onBondStateChanged and the broadcast. On 15-style trees, add it in AdapterService after mDatabaseManager.handleBondStateChanged."
      ],
      "meta": {
       "generated": "2026-10-04",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 9,
       "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_r17",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r17",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "142acc56658c68b549cfa3827abad57741f49ef5",
       "tag": "android-security-14.0.0_r17",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-26417",
     "osv_id": "ASB-A-304497167",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds an ownership check to DownloadProvider's insert destination-path validation: if MediaStore already has a record for the target file path, the calling UID must own a package equal to that record's OWNER_PACKAGE_NAME, otherwise a SecurityException is thrown.",
      "confidence": "high",
      "backport_notes": [
       "Single-commit, additive change, identical on 14 and 15. It depends on Helpers.getContentUriForPath, Constants.TAG and the existing Helpers.checkDestinationFilePathRestrictions call site. For older branches (12/12L/13, listed by the bulletin), verify that those helpers exist and that the Downloads-dir-only destination check is the right place to add the call.",
       "MediaStore.setIncludePending and OWNER_PACKAGE_NAME are public MediaStore APIs available since Android 10 (general platform knowledge), so no framework change should be needed."
      ],
      "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_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-14.0.0_r18",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/providers/DownloadProvider",
       "sha": "d37a58ed0acb8fa8c216c8c10538ba162943f5d5",
       "tag": "android-security-14.0.0_r18",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/packages/providers/DownloadProvider"
     ]
    }
   ],
   "tags": [
    "android-security-14.0.0_r18"
   ],
   "unannounced": [
    {
     "bug_ids": [
      "290365279"
     ],
     "commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "f8b2c476c238d764d7d1c51bea307c6be1986e49",
       "subject": "Check access permission for QuickAccessWalletTile icon.",
       "tag": "android-security-14.0.0_r18",
       "merged": "2025-01-09",
       "markers": []
      }
     ],
     "tags": [
      "android-security-14.0.0_r18"
     ],
     "tag": "android-security-14.0.0_r18"
    }
   ],
   "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-2025-0081": {
     "cve": "CVE-2025-0081",
     "summary": "Adds a null-pointer check at the top of dng_lossless_decoder::HuffDecode in external/dng_sdk, so a null Huffman table during lossless JPEG decoding triggers ThrowBadFormat instead of being dereferenced.",
     "component": "platform/external/dng_sdk, lossless JPEG decoder (source/dng_lossless_jpeg.cpp)",
     "weakness": "Missing null-pointer check (NULL pointer dereference)",
     "root_cause": "dng_lossless_decoder::HuffDecode (source/dng_lossless_jpeg.cpp) takes a HuffmanTable *htbl and goes straight to the fast 8-bit table lookup and the rest of decoding without checking that the pointer is non-null. The commit title ('Catch null HuffmanTables when decoding jpeg') shows the table pointer can be null at this point. The material does not show how it becomes null.",
     "fix_analysis": [
      "source/dng_lossless_jpeg.cpp: dng_lossless_decoder::HuffDecode: inserts `if (htbl == nullptr) { ThrowBadFormat (); }` before the fast table lookup, so decoding stops with a bad-format error instead of dereferencing the null table.",
      "One commit with one hunk (4 added lines). No other files, headers or call sites are changed."
     ],
     "completeness": [
      "The check is at the point of use inside HuffDecode, so every caller of HuffDecode is covered whichever table is passed.",
      "The fix is defensive. It does not change where the table pointers are set or check table references while the scan header is parsed. The material does not show those code paths, so it is unknown whether other uses of HuffmanTable pointers outside HuffDecode go unchecked.",
      "Only the decoder side is touched. The encoder code in the same file is not modified, and the material gives no sign that it needs a change."
     ],
     "behavior_changes": [
      "Decoding a lossless JPEG stream that reaches HuffDecode with a null Huffman table now calls ThrowBadFormat (a bad-format error) instead of dereferencing a null pointer."
     ],
     "preconditions": [
      "A lossless-JPEG-compressed stream must be decoded by dng_sdk's dng_lossless_decoder (the file instantiates DecodeLosslessJPEG<Scalar>).",
      "The stream must leave a Huffman table pointer null when HuffDecode runs. The material does not show the exact condition.",
      "The material does not show which Android components reach dng_sdk decoding. The index search results (ultrahdr, qcom jpeg test) are not related to dng_sdk."
     ],
     "per_major": {
      "14": "same fix: commit 4b02aff0777b in android-security-14.0.0_r18 (cherry-pick, Change-Id Iaf36c076467d18e4e31d8436a6d199c3276a8786). 3/4 lines of the patched region are present at android-security-14.0.0_r29.",
      "15": "same fix: commit 7fc02c8d5af3 in android-security-15.0.0_r6, identical diff. 3/4 lines of the patched region are present at android-security-15.0.0_r17.",
      "16": "not affected (not listed by the bulletin). 3/4 lines of the patched region are present at android-security-16.0.0_r8.",
      "17": "not affected (not listed by the bulletin). 3/4 lines of the patched region are present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Self-contained 4-line insertion at the start of HuffDecode that uses the existing ThrowBadFormat call. The same diff was applied unchanged to 14 and 15."
     ],
     "confidence": "medium",
     "unknowns": [
      "How the Huffman table pointer becomes null (which part of stream parsing leaves it unset).",
      "Which Android processes or services decode through dng_sdk, and so which process would crash.",
      "Whether 12, 12L and 13 received the same patch; the per-major facts provided do not cover them.",
      "Whether the file uses HuffmanTable pointers elsewhere without going through HuffDecode.",
      "Why only 3/4 lines of the patched region match in the latest security tags."
     ],
     "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-2025-0084": {
     "cve": "CVE-2025-0084",
     "summary": "Adds a guard in bta_hf_client_do_disc that aborts discovery when the HF client control block already owns an SDP discovery database, and a NULL check on p_ccb->p_db in process_service_search_attr_rsp that disconnects the SDP connection instead of continuing with no database.",
     "component": "platform/packages/modules/Bluetooth, system/bta/hf_client (HFP client SDP) and system/stack/sdp (SDP discovery client)",
     "weakness": "Use-after-free (race between two SDP discovery connections sharing one discovery database)",
     "root_cause": "bta_hf_client_do_disc always allocated a new tSDP_DISCOVERY_DB into client_cb->p_disc_db with osi_malloc and set up discovery. It never checked whether the control block already held a discovery database. According to the commit message, a modified client can open two connections against the same SDP discovery database. Once the first connection closes, the second one can reference the freed database. Separately, process_service_search_attr_rsp used p_ccb->p_db without checking for NULL, and the commit adds that check to guard against unchecked use of the database.",
     "fix_analysis": [
      "system/bta/hf_client/bta_hf_client_sdp.cc:bta_hf_client_do_disc: the new check runs after the attribute and UUID lists are built and before osi_malloc of the discovery db. If client_cb->p_disc_db != NULL, the function logs an error (APPL_TRACE_ERROR on 14, log::error on 15), sets client_cb->p_disc_db = NULL, forces client_cb->state = 0 (BTA_HF_CLIENT_INIT_ST) and returns. It does not allocate a second database or start a second discovery. Per the code comment, the state is set by hand because the function can be entered from the OPEN state, where a discovery-fail event would be ignored.",
      "system/stack/sdp/sdp_discovery.cc:process_service_search_attr_rsp: in the branch that sends the continuation or first-time request, if p_ccb->p_db == NULL the function logs a warning (SDP_TRACE_WARNING on 14, log::warn on 15), calls sdp_disconnect(p_ccb, tSDP_STATUS::SDP_INVALID_CONT_STATE) and returns before using the database. This catches only a NULL pointer, not a dangling one.",
      "The commit message names the flag com.android.bluetooth.flags.btsec_check_valid_discovery_database, but neither diff shown contains a flag check. In the shown diffs, both checks run unconditionally."
     ],
     "completeness": [
      "Covers the HF client entry point that allocates the discovery database (bta_hf_client_do_disc) and one SDP response handler (process_service_search_attr_rsp), which gets a NULL p_db check.",
      "Only process_service_search_attr_rsp received the p_db NULL check. The sibling response handlers in sdp_discovery.cc are not in the diff, and the material does not show whether they use p_ccb->p_db without a check.",
      "The guard in bta_hf_client_do_disc sets the existing p_disc_db pointer to NULL. It does not free that database or tear down the earlier SDP connection, and the material does not show how the old database is eventually released.",
      "Only the HF client profile's discovery setup is guarded. Other profiles that allocate SDP discovery databases are outside the diff and not shown in the material."
     ],
     "behavior_changes": [
      "A second bta_hf_client_do_disc call on a control block that already has a discovery database now logs an error, resets the control block state to BTA_HF_CLIENT_INIT_ST and returns without starting discovery. Previously it allocated a second database.",
      "process_service_search_attr_rsp now logs a warning and ends the SDP connection with tSDP_STATUS::SDP_INVALID_CONT_STATE when p_ccb->p_db is NULL. Previously it carried on."
     ],
     "preconditions": [
      "Per the commit message: a modified (malicious) Bluetooth client opens two connections against the same SDP discovery database, and the first connection is then closed.",
      "Per the fix comment, bta_hf_client_do_disc can be entered while the control block is in the OPEN state. The index search returns bta_hf_client_start_open (system/bta/hf_client/bta_hf_client_act.cc) as related code, but the snippet shown does not include a call to bta_hf_client_do_disc.",
      "process_service_search_attr_rsp runs when an SDP ServiceSearchAttribute response arrives on a client SDP connection."
     ],
     "per_major": {
      "14": "same fix: commit c4d8043ef4ea in android-security-14.0.0_r18, using APPL_TRACE_ERROR / SDP_TRACE_WARNING. All 6 lines of the patched region are present at android-security-14.0.0_r29.",
      "15": "adapted fix: commit 94c565214e34 in android-security-15.0.0_r6, with identical logic but log::error / log::warn logging. All 6 lines of the patched region are present at android-security-15.0.0_r17.",
      "16": "not affected: not listed by the bulletin. All 6 lines of the patched region are present at android-security-16.0.0_r8.",
      "17": "not affected: not listed by the bulletin. All 6 lines of the patched region are present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "One commit with two independent hunks. The only difference between the 14 and 15 versions is the logging API (APPL_TRACE_ERROR/SDP_TRACE_WARNING on 14, log::error/log::warn on 15), so use whichever API the target branch has. The diffs shown contain no flag check for the flag named in the commit message.",
      "Bluetooth is a mainline module on these releases, so a device may receive this via the module update rather than the platform tag (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "How two SDP connections come to share one discovery database in the unpatched code path. The commit message describes this only at a high level.",
      "Where the freed database is actually used after the first connection closes. The NULL check in process_service_search_attr_rsp does not catch a dangling pointer.",
      "Whether other response handlers in sdp_discovery.cc use p_ccb->p_db without a check (not in the material).",
      "What happens to the existing database that the new guard drops by setting client_cb->p_disc_db = NULL (whether it is freed elsewhere or leaked).",
      "Whether the flag com.android.bluetooth.flags.btsec_check_valid_discovery_database gates this code anywhere. The diffs shown contain no flag check.",
      "Whether bta_hf_client_start_open calls bta_hf_client_do_disc (the index snippet is cut off)."
     ],
     "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-0032": {
     "cve": "CVE-2024-0032",
     "summary": "Replaces FileSystemProvider's exact-match regex for /Android/{data,obb,sandbox} with an overridable shouldHideDocument(documentId) hook. ExternalStorageProvider implements the hook to hide those directories and their entire subtrees (on non-USB storage) from queryChildDocuments, querySearchDocuments and the open-tree flag. The fix also consolidates the queryChildDocuments variants around a single includeHidden parameter.",
     "component": "platform/frameworks/base (com.android.internal.content.FileSystemProvider, packages/ExternalStorageProvider) and platform/packages/providers/DownloadProvider (DownloadStorageProvider), storage access framework / DocumentsProvider",
     "weakness": "Incomplete path-based access restriction: the hidden-directory check matched only the exact Android/data|obb|sandbox directory, not its descendants, and was keyed on an absolute-path regex.",
     "root_cause": "FileSystemProvider.shouldHide(File) used PATTERN_HIDDEN_PATH, \"(?i)^/storage/[^/]+/(?:[0-9]+/)?Android/(?:data|obb|sandbox)$\", which matches only the restricted directory itself. queryChildDocuments(parentDocumentId, ...) applied this filter to the queried parent and to each child. A document ID whose path pointed inside one of those directories was therefore not recognised as hidden: the parent check passed and the contents were listed. The check also depended on the absolute path starting with /storage/, not on the canonicalised root-relative path of the document ID. ExternalStorageProvider.shouldBlockFromTree relied on the same shouldHide(dir). FLAG_DIR_BLOCKS_OPEN_DOCUMENT_TREE was only computed for writable directories.",
     "fix_analysis": [
      "frameworks/base core/java/com/android/internal/content/FileSystemProvider.java: removes PATTERN_HIDDEN_PATH, shouldHide(File), shouldShow(File), queryChildDocumentsShowAll and the Predicate-based private queryChildDocuments. Adds protected shouldHideDocument(String documentId) (default false) and a final File overload that converts the file via getDocIdForFile(document). Renames shouldBlockFromTree to shouldBlockDirectoryFromTree (default false, may throw FileNotFoundException).",
      "FileSystemProvider.queryChildDocuments(documentId, projection, sortOrder) now delegates to a new protected queryChildDocuments(documentId, projection, sortOrder, includeHidden=false). queryChildDocumentsForManage is made final and delegates with includeHidden=true. The 4-arg method returns an empty cursor if the parent is not a directory. It also returns an empty cursor if !includeHidden && shouldHideDocument(documentId) holds for the parent, and it skips every child for which shouldHideDocument(file) is true.",
      "FileSystemProvider.querySearchDocuments: the BFS is rewritten on ArrayDeque with MAX_RESULTS_NUMBER=23. Each dequeued file is skipped (and not expanded) when shouldHideDocument(file) is true. The exclusion set and matchSearchQueryArguments are applied after that.",
      "FileSystemProvider.includeFile: FLAG_DIR_BLOCKS_OPEN_DOCUMENT_TREE is now set for any directory where shouldBlockDirectoryFromTree(docId) is true, independent of file.canWrite(). Delete, rename and move flags are set for writable files and directories alike.",
      "packages/ExternalStorageProvider ExternalStorageProvider.java: adds PATTERN_RESTRICTED_ANDROID_SUBTREES = \"^Android/(?:data|obb|sandbox)(?:/.+)?\" (CASE_INSENSITIVE) and overrides shouldHideDocument(documentId). The override returns false if isOnRemovableUsbStorage(documentId). Otherwise it matches getPathFromDocId(documentId) (canonicalised, no leading or trailing slash) against the pattern, so the directories and all their descendants are hidden. The file also removes its queryChildDocumentsForManage override, which the final base method now handles.",
      "ExternalStorageProvider.shouldBlockDirectoryFromTree(documentId) keeps the same checks: non-directory returns false, USB returns false, root returns true, Download and Android return true. It now ends with a shouldHideDocument(documentId) check and propagates FileNotFoundException instead of wrapping IOException in IllegalArgumentException. A new helper, isOnRemovableUsbStorage(documentId), checks Root.FLAG_REMOVABLE_USB on getRootFromDocId. getPathFromDocId no longer throws: on IOException during canonicalisation it logs and returns \"\". The visible parameter is dropped from buildFile and resolveDocId.",
      "packages/providers/DownloadProvider DownloadStorageProvider.java: removes its own queryChildDocuments and queryChildDocumentsForManage overrides (the latter is now final in the base class). It overrides the protected 4-arg queryChildDocuments(documentId, projection, sortOrder, includeHidden) instead. Raw document IDs delegate to super.queryChildDocuments(..., includeHidden). The former manage flag becomes includeHidden for includeDownloadsFromMediaStore and the DownloadManager query."
     ],
     "completeness": [
      "Covers listing (queryChildDocuments), recursive search (querySearchDocuments) and tree-selection blocking for Android/data, Android/obb and Android/sandbox and all their subdirectories and files on the integrated shared storage. Matching is case-insensitive and uses the canonicalised root-relative path from the document ID.",
      "Hiding is explicitly skipped for roots with Root.FLAG_REMOVABLE_USB (isOnRemovableUsbStorage). The old base-class regex applied in queryChildDocuments to any /storage/<vol>/ path, so listing on USB volumes is now less restricted than before.",
      "The diff adds shouldHideDocument calls only in queryChildDocuments, querySearchDocuments and shouldBlockDirectoryFromTree (used by includeFile's tree flag). It adds none to other document-ID entry points. The index shows FileSystemProvider.openDocument resolving getFileForDocId(documentId) directly. The other entry points' bodies are not shown.",
      "If getPathFromDocId fails to canonicalise the path, it returns \"\". shouldHideDocument treats that as not hidden, while shouldBlockDirectoryFromTree treats it as root and blocks it.",
      "The default shouldHideDocument in FileSystemProvider returns false, so other FileSystemProvider subclasses hide nothing unless they override it. The previous base-class regex did apply to them (for example, DownloadStorageProvider raw documents through the 3-arg super call)."
     ],
     "behavior_changes": [
      "A child-listing query (queryChildDocuments) on ExternalStorageProvider for a directory inside Android/data, Android/obb or Android/sandbox (any depth, any case) now returns an empty cursor and logs 'Queried directory ... is hidden'. Such entries are also omitted from parent listings and search results. queryChildDocumentsForManage (includeHidden=true) still returns them.",
      "FLAG_DIR_BLOCKS_OPEN_DOCUMENT_TREE is now set on blocked directories even when they are not writable. The FLAG_SUPPORTS_DELETE/RENAME/MOVE computation is restructured without changing which flags writable entries receive.",
      "Hidden-path filtering no longer applies to removable USB roots in ExternalStorageProvider.",
      "queryChildDocumentsForManage is final in FileSystemProvider, so subclasses must override the protected 4-arg queryChildDocuments. shouldHide and shouldBlockFromTree are replaced by shouldHideDocument and shouldBlockDirectoryFromTree.",
      "ExternalStorageProvider.shouldBlockDirectoryFromTree now throws FileNotFoundException instead of IllegalArgumentException on resolution failure. getPathFromDocId no longer throws IOException.",
      "DownloadStorageProvider: raw-document manage queries now pass includeHidden=true to the base class. Previously they called the 3-arg base method, which applied hiding."
     ],
     "preconditions": [
      "A caller can issue a DocumentsProvider child-listing or search query against ExternalStorageProvider with a document ID of the form root:path whose path resolves under Android/data, Android/obb or Android/sandbox on the integrated (non-USB) shared storage.",
      "How a caller obtains query access to the provider is not shown in the material."
     ],
     "per_major": {
      "14": "Same fix: frameworks/base 4af5db76f253 and DownloadProvider 5acd646e0cf6 both landed in android-security-14.0.0_r5 (cherry-picks of internal changes). At android-security-14.0.0_r29 the per-major facts report only 2/8 lines of the patched region present. The reason is not shown in the material, so the current state of that region is unverified. The FileSystemProvider imports (ArrayDeque, Queue) and MAX_RESULTS_NUMBER are present at r29.",
      "15": "Not affected: the bulletin does not list Android 15. 8/8 lines of the patched region are present at android-security-15.0.0_r17.",
      "16": "Not affected: the bulletin does not list Android 16. 8/8 lines of the patched region are present at android-security-16.0.0_r8.",
      "17": "Not affected: the bulletin does not list Android 17. 8/8 lines of the patched region are present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Apply the frameworks/base and DownloadProvider commits together. The base change makes FileSystemProvider.queryChildDocumentsForManage final and removes shouldHide, shouldBlockFromTree and queryChildDocumentsShowAll. DownloadStorageProvider, and any OEM FileSystemProvider subclass that overrides those methods, fails to compile until it overrides the protected 4-arg queryChildDocuments(documentId, projection, sortOrder, includeHidden) and the renamed shouldHideDocument/shouldBlockDirectoryFromTree instead.",
      "Any subclass that depended on the base-class regex must now implement shouldHideDocument itself, since the base default returns false. Run ExternalStorageProviderTests (named in the commit) after porting."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact trigger and which path form (non-/storage/ mount, path casing, or a subdirectory document ID) was used in the reported issue. The bulletin gives only High/EoP.",
      "Why android-security-14.0.0_r29 has only 2/8 lines of the patched region present, and which file's region this refers to. The surrounding code at r29 is not shown.",
      "Contents of the two internal cherry-picked changes (7f5667bf..., cf28630a...) beyond what is in the AOSP commit.",
      "Whether the Android 12/12L/13 backports differ from this Android 14 change.",
      "Whether the bulletin's '15-next' entry corresponds to any Android 15 release branch. The per-major facts treat Android 15 as not listed."
     ],
     "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-43090": {
     "cve": "CVE-2024-43090",
     "summary": "SystemUI's keyboard shortcut helper now strips any Icon carried in app-provided KeyboardShortcutInfo objects before the shortcuts are displayed. It does this through a new @hide KeyboardShortcutInfo.clearIcon(), called from a new KeyboardShortcuts.sanitiseShortcuts() helper.",
     "component": "platform/frameworks/base, SystemUI keyboard shortcut helper (KeyboardShortcuts / KeyboardShortcutListSearch) and android.view.KeyboardShortcutInfo",
     "weakness": "Missing sanitisation of untrusted app-supplied data (Icon) consumed by a privileged UI; the bulletin classifies it as information disclosure (ID)",
     "root_cause": "KeyboardShortcutInfo is a Parcelable whose mIcon field can be populated by the providing app. The commit message notes this is only possible via reflection and is not intended for use outside the system. SystemUI requested the focused app's shortcuts via WindowManager.requestAppKeyboardShortcuts. Per index search, the result reached KeyboardShortcuts.showKeyboardShortcuts / KeyboardShortcutListSearch.showKeyboardShortcuts via WindowManagerImpl.requestAppKeyboardShortcuts -> IResultReceiver.send -> onKeyboardShortcutsReceived. From there it was passed unchanged to showKeyboardShortcutsDialog or reMapToKeyboardShortcutMultiMappingGroup, so an app-controlled Icon reached the SystemUI shortcut helper. On Android 15 the governing flag is named validateKeyboardShortcutHelperIconUri, which hints that the concern is app-supplied icon URIs. The bulletin rates this as High ID.",
     "fix_analysis": [
      "core/java/android/view/KeyboardShortcutInfo.java: mIcon is no longer final, and a new @hide method clearIcon() sets mIcon = null.",
      "packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java: a new package-private static sanitiseShortcuts(List<KeyboardShortcutGroup>) walks every group and every KeyboardShortcutInfo in group.getItems() and calls info.clearIcon(). In showKeyboardShortcuts(int), the onKeyboardShortcutsReceived callback now calls sanitiseShortcuts(result) first. Only after that does it append getSystemShortcuts()/getDefaultApplicationShortcuts() and run showKeyboardShortcutsDialog(result). As a result only the app-provided groups are stripped.",
      "packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java: in showKeyboardShortcuts(int), the non-empty branch of onKeyboardShortcutsReceived calls KeyboardShortcuts.sanitiseShortcuts(result) before reMapToKeyboardShortcutMultiMappingGroup(result) builds mSpecificAppGroup.",
      "Android 15 (f1a15b5ef253): the sanitiseShortcuts() calls already existed there but were gated by Flags.validateKeyboardShortcutHelperIconUri. The fix removes the flag checks, so sanitisation is unconditional in KeyboardShortcuts (app and IME result handlers) and in KeyboardShortcutListSearch (specific-app and IME branches). It also removes the @EnableFlags annotations from the corresponding tests."
     ],
     "completeness": [
      "On Android 14 the commit covers the two SystemUI consumers of requestAppKeyboardShortcuts shown in the material (KeyboardShortcuts and KeyboardShortcutListSearch). It clears the icon on every item of every returned group.",
      "The mitigation is applied at the consumer (SystemUI), not where the data is produced or relayed. KeyboardShortcutInfo still parcels and unparcels an app-set Icon, and the commit does not change the system_server path. Any other consumer of these icons is therefore not covered by this commit.",
      "The Android 14 commit sanitises only the app-shortcut result path. The Android 15 commit also sanitises IME shortcut results. The Android 14 code shown has no IME shortcut request in these two classes, so the material does not show whether such a path exists on 14 or whether it is unsanitised.",
      "The removal is coarse: no URI validation is attempted, and all app-provided icons are dropped."
     ],
     "behavior_changes": [
      "Shortcuts provided by the focused app appear in the SystemUI shortcut helper without any icon. The system and default-application groups that SystemUI builds itself are added after sanitisation and are not affected.",
      "KeyboardShortcutInfo gains a @hide mutator clearIcon(), and mIcon is no longer final.",
      "On Android 15, sanitisation no longer depends on the validateKeyboardShortcutHelperIconUri flag."
     ],
     "preconditions": [
      "A focused app returns KeyboardShortcutGroup items whose KeyboardShortcutInfo has a non-null Icon. Per the commit message, this is only settable via reflection.",
      "The SystemUI keyboard shortcut helper is opened, so that KeyboardShortcuts.showKeyboardShortcuts or KeyboardShortcutListSearch.showKeyboardShortcuts calls WindowManager.requestAppKeyboardShortcuts. Per index search, the result is delivered through WindowManagerImpl.requestAppKeyboardShortcuts -> IResultReceiver.send -> onKeyboardShortcutsReceived."
     ],
     "per_major": {
      "14": "Same fix: commit 4677d3ee0ec2 (RESTRICT AUTOMERGE, cherry-picked from internal commit 8dc5ed150f2c) in android-security-14.0.0_r14 adds clearIcon(), sanitiseShortcuts() and the two call sites. 8/8 lines of the patched region are present at android-security-14.0.0_r29.",
      "15": "Adapted fix: commit f1a15b5ef253 (RESTRICT AUTOMERGE) in android-security-15.0.0_r6 removes the validateKeyboardShortcutHelperIconUri flag gate around existing sanitiseShortcuts() calls, for both app and IME shortcut results, and updates the tests. 7/8 lines of the patched region are present at android-security-15.0.0_r17; the material does not explain the one-line difference.",
      "16": "Not affected (not listed by the bulletin). 8/8 lines of the patched region are present at android-security-16.0.0_r8.",
      "17": "Not affected (not listed by the bulletin). 8/8 lines of the patched region are present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "The fix is a single frameworks/base commit, but it spans the framework (KeyboardShortcutInfo.clearIcon(); because it is @hide, no public API signature update is needed (general platform knowledge)) and SystemUI. Both halves must land together, because sanitiseShortcuts() calls the new method. On branches that already carry the flag-gated version (as on 15), apply the flag-removal variant instead.",
      "If the target branch's SystemUI also requests IME keyboard shortcuts, consider mirroring the Android 15 commit and sanitising that result path too. Per index search, requestImeKeyboardShortcuts exists in WindowManagerImpl on Android 14."
     ],
     "confidence": "medium",
     "unknowns": [
      "The material does not show how the Icon is rendered in the dialog or what information is disclosed. The only hints are the ID classification and the Android 15 flag name (validateKeyboardShortcutHelperIconUri).",
      "It is not shown whether Android 14 SystemUI has an IME keyboard shortcut path that would need the same treatment.",
      "It is not shown whether there are other Android 14 consumers of requestAppKeyboardShortcuts beyond the two classes patched.",
      "The nature of the one-line difference in the patched region at android-security-15.0.0_r17 is not shown.",
      "It is not shown whether the flag-gated code that already existed on Android 15 shipped with the flag enabled."
     ],
     "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-43093": {
     "cve": "CVE-2024-43093",
     "summary": "ExternalStorageProvider replaces the regex string match used to hide Android/data, Android/obb and Android/sandbox (and their subtrees) with a filesystem identity check (Files.isSameFile). The check walks the resolved file path and its parents against the restricted directories that exist under the document's root, and fails closed on any error.",
     "component": "platform/frameworks/base, packages/ExternalStorageProvider (ExternalStorageProvider DocumentsProvider)",
     "weakness": "Incomplete path-based access restriction: the access decision was made by a textual pattern match on a path derived from the document id instead of on filesystem identity",
     "root_cause": "In ExternalStorageProvider.java, access to the Android/data, Android/obb and Android/sandbox subtrees was restricted by matching the string returned by getPathFromDocId(documentId) against PATTERN_RESTRICTED_ANDROID_SUBTREES (\"^Android/(?:data|obb|sandbox)(?:/.+)?\", CASE_INSENSITIVE). This checks only how the path is spelled, not which directory it resolves to on disk. The commit message says the fix is \"Replacing path's pattern match check with file equality check\". From that change one can infer (the material does not show it) that path strings which do not match the regex literally but resolve into a restricted tree were not treated as restricted. The exact bypassing input is not shown in the material.",
     "fix_analysis": [
      "ExternalStorageProvider.java: removes PATTERN_RESTRICTED_ANDROID_SUBTREES and the CASE_INSENSITIVE/Pattern imports. Adds the constants PRIMARY_EMULATED_STORAGE_PATH = \"/storage/emulated/\" and STORAGE_PATH = \"/storage/\", plus imports for java.nio.file.Files/Paths, Arrays and Collectors.",
      "ExternalStorageProvider.java, restricted-subtree check method (name not visible in the hunk; it previously returned PATTERN_RESTRICTED_ANDROID_SUBTREES.matcher(path).matches()): inside a try block it now resolves RootInfo root = getRootFromDocId(documentId) and canonicalPath = getPathFromDocId(documentId), then returns isRestrictedPath(root.rootId, canonicalPath). Any Exception makes the method return true (restricted). The existing early 'return false' above the hunk is kept.",
      "ExternalStorageProvider.java:isRestrictedPath(String rootId, String canonicalPath) (new): returns true if rootId or canonicalPath is null. Builds rootPath as \"/storage/emulated/\" + UserHandle.myUserId() when rootId equalsIgnoreCase ROOT_ID_PRIMARY_EMULATED, otherwise as \"/storage/\" + rootId. Builds the paths rootPath/Android/data, rootPath/Android/obb and rootPath/Android/sandbox, and keeps only those for which Files.exists is true.",
      "isRestrictedPath: starting from Paths.get(rootPath, canonicalPath), it loops while the path is non-null. Each step tests Files.isSameFile(restrictedPath, filePathToCheck) against every existing restricted directory, then moves to getParent(). A match sets isRestricted = true (logged at Log.v) and ends the walk. Any Exception during the walk is logged at Log.w and sets isRestricted = true, so the check fails closed."
     ],
     "completeness": [
      "The check now compares the filesystem identity of the resolved document path and every ancestor against the three restricted directories. This covers the directories themselves and all nested content, for both the primary emulated root and other roots mapped to /storage/<rootId>.",
      "Only restricted directories that currently exist on disk are compared (Files::exists filter). If none of the three exist for the computed rootPath, validRestrictedPathsToCheck is empty, the loop never calls isSameFile, and the method returns false (not restricted).",
      "The non-primary root mapping assumes the volume is mounted at \"/storage/\" + rootId. The material does not show how rootId is derived for other volumes.",
      "The restriction is computed for UserHandle.myUserId(); no cross-user path handling is added.",
      "The walk is not bounded by rootPath: getParent() continues up to \"/\".",
      "Only this one check method is changed. getPathFromDocId, getRootFromDocId and the 'root of storage or blocked file from tree' check that follows the hunk are not modified by this commit."
     ],
     "behavior_changes": [
      "The restriction decision now performs filesystem I/O (Files.exists, Files.isSameFile) on each call instead of a pure string match.",
      "Fail-closed: any exception while resolving the root or path, or during the identity walk, is now caught and the document is treated as restricted.",
      "Case-insensitive textual matching is replaced by filesystem identity.",
      "New verbose log on restriction and warning log on errors."
     ],
     "preconditions": [
      "A caller must be able to send DocumentsProvider requests to ExternalStorageProvider with a document id whose path reaches the Android/data, Android/obb or Android/sandbox tree without matching the old regex literally. The exact input form is not shown in the material.",
      "The existing early 'return false' guard at the top of the modified method must not apply (its condition is not shown in the hunk)."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/base 67d6e0832201 in android-security-14.0.0_r14 (cherry-pick of 02c5b768..., Change-Id I8879900e...); at android-security-14.0.0_r29, 7/8 lines of the patched region are present.",
      "15": "same fix: platform/frameworks/base 7f83c671626f in android-security-15.0.0_r2, identical diff (same blob hashes 3409c29d3c2c..defbc1142adb); at android-security-15.0.0_r17, 7/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, 7/8 lines of the patched region are present."
     },
     "backport_notes": [
      "Single self-contained commit touching one file. It relies on getRootFromDocId, getPathFromDocId, RootInfo.rootId and ROOT_ID_PRIMARY_EMULATED already existing in ExternalStorageProvider (referenced but not added by the diff). The commits for 12/12L/13 are not included in the material.",
      "No 'Fix in fork' section was provided, so no per-file fork verdict can be reported."
     ],
     "confidence": "high",
     "unknowns": [
      "The name of the modified check method and the condition of its early 'return false' are not shown in the diff hunk.",
      "The concrete path form that bypassed the regex is not shown.",
      "How rootId is derived for non-primary volumes, and so whether \"/storage/\" + rootId is always the mount point.",
      "Which inputs cause Files.isSameFile to throw (and so be mapped to restricted) in this context.",
      "Whether getPathFromDocId could throw in the pre-fix code.",
      "Which of the 8 patched-region lines differs in the later security tags (7/8 present) and whether that difference is cosmetic.",
      "The commits used for Android 12, 12L and 13 are not included in the material."
     ],
     "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-49740": {
     "cve": "CVE-2024-49740",
     "summary": "Adds server-side enforcement in PhoneInterfaceManager so that only the visual voicemail package (default dialer, system dialer or carrier VVM app) can enable or disable the visual voicemail SMS filter. It also limits the size of VisualVoicemailSmsFilterSettings fields in the Builder: clientPrefix at most 256 chars, originatingNumbers at most 100 entries of at most 256 chars each.",
     "component": "platform/packages/services/Telephony (PhoneInterfaceManager, visual voicemail SMS filter) and platform/frameworks/base (android.telephony.VisualVoicemailSmsFilterSettings)",
     "weakness": "Missing authorization check combined with missing input size limits",
     "root_cause": "PhoneInterfaceManager.enableVisualVoicemailSmsFilter and disableVisualVoicemailSmsFilter only ran mAppOps.checkPackage(Binder.getCallingUid(), callingPackage). They then cleared the calling identity and called VisualVoicemailSmsFilterConfig to apply or remove the caller's filter settings. The API documentation requires the caller to be the default dialer, but the server side did not enforce this (per the commit message), so any package could set filter settings. In addition, VisualVoicemailSmsFilterSettings.Builder accepted a clientPrefix of any length and an originatingNumbers list of any size, with elements of any length. The bulletin classifies the result as a High severity DoS. The material does not show which resource is exhausted.",
     "fix_analysis": [
      "platform/frameworks/base ea3337c88a8c, telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java: adds hidden constants MAX_STRING_LENGTH = 256 and MAX_LIST_SIZE = 100. Builder.setClientPrefix now throws IllegalArgumentException if clientPrefix.length() > 256. Builder.setOriginatingNumbers now throws IllegalArgumentException if the list has more than 100 elements. It also loops over the list and throws IllegalArgumentException for any non-null element longer than 256 characters. Javadoc @throws entries are added for both setters.",
      "platform/packages/services/Telephony 095be0bb467e, src/com/android/phone/PhoneInterfaceManager.java:enableVisualVoicemailSmsFilter: inserts enforceVisualVoicemailPackage(callingPackage, subId) right after mAppOps.checkPackage and before Binder.clearCallingIdentity. Settings are applied only after the caller is verified as the default dialer, system dialer or carrier visual voicemail app (per the commit message).",
      "platform/packages/services/Telephony b2c88f00503a (follow-up, android-security-14.0.0_r18), src/com/android/phone/PhoneInterfaceManager.java:disableVisualVoicemailSmsFilter: inserts the same enforceVisualVoicemailPackage(callingPackage, subId) call after mAppOps.checkPackage. This closes the sibling path that the first Telephony commit left unguarded."
     ],
     "completeness": [
      "At android-security-14.0.0_r29, both mutating entry points (enableVisualVoicemailSmsFilter and disableVisualVoicemailSmsFilter) call enforceVisualVoicemailPackage (code context lines 4088 and 4101).",
      "The size limits are added only in the public Builder setters. The diff touches no other part of VisualVoicemailSmsFilterSettings. The class implements Parcelable, and the material does not show whether the Parcel-reading path goes through these setters. PhoneInterfaceManager.enableVisualVoicemailSmsFilter does not re-check field sizes in the code shown.",
      "setOriginatingNumbers skips null elements (num != null), so nulls are still accepted. The list-size error message prints MAX_STRING_LENGTH (256) instead of MAX_LIST_SIZE (100). This is cosmetic only.",
      "getVisualVoicemailSmsFilterSettings is unchanged and still calls only mAppOps.checkPackage."
     ],
     "behavior_changes": [
      "VisualVoicemailSmsFilterSettings.Builder.setClientPrefix throws IllegalArgumentException for prefixes longer than 256 characters. This is a public API behavior change, documented with @throws.",
      "VisualVoicemailSmsFilterSettings.Builder.setOriginatingNumbers throws IllegalArgumentException for lists with more than 100 entries or with an element longer than 256 characters.",
      "ITelephony.enableVisualVoicemailSmsFilter and disableVisualVoicemailSmsFilter now reject callers that are not the visual voicemail package, via enforceVisualVoicemailPackage. The material does not show the exception type or how it reaches the app."
     ],
     "preconditions": [
      "Before the fix, any app that can reach ITelephony.enableVisualVoicemailSmsFilter could set filter settings, for example through the public TelephonyManager.setVisualVoicemailSmsFilterSettings or enableVisualVoicemailSmsFilter, which pass mContext.getOpPackageName() (per index search). The only server-side check was that callingPackage matched the calling UID.",
      "TelephonyManager.setVisualVoicemailSmsFilterSettings is annotated @RequiresFeature(FEATURE_TELEPHONY_CALLING) (per index search)."
     ],
     "per_major": {
      "14": "same fix: frameworks/base ea3337c88a8c and Telephony 095be0bb467e landed in android-security-14.0.0_r16, and the disableVisualVoicemailSmsFilter follow-up b2c88f00503a in android-security-14.0.0_r18. At android-security-14.0.0_r29 all 5/5 lines of the patched region are present and both the enable and disable paths call enforceVisualVoicemailPackage.",
      "15": "same fix: frameworks/base bcb1316835dc (same diff as ea3337c88a8c) in android-security-15.0.0_r4. 8/8 lines of the patched region are present at android-security-15.0.0_r17.",
      "16": "not affected (not listed by the bulletin). The patched region is present 8/8 at android-security-16.0.0_r8.",
      "17": "not affected (not listed by the bulletin). The patched region is present 8/8 at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "This is a three-commit fix across two projects. The frameworks/base Builder limits do not depend on the Telephony changes. Both Telephony commits are needed: enable in 095be0bb467e and disable in b2c88f00503a. They rely on an existing enforceVisualVoicemailPackage(String, int) helper in PhoneInterfaceManager, whose definition the material does not show.",
      "In trees where enableVisualVoicemailSmsFilter has extra checks (the index shows an enforceTelephonyFeatureWithException call in one snapshot), place enforceVisualVoicemailPackage after mAppOps.checkPackage and before Binder.clearCallingIdentity."
     ],
     "confidence": "medium",
     "unknowns": [
      "The exact DoS mechanism (which resource is exhausted, or which process fails, when oversized or unauthorized settings are applied) is not shown.",
      "The implementation of enforceVisualVoicemailPackage and the exception it throws are not in the material.",
      "The material does not show whether the Parcel-reading path of VisualVoicemailSmsFilterSettings applies any length limits. The diff changes only the Builder.",
      "The material does not establish which public (non-security) Android 14 tags contain the fix. The index snapshot of enableVisualVoicemailSmsFilter labelled android-14.0.0_r75 lacks enforceVisualVoicemailPackage, but the index may be noisy."
     ],
     "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-2025-0078": {
     "cve": "CVE-2025-0078",
     "summary": "servicemanager now calls setRequestingSid(true) on its own ServiceManager object before it registers itself as the \"manager\" service, so the flags on the self-registered object match the special flags used for the context object.",
     "component": "platform/frameworks/native, cmds/servicemanager (binder service manager)",
     "weakness": "Missing security attribute on a binder object: the self-registered servicemanager binder did not have the requesting-SID flag that is used for the context object.",
     "root_cause": "In cmds/servicemanager/main.cpp main(), one ServiceManager instance (built with std::make_unique<Access>()) is registered as a normal service named \"manager\" through manager->addService(\"manager\", manager, ...). The same instance is then made the binder context object (setTheContextObject, becomeContextManager). The commit message says servicemanager has special flags set to become a context object, but these were not set when it registers as itself. Before the fix, setRequestingSid(true) was not called on the object before self-registration.",
     "fix_analysis": [
      "cmds/servicemanager/main.cpp:main(): one line is added, manager->setRequestingSid(true);. It comes right after sp<ServiceManager>::make(std::make_unique<Access>()) and before manager->addService(\"manager\", manager, ...), so the ServiceManager binder is marked as requesting the caller SID when it registers itself.",
      "The following context-manager setup (setTheContextObject, becomeContextManager) is unchanged."
     ],
     "completeness": [
      "The fix covers the single self-registration point in main(). The same ServiceManager instance is used for addService(\"manager\", ...) and for setTheContextObject.",
      "No change is made to the Access class or to how ServiceManager handles transactions that arrive without a SID. Whether such handling exists is not shown in the material.",
      "main() contains an #ifndef VENDORSERVICEMANAGER block, which suggests the same file is also built for vendorservicemanager. The build files are not in the material."
     ],
     "behavior_changes": [
      "The ServiceManager binder object is marked as requesting the caller SID from before its self-registration as \"manager\". The commit message says the change was tested by booting with harsher checks.",
      "No new error codes or API changes appear in the diff."
     ],
     "preconditions": [
      "unknown: the material does not show which callers reach servicemanager through the self-registered \"manager\" object, or how."
     ],
     "per_major": {
      "14": "same fix: commit 1114faa38da8 in android-security-14.0.0_r18 (cherry-pick of 5075f8244827), a one-line addition in cmds/servicemanager/main.cpp. 4/4 lines of the patched region are present at android-security-14.0.0_r29.",
      "15": "same fix: commit c32d4defe0f4 in android-security-15.0.0_r6, the same one-line addition. The surrounding context differs (a preceding disableBackgroundScheduling(true) line). 4/4 lines are present at android-security-15.0.0_r17.",
      "16": "not affected (not listed by the bulletin). The patched region is present at android-security-16.0.0_r8.",
      "17": "not affected (not listed by the bulletin). The patched region is present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Single-line, self-contained change: insert manager->setRequestingSid(true); between sp<ServiceManager>::make(...) and the addService(\"manager\", ...) call in main()."
     ],
     "confidence": "medium",
     "unknowns": [
      "How ServiceManager/Access behaves when a transaction arrives without a security context (whether checks fail closed, fall back, or are skipped) is not shown.",
      "The material does not describe the concrete EoP consequence behind the bulletin rating beyond what the commit message says.",
      "Where the context-object 'special flags' named in the commit message are applied is not shown in the diff or context.",
      "Which callers can reach servicemanager through the self-registered \"manager\" object is not shown."
     ],
     "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-2025-0079": {
     "cve": "CVE-2025-0079",
     "summary": "Adds an encryption requirement (BTA_SEC_ENCRYPT / BTM_SEC_OUT_ENCRYPT) next to the existing authentication requirement for the AVDTP and AVCTP L2CAP PSM registrations and outgoing connect requests in the Bluetooth stack.",
     "component": "platform/packages/modules/Bluetooth, system/stack (AVDTP and AVCTP L2CAP channel setup)",
     "weakness": "Missing encryption requirement on a security-sensitive link (the channel security level required only authentication, not encryption)",
     "root_cause": "AVCTP (control PSM AVCT_PSM and browsing PSM AVCT_BR_PSM) and AVDTP (AVDT_PSM) registered their PSMs with L2CAP and made outgoing connect requests with only BTA_SEC_AUTHENTICATE (BTM_SEC_OUT_AUTHENTICATE for the outgoing AVDTP request). No encryption flag was set, so the requested security level for these channels did not include encryption. On Android 14, L2CA_Register2 passes sec_level to BTM_SetSecurityLevel (system/stack/l2cap/l2c_api.cc, per index search), so the missing flag affected the registered security level for incoming connections as well as the outgoing requests.",
     "fix_analysis": [
      "system/stack/avct/avct_api.cc:AVCT_Register: adds uint16_t sec = BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT and passes it to both L2CA_Register2 calls (AVCT_PSM with avct_l2c_appl, and AVCT_BR_PSM with avct_l2c_br_appl).",
      "system/stack/avct/avct_lcb_act.cc:avct_lcb_chnl_open: the outgoing L2CA_ConnectReq2 for AVCT_PSM now passes BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT.",
      "system/stack/avct/avct_bcb_act.cc:avct_bcb_chnl_open: the outgoing L2CA_ConnectReq2 for AVCT_BR_PSM (browsing channel) now passes BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT.",
      "system/stack/avdt/avdt_api.cc:AVDT_Register: adds uint16_t sec = BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT and passes it to L2CA_Register2 for AVDT_PSM.",
      "system/stack/avdt/avdt_ad.cc:avdt_ad_open_req: the outgoing L2CA_ConnectReq2 for AVDT_PSM, which handles both signaling and media channel types in the initiator role, now passes BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT.",
      "No new error handling is added. The existing failure paths (lcid == 0 leads to AVCT_LCB_LL_CLOSE_EVT or avdt_ad_tc_close_ind) handle connect request failures as before."
     ],
     "completeness": [
      "Covers all three PSMs used by AVDTP/AVCTP (AVDT_PSM, AVCT_PSM, AVCT_BR_PSM) on both the acceptor side (PSM registration) and the initiator side (connect requests). This is six call sites in five files.",
      "avdt_ad_open_req has one L2CA_ConnectReq2 call shared by signaling and media channel types, so this one change covers both.",
      "The fix only changes the requested security level. It adds no runtime checks in the AVDTP/AVCTP data paths that the link is encrypted, and relies on the L2CAP/BTM security layer to enforce the flags.",
      "Security levels of other Bluetooth profiles' PSM registrations are outside this commit, and the material does not show them.",
      "The commit message lists only 'mmm packages/modules/Bluetooth' as the test. No functional test is included."
     ],
     "behavior_changes": [
      "AVDTP (A2DP) and AVCTP (AVRCP control and browsing) L2CAP channels now request encryption as well as authentication, both in the PSM registration (passed to BTM_SetSecurityLevel via L2CA_Register2, per index search) and in outgoing connect requests.",
      "Expected effect: peers that cannot meet the encryption requirement may no longer be able to set up these channels. The material does not show the enforcement behavior."
     ],
     "preconditions": [
      "Bluetooth enabled with the AVDTP/AVCTP PSMs registered (AVDT_Register / AVCT_Register called).",
      "A remote Classic Bluetooth device setting up or accepting AVDTP or AVCTP L2CAP channels with the device.",
      "The material does not show the exact trigger conditions beyond the missing encryption requirement."
     ],
     "per_major": {
      "14": "same fix: commit 6893799a69f2 in android-security-14.0.0_r18 (security-branch backport of b/345258562, Ignore-AOSP-First), using the L2CA_Register2 / L2CA_ConnectReq2 APIs. 7/8 lines of the patched region present at android-security-14.0.0_r29.",
      "15": "adapted fix: commit b1e6d8d1e393 in android-security-15.0.0_r6. Same six call sites, but on the L2CA_RegisterWithSecurity / L2CA_ConnectReqWithSecurity APIs (the log::error on registration failure already existed). 7/8 lines of the patched region present at android-security-15.0.0_r17.",
      "16": "not affected per the bulletin (not listed). 5/8 lines of the patched region present at android-security-16.0.0_r8. The material does not show whether the encryption flags are present.",
      "17": "not affected per the bulletin (not listed). 5/8 lines of the patched region present at android-security-17.0.0_r1. The material does not show whether the encryption flags are present."
     },
     "backport_notes": [
      "One commit per branch. On a tree with different L2CAP API names (L2CA_Register2/L2CA_ConnectReq2 on 14, L2CA_RegisterWithSecurity/L2CA_ConnectReqWithSecurity on 15), only the sec_level argument at the six call sites needs the ENCRYPT flag OR-ed in. avdt_ad_open_req uses BTM_SEC_OUT_* constants while the other sites use BTA_SEC_* constants, so keep each site's constant family.",
      "Test mocks in system/test/mock/mock_stack_l2cap_api.cc pass sec_level through unchanged (per index search)."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show the concrete attack scenario or what elevated privilege results from an unencrypted AVDTP/AVCTP link. The bulletin only rates it High EoP.",
      "The material does not show the numeric values of BTA_SEC_ENCRYPT and BTM_SEC_OUT_ENCRYPT or whether they are equivalent.",
      "The material does not show how BTM enforces the new encryption level, for example whether connections fail or encryption is started on demand.",
      "The material does not show when AVDT_Register / AVCT_Register are called.",
      "Whether Android 16/17 code carries the encryption flags (only partial line matches are reported).",
      "The original change for b/345258562 (d7ff46bc6dc9) is not included. Only the security-branch backports are shown."
     ],
     "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-2025-0082": {
     "cve": "CVE-2025-0082",
     "summary": "Replaces the Uri.getEncodedUserInfo()-based cross-user icon check in telecom StatusHints and TelecomServiceImpl (phone account registration) with a new StatusHints.getUserIdFromAuthority() helper that derives the user id from the URI authority (getAuthority()) and rejects any mismatch or unparsable user id.",
     "component": "platform/frameworks/base (telecomm/java/android/telecom/StatusHints.java) and platform/packages/services/Telecomm (TelecomServiceImpl), Telecom icon URI validation",
     "weakness": "Improper input validation / authorization bypass: user-id boundary check parsed the URI with the wrong accessor (encoded user-info), so a percent-encoded '@' in the authority defeated the check",
     "root_cause": "Both StatusHints (icon validation returning the icon or null) and TelecomServiceImpl (icon validation when registering a phone account) decided whether a TYPE_URI / TYPE_URI_ADAPTIVE_BITMAP icon belonged to the calling user by calling icon.getUri().getEncodedUserInfo(). If that returned null the code assumed the URI targeted the calling user's space and accepted it. Per the commit message and the new tests, an authority written with a percent-encoded separator (e.g. encodedAuthority \"10%40media\" or \"content://10%40play.ground\") is not parsed properly by that accessor, so the user id embedded in the authority was not compared against the caller and an icon URI naming another user passed validation. The old code also called Integer.parseInt on the user-info without catching NumberFormatException.",
     "fix_analysis": [
      "platform/frameworks/base 24e31767630f, telecomm/java/android/telecom/StatusHints.java: adds a public static @hide helper getUserIdFromAuthority(String auth, int defaultUserId). It returns defaultUserId when auth is null or contains no '@'; otherwise it takes the substring before the last '@' and Integer.parseInt()s it; on NumberFormatException it logs a warning and returns UserHandle.USER_NULL. It is called on icon.getUri().getAuthority() rather than the encoded user-info.",
      "Same commit, StatusHints.java icon validation (the method that returns the icon or null, around line 150): for TYPE_URI / TYPE_URI_ADAPTIVE_BITMAP icons it now computes callingUserId = callingUserHandle.getIdentifier(), requestingUserId = getUserIdFromAuthority(icon.getUri().getAuthority(), callingUserId), and returns null (drops the icon) when they differ. Unparsable user ids map to USER_NULL and are therefore rejected rather than throwing.",
      "platform/packages/services/Telecomm e1a0858925cb, src/com/android/server/telecom/TelecomServiceImpl.java (icon check in phone account registration, around line 3150): imports android.telecom.StatusHints, replaces the getEncodedUserInfo() logic with callingUserId = UserHandle.getCallingUserId() and requestingUserId = StatusHints.getUserIdFromAuthority(icon.getUri().getAuthority(), callingUserId), and throws IllegalArgumentException(\"Attempting to register a phone account with an image icon belonging to another user.\") when they differ.",
      "Same Telecomm commit, tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java testRegisterPhoneAccountImageIconCrossUser: adds two negative cases using encodedAuthority(\"10%40media\") and Uri.parse(\"content://10%40play.ground\") that must fail registration, keeping the existing positive case content://0@media/... that must succeed."
     ],
     "completeness": [
      "Covers both sites named in the commit message: the StatusHints icon validation and the TelecomServiceImpl phone-account registration icon check; both now share one parser so behavior is consistent.",
      "The check still applies only to icons of type Icon.TYPE_URI or Icon.TYPE_URI_ADAPTIVE_BITMAP; other icon types are untouched.",
      "The parser uses lastIndexOf('@') on the authority, so everything before the last '@' is parsed; a non-numeric prefix yields USER_NULL and is rejected.",
      "A URI with no '@' in the authority is treated as belonging to the caller (defaultUserId), which matches the previous code's stated intent; whether any other code path accepts caller-supplied icon URIs without going through these two checks is not shown in the material."
     ],
     "behavior_changes": [
      "Phone account registration with a URI icon whose authority carries a different user id (including percent-encoded forms such as 10%40media) now throws IllegalArgumentException instead of being accepted.",
      "StatusHints drops (returns null for) a URI icon whose authority names another user, now also for percent-encoded forms.",
      "A URI icon whose user-id prefix is not an integer no longer causes an uncaught NumberFormatException; it is logged (TAG StatusHints) and treated as a user mismatch (rejected).",
      "TelecomServiceImpl now obtains the caller via UserHandle.getCallingUserId() instead of UserHandle.getUserId(Binder.getCallingUid())."
     ],
     "preconditions": [
      "Caller supplies an Icon of type TYPE_URI or TYPE_URI_ADAPTIVE_BITMAP, either in a PhoneAccount passed to TelecomServiceImpl registerPhoneAccount (the test calls the binder registerPhoneAccount with MODIFY_PHONE_STATE granted; whether that permission gates this path is not shown) or in a StatusHints object processed by the StatusHints validation method.",
      "The icon URI authority encodes a user id other than the caller's, e.g. using a percent-encoded '@' separator."
     ],
     "per_major": {
      "14": "same fix: resolved via bug_id in android-security-14.0.0_r18 with both commits (frameworks/base 24e31767630f, Telecomm e1a0858925cb); at android-security-14.0.0_r29 the patched region is fully present (8/8 lines) and StatusHints.java contains the new TAG/Log import.",
      "15": "same fix: resolved in android-security-15.0.0_r6 via Telecomm 685c2fc2f6b4, whose diff matches the 14 one apart from line offsets (hunk at TelecomServiceImpl line ~3421, test at ~1090); 8/8 lines present at android-security-15.0.0_r17. The corresponding frameworks/base commit for 15 is not shown in the material, though the Telecomm code depends on StatusHints.getUserIdFromAuthority.",
      "16": "not affected per the bulletin (not listed); the patched region is fully present (8/8 lines) at android-security-16.0.0_r8.",
      "17": "not affected per the bulletin; at android-security-17.0.0_r1 the patched file telecomm/java/android/telecom/StatusHints.java is absent at that path; the material does not show where (or whether) the code lives now."
     },
     "backport_notes": [
      "Two-repository dependency: the Telecomm change calls the new public static StatusHints.getUserIdFromAuthority() in frameworks/base, so the frameworks/base commit must be applied first or in the same build. No feature flag is involved (Flag: EXEMPT bugfix)."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact names of the two patched validation methods (the diff hunks do not include the method signatures).",
      "Whether the frameworks/base StatusHints commit was also applied to the Android 15 and 16 security branches (only the Telecomm commit is listed for 15; 16 shows the patched region present).",
      "Where the StatusHints code lives in Android 17 after the file disappeared from telecomm/java/android/telecom/.",
      "What permission, if any, gates the registerPhoneAccount icon path for third-party callers (the test grants MODIFY_PHONE_STATE but the production check is not shown).",
      "What device user/profile configuration is needed for a foreign-user icon URI to resolve to content.",
      "What exactly was disclosed (the bulletin only rates it High / ID)."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 2,
      "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-2025-0083": {
     "cve": "CVE-2025-0083",
     "summary": "Replaces the Uri.getEncodedUserInfo()-based cross-user check on content-URI icons in StatusHints and in TelecomServiceImpl (phone account registration) with a new StatusHints.getUserIdFromAuthority() helper. The helper parses the user id from Uri.getAuthority() and rejects any icon whose user id differs from the caller's, including the percent-encoded test forms and non-numeric prefixes.",
     "component": "platform/frameworks/base (telecomm/java/android/telecom/StatusHints.java) and platform/packages/services/Telecomm (TelecomServiceImpl phone account icon validation)",
     "weakness": "Bypass of a cross-user check on icon URIs because the user id was parsed inconsistently (Uri.getEncodedUserInfo() did not catch some URI forms)",
     "root_cause": "StatusHints (icon validation near line 150) and TelecomServiceImpl (icon check during phone account registration, near line 3150) both took the target user id of a TYPE_URI / TYPE_URI_ADAPTIVE_BITMAP icon from icon.getUri().getEncodedUserInfo(). When that value was null, the code assumed the URI pointed at the calling user and accepted the icon. Per the commit message, a URI formatted as `userId%` is not parsed properly this way, so the cross-user check could be bypassed. The new tests use authorities '10%40media' and '10%40play.ground'. The old code also called Integer.parseInt(encodedUser) without handling NumberFormatException.",
     "fix_analysis": [
      "platform/frameworks/base 24e31767630f, StatusHints.java: adds a @hide public static helper getUserIdFromAuthority(String auth, int defaultUserId). It returns defaultUserId when auth is null or contains no '@'. Otherwise it Integer.parseInt()s the substring before lastIndexOf('@'). A NumberFormatException is caught and logged with Log.w, and UserHandle.USER_NULL is returned.",
      "Same commit, StatusHints icon validation: for TYPE_URI / TYPE_URI_ADAPTIVE_BITMAP icons it computes requestingUserId = getUserIdFromAuthority(icon.getUri().getAuthority(), callingUserId). It returns null (drops the icon) whenever callingUserId != requestingUserId.",
      "platform/packages/services/Telecomm e1a0858925cb, TelecomServiceImpl.java: imports android.telecom.StatusHints and replaces the getEncodedUserInfo()/parseInt block with callingUserId = UserHandle.getCallingUserId() and requestingUserId = StatusHints.getUserIdFromAuthority(icon.getUri().getAuthority(), callingUserId). If the two differ, it throws IllegalArgumentException(\"Attempting to register a phone account with an image icon belonging to another user.\").",
      "Same Telecomm commit, TelecomServiceImplTest.testRegisterPhoneAccountImageIconCrossUser: adds two negative cases, encodedAuthority(\"10%40media\") and Uri.parse(\"content://10%40play.ground\"), both expected to be rejected, while \"content://0@media/...\" still succeeds."
     ],
     "completeness": [
      "Both validation sites named in the commit message (StatusHints and TelecomServiceImpl phone account registration) are updated and share one helper.",
      "A non-numeric prefix before '@' now yields USER_NULL and is rejected instead of throwing an uncaught NumberFormatException.",
      "The check still applies only to Icon.TYPE_URI and Icon.TYPE_URI_ADAPTIVE_BITMAP, as before.",
      "An authority with no '@' is treated as the calling user (defaultUserId), similar to the old behaviour when no user info was present.",
      "The material does not show whether other Telecom entry points accept content-URI icons without going through one of these two sites."
     ],
     "behavior_changes": [
      "Registering a phone account with an icon whose authority names a user id different from the caller's (including the percent-encoded test forms) now throws IllegalArgumentException.",
      "Icons whose authority prefix before '@' is not an integer are now rejected: StatusHints drops the icon and logs a warning, and TelecomServiceImpl throws IllegalArgumentException. Previously both paths threw NumberFormatException.",
      "TelecomServiceImpl now gets the caller's user id from UserHandle.getCallingUserId() instead of UserHandle.getUserId(Binder.getCallingUid()).",
      "StatusHints gains a new @hide public static method getUserIdFromAuthority(String, int), which Telecomm depends on."
     ],
     "preconditions": [
      "A caller passes a PhoneAccount with an Icon of type TYPE_URI or TYPE_URI_ADAPTIVE_BITMAP to registerPhoneAccount (the test calls mTSIBinder.registerPhoneAccount), or StatusHints carrying such an icon reach the StatusHints validation.",
      "The icon URI's authority names another user in a form that getEncodedUserInfo() did not catch (commit message: 'userId%' style; tests: '10%40media').",
      "The test stubs MODIFY_PHONE_STATE as granted. The material does not show whether the real path requires it."
     ],
     "per_major": {
      "14": "same fix: resolved in android-security-14.0.0_r18 via frameworks/base 24e31767630f (StatusHints.java) and Telecomm e1a0858925cb (TelecomServiceImpl.java plus test). At android-security-14.0.0_r29, 8/8 lines of the patched region are present.",
      "15": "same fix: resolved in android-security-15.0.0_r6 via Telecomm 685c2fc2f6b4, with the same Telecomm diff at different line offsets (hunk @@ -3421). At android-security-15.0.0_r17, 8/8 lines are present. The matching frameworks/base commit for 15 is not shown in the material.",
      "16": "not affected (not listed by the bulletin). At android-security-16.0.0_r8, 8/8 lines of the patched region are present.",
      "17": "not affected (not listed by the bulletin). At android-security-17.0.0_r1 the patched file telecomm/java/android/telecom/StatusHints.java is absent."
     },
     "backport_notes": [
      "Apply the frameworks/base StatusHints.java change first. The Telecomm change calls the new @hide StatusHints.getUserIdFromAuthority() and will not build without it (Telecomm is a platform app built against framework internals, general platform knowledge).",
      "The Telecomm hunk is the same on 14 and 15 apart from line offsets. Replace the whole getEncodedUserInfo()/parseInt block, and carry over the two new test cases in testRegisterPhoneAccountImageIconCrossUser."
     ],
     "confidence": "high",
     "unknowns": [
      "Names of the enclosing methods in StatusHints.java and TelecomServiceImpl.java (the hunk headers show only the class).",
      "Exactly how Uri.getEncodedUserInfo() handled the `userId%` forms before the fix.",
      "Whether the two patched sites are the only places Telecom accepts caller-supplied content-URI icons.",
      "The frameworks/base StatusHints commit for Android 15.",
      "Where, if anywhere, the StatusHints icon validation lives in Android 17 (file absent at android-security-17.0.0_r1).",
      "Exact permission requirements on the real registerPhoneAccount path."
     ],
     "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-2025-0086": {
     "cve": "CVE-2025-0086",
     "summary": "Adds a check in AccountManagerService's getAuthToken result handler that rejects an authenticator response whose KEY_ACCOUNT_TYPE differs from the session's account type, returning ERROR_CODE_INVALID_RESPONSE instead of storing the token.",
     "component": "platform/frameworks/base, services/core AccountManagerService (accounts)",
     "weakness": "Missing validation of authenticator-supplied account type in a result Bundle (improper input validation)",
     "root_cause": "In AccountManagerService.java, the getAuthToken Session's onResult(Bundle result) built an Account from the KEY_ACCOUNT_NAME and KEY_ACCOUNT_TYPE strings returned by the AbstractAccountAuthenticator. When customTokens was false, it passed that resultAccount to saveAuthTokenToDatabase. The only validation was that name and type were non-empty. The commit message says the service already knows which account getAuthToken is called for, but the code did not check that the returned type matched the session's mAccountType. As a result, the authenticator could have an auth token recorded under an account of a different type.",
     "fix_analysis": [
      "services/core/java/com/android/server/accounts/AccountManagerService.java, getAuthToken Session.onResult: after the existing TextUtils.isEmpty(type) || TextUtils.isEmpty(name) check and before `Account resultAccount = new Account(name, type)`, the fix adds `if (!type.equals(mAccountType)) { onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, \"incorrect account type\"); return; }`.",
      "The check comes before both the `!customTokens` saveAuthTokenToDatabase(mAccounts, resultAccount, ...) call and the customTokens saveCachedToken path. A mismatched type therefore ends result handling and nothing is persisted or cached.",
      "Single commit, 6 added lines, no other files touched. The commit message says the response keys look unnecessary but the API cannot change at this moment, so a validation check was added."
     ],
     "completeness": [
      "Covers only the getAuthToken Session.onResult path in AccountManagerService. The type returned by the authenticator is compared to mAccountType.",
      "KEY_ACCOUNT_NAME returned by the authenticator is still accepted as-is. The fix does not compare `name` to the requested account's name, so resultAccount can still carry a name chosen by the authenticator, as long as the type is correct.",
      "Other authenticator callbacks that also return KEY_ACCOUNT_NAME/KEY_ACCOUNT_TYPE are not part of this diff. The material does not show whether they already validate the type.",
      "The customTokens branch passes the original `account` to saveCachedToken, so it did not rely on the authenticator-supplied type. The new check still gates that branch."
     ],
     "behavior_changes": [
      "A getAuthToken response whose KEY_ACCOUNT_TYPE does not equal the session's account type now fails with AccountManager.ERROR_CODE_INVALID_RESPONSE and the message \"incorrect account type\" instead of succeeding.",
      "In that case no token is written to the database or cached."
     ],
     "preconditions": [
      "An AbstractAccountAuthenticator must be invoked through AccountManagerService getAuthToken. The Session calls mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions) at line 3186 of the r29 context.",
      "The authenticator's result Bundle must contain KEY_AUTHTOKEN plus non-empty KEY_ACCOUNT_NAME and KEY_ACCOUNT_TYPE. The KEY_AUTH_TOKEN_LABEL branch is checked first and is not affected.",
      "The authenticator-supplied type was used on the non-customTokens path (saveAuthTokenToDatabase with resultAccount)."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/base b6dcda18039c in android-security-14.0.0_r18 (cherry-picked from ab3a6b9e5ced, Change-Id Ifc62866f4feaca43abc32bc542b97f3741953f56). All 4 lines of the patched region are present at android-security-14.0.0_r29 (hunk at about line 3124, context now at line 3217).",
      "15": "same fix: platform/frameworks/base c1aa9e662464 in android-security-15.0.0_r6, with an identical 6-line hunk at about line 3190. All 4 lines are present at android-security-15.0.0_r17.",
      "16": "not affected (not listed by the bulletin). All 4 lines of the patched region are present at android-security-16.0.0_r8.",
      "17": "not affected (not listed by the bulletin). All 4 lines of the patched region are present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Single self-contained hunk with no dependencies. Apply it inside the getAuthToken Session.onResult block right after the empty name/type check, using the existing mAccountType field. The bulletin lists Android 12, 12L and 13 as affected, but the material contains no commit for them."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show the fix commits for Android 12, 12L and 13, which the bulletin lists as affected.",
      "The material does not show what concrete information disclosure results from a token stored under the wrong account type. The bulletin only rates it High / ID.",
      "No automated test is shown with the change (Test: manual)."
     ],
     "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-2025-0092": {
     "cve": "CVE-2025-0092",
     "summary": "The fix resets a remote device's Message Access, Phonebook Access and SIM Access permissions to ACCESS_UNKNOWN whenever its bond state transitions to BOND_NONE, so that access granted while a device was bonded does not survive unbonding.",
     "component": "platform/packages/modules/Bluetooth, btservice (BondStateMachine / AdapterService bond-state handling; affects MAP, PBAP and SAP access permissions)",
     "weakness": "Missing revocation of per-device authorization on trust-state change (stale MAP/PBAP/SIM access permissions retained after unbond)",
     "root_cause": "In BondStateMachine's bond-state intent path (sendIntent, per the in-file comment), when a device's bond state changed to BOND_NONE, the code broadcast ACTION_BOND_STATE_CHANGED and notified AdapterService. It never cleared the per-device message, phonebook and SIM access permission values held by AdapterService, so those permissions persisted for a device that was no longer bonded. The commit message cites two spec requirements: PBAP requires the user to confirm at least the first PBAP connection from each new PCE, and MAP requires the MCE and MSE to be bonded before a MAP connection is set up.",
     "fix_analysis": [
      "android/app/src/com/android/bluetooth/btservice/BondStateMachine.java:sendIntent (Android 14): the fix adds an `if (newState == BluetoothDevice.BOND_NONE)` block after the pending-SDP handling block and before the ACTION_BOND_STATE_CHANGED intent is built. The block calls mAdapterService.setMessageAccessPermission, setPhonebookAccessPermission and setSimAccessPermission with BluetoothDevice.ACCESS_UNKNOWN for the device.",
      "The new block sits before mAdapterService.onBondStateChanged(device, newState) and before the broadcast, so the permissions are already reset when those run.",
      "Android 15 (090ca53cc13c): the same three reset calls are placed in AdapterService.java instead, in the bond-state handling method that calls mDatabaseManager.handleBondStateChanged(device, fromState, toState). They are guarded by `toState == BOND_NONE`, and the commit adds a static import of BluetoothDevice.BOND_NONE."
     ],
     "completeness": [
      "The fix covers all three per-device access permissions (message, phonebook, SIM). It covers every transition to BOND_NONE that goes through this BondStateMachine path, whatever the old state, so it includes failed pairings (BONDING -> NONE) and explicit unbonds (BONDED -> NONE).",
      "The reset only happens on a transition event. The diff contains no one-time cleanup of permissions already stored for devices that were unbonded before the fix was installed.",
      "On Android 14 the hook is inside BondStateMachine.sendIntent, so a bond-state change that bypasses this path would not trigger the reset; the material shows no such path. Android 15 places the hook in AdapterService instead."
     ],
     "behavior_changes": [
      "After a device is unbonded or a pairing attempt fails, its MAP, PBAP and SAP access permissions are set to ACCESS_UNKNOWN.",
      "Three additional set*AccessPermission calls run on every BOND_NONE transition, before the ACTION_BOND_STATE_CHANGED broadcast (Android 14)."
     ],
     "preconditions": [
      "A remote device must previously have had a non-UNKNOWN message, phonebook or SIM access permission set on the local AdapterService.",
      "The device's bond state then transitions to BOND_NONE (unbond or failed pairing).",
      "The material does not detail the later MAP/PBAP/SAP connection path that would use the stale permission."
     ],
     "per_major": {
      "14": "same fix: 142acc56658c in android-security-14.0.0_r17 adds the BOND_NONE reset block in BondStateMachine.sendIntent; 3/3 patched lines present at android-security-14.0.0_r29.",
      "15": "adapted fix: 090ca53cc13c in android-security-15.0.0_r5 places the same three reset calls in AdapterService (toState == BOND_NONE) and adds a BOND_NONE static import; 8/8 lines present at android-security-15.0.0_r17.",
      "16": "not affected (not listed by the bulletin); the patched region is present (3/3) at android-security-16.0.0_r8.",
      "17": "not affected (not listed by the bulletin); the patched region is present (3/3) at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "The Android 14 commit message says it is a backport of ag/30386015 with minor logic changes. On 14 the reset lives in BondStateMachine.sendIntent and calls through mAdapterService. On 15 it lives in AdapterService's bond-state handler next to mDatabaseManager.handleBondStateChanged. When porting, use whichever of the two hook points exists in your tree.",
      "Bluetooth is a mainline (APEX) module on these releases, so the fix may arrive through a module update and not only through the platform security tag (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "Whether the set*AccessPermission values are persisted across reboots, and whether stale pre-fix entries are cleaned up elsewhere; the material shows no such cleanup.",
      "The exact MAP/PBAP/SAP connection-acceptance code that used the stale permission; only the spec requirements quoted in the commit message are provided.",
      "Whether the Android 15 hook method is named handleBondStateChanged; the diff hunk header shows only the class, not the enclosing method.",
      "The Android 14 enclosing method name sendIntent is inferred from an in-file comment; the code excerpt does not show the method signature.",
      "Whether ag/30386015 corresponds to the Android 15 commit 090ca53cc13c."
     ],
     "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-2025-0093": {
     "cve": "CVE-2025-0093",
     "summary": "When a device's bond state changes to BOND_NONE, the Bluetooth stack now resets that device's Message Access (MAP), Phonebook Access (PBAP) and SIM Access permissions to ACCESS_UNKNOWN, so access granted earlier does not survive unbonding.",
     "component": "platform/packages/modules/Bluetooth, btservice (bond state handling in BondStateMachine / AdapterService, MAP/PBAP/SIM access permissions)",
     "weakness": "Stale authorization state: per-device profile access permissions were not revoked when the device was unbonded (missing permission reset on a state change)",
     "root_cause": "Nothing reset the per-device Message Access, Phonebook Access and SIM Access permissions (set through AdapterService.setMessageAccessPermission / setPhonebookAccessPermission / setSimAccessPermission) when a device's bond state changed to BOND_NONE. In android/app/src/com/android/bluetooth/btservice/BondStateMachine.java, the method that handles bond state changes and broadcasts ACTION_BOND_STATE_CHANGED (an in-file comment calls it sendIntent) updated the adapter properties and sent the intent, but left any earlier stored permission in place. So a device that was unbonded kept the MAP/PBAP/SIM access it had been granted before. This conflicts with the PBAP requirement, quoted in the commit message, that the user confirm at least the first connection from each new PCE, and with the MAP requirement that the MCE and MSE be bonded.",
     "fix_analysis": [
      "android/app/src/com/android/bluetooth/btservice/BondStateMachine.java (the bond-state intent method; the in-file comment calls it sendIntent): a new block is added after the BONDED/pending-UUID handling and before the ACTION_BOND_STATE_CHANGED intent is built. It checks `if (newState == BluetoothDevice.BOND_NONE)` and calls mAdapterService.setMessageAccessPermission, setPhonebookAccessPermission and setSimAccessPermission with BluetoothDevice.ACCESS_UNKNOWN.",
      "The reset runs before mAdapterService.onBondStateChanged(device, newState) and before the broadcast.",
      "The block comes after the early `return` (line 472 at android-security-14.0.0_r29). That return is only reached when newState == BOND_BONDED with UUIDs still pending, so every BOND_NONE transition that reaches this method performs the reset.",
      "Android 15 (AdapterService.java): the same three setters are called, unqualified, when `toState == BOND_NONE`. They are placed after mDatabaseManager.handleBondStateChanged(device, fromState, toState), and a static import of BluetoothDevice.BOND_NONE is added. The Android 14 commit message says it is a backport of ag/30386015 that needed minor logic changes."
     ],
     "completeness": [
      "Covers all three profile access permissions (message, phonebook, SIM) for any device whose bond state becomes BOND_NONE through the patched path (BondStateMachine on Android 14, AdapterService bond-state handling on Android 15).",
      "Only acts on a BOND_NONE transition. The material does not show how permissions are handled for devices that were never bonded.",
      "Devices that were already unbonded before the update are not cleared retroactively. The material shows no migration or startup cleanup of existing permission entries.",
      "The fix depends on every BOND_NONE transition passing through the patched method. The material does not show whether other paths exist."
     ],
     "behavior_changes": [
      "After unbonding, the stored message, phonebook and SIM access permissions for that device are set to ACCESS_UNKNOWN instead of keeping their earlier value.",
      "The three setter calls now run on every BOND_NONE transition, including for devices that never had a permission stored."
     ],
     "preconditions": [
      "A remote device was bonded with the Android device and had MAP, PBAP or SIM access permission stored.",
      "The bond is removed (the bond state changes to BOND_NONE). Before the fix, the stored permission was not reset at this point.",
      "Bluetooth is enabled. The code runs in the Bluetooth app (BondStateMachine bond-state handling, fed by bondStateChangeCallback)."
     ],
     "per_major": {
      "14": "Adapted fix (commit 142acc56658c in android-security-14.0.0_r17): the reset is placed in the bond-state intent method of BondStateMachine.java and uses mAdapterService.set*AccessPermission. At android-security-14.0.0_r29, 3/3 patched lines are present. The commit message says it is a backport of ag/30386015 with minor logic changes.",
      "15": "Fixed (commit 090ca53cc13c in android-security-15.0.0_r5): the reset is placed in AdapterService.java after mDatabaseManager.handleBondStateChanged, plus a static import of BOND_NONE. At android-security-15.0.0_r17, 8/8 patched lines are present.",
      "16": "Not affected (not listed by the bulletin). The patched region (3/3 lines) is present at android-security-16.0.0_r8.",
      "17": "Not affected (not listed by the bulletin). The patched region (3/3 lines) is present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "The fix is small and self-contained: 7 added lines on 14, 8 on 15, and it only calls existing AdapterService setters. On 14-style trees, add the BOND_NONE check in BondStateMachine's bond-state intent method before mAdapterService.onBondStateChanged and the broadcast. On 15-style trees, add it in AdapterService after mDatabaseManager.handleBondStateChanged."
     ],
     "confidence": "high",
     "unknowns": [
      "The hunk headers do not show the exact method names in BondStateMachine.java and AdapterService.java. The in-file comment at lines 502-503 calls the BondStateMachine method sendIntent.",
      "The material does not show whether the access permissions are persisted to storage.",
      "The material does not show whether any bond-removal path bypasses the patched method.",
      "The material does not show the user-visible behaviour on the next MAP/PBAP/SIM connection after the reset (for example, whether the user is prompted again).",
      "Whether the Android 15 commit is the original change ag/30386015, and what that change contains, is not provided."
     ],
     "meta": {
      "generated": "2026-10-04",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 9,
      "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-2025-26417": {
     "cve": "CVE-2025-26417",
     "summary": "Adds an ownership check to DownloadProvider's insert destination-path validation: if MediaStore already has a record for the target file path, the calling UID must own a package equal to that record's OWNER_PACKAGE_NAME, otherwise a SecurityException is thrown.",
     "component": "platform/packages/providers/DownloadProvider, DownloadProvider content provider (insert path / destination file validation)",
     "weakness": "Missing authorization (ownership) check on a caller-supplied destination file path",
     "root_cause": "In src/com/android/providers/downloads/DownloadProvider.java, the insert path validated a caller-supplied destination file via Helpers.checkDestinationFilePathRestrictions (with allowDownloadsDirOnly=true). It did not check whether the target file already existed as a MediaStore record owned by another package. Per the commit message, this let an app access any file in Downloads through the insert method, whichever package owned it. The bulletin classifies this as information disclosure.",
     "fix_analysis": [
      "DownloadProvider.java, destination-check method around line 1120 (the one calling Helpers.checkDestinationFilePathRestrictions with allowDownloadsDirOnly=true): after the existing restriction check, a new call checkWhetherCallingAppHasAccess(file.getPath(), Binder.getCallingUid()) is added.",
      "DownloadProvider.java:checkWhetherCallingAppHasAccess (new private method): acquires a ContentProviderClient for MediaStore.AUTHORITY, builds the files URI with Helpers.getContentUriForPath(getContext(), filePath) wrapped in MediaStore.setIncludePending so pending rows are included, then queries _ID and OWNER_PACKAGE_NAME with selection DATA=? bound to filePath.",
      "If a row is found and its OWNER_PACKAGE_NAME is non-null, the method gets getPackageManager().getPackagesForUid(uid) for the calling UID and requires that list to contain the owner package name. If it does not, the method throws SecurityException(\"Caller does not have access to this path\"), which aborts the insert.",
      "Adds import java.util.Arrays for the Arrays.asList membership test."
     ],
     "completeness": [
      "Covers only the insert destination-path validation that calls Helpers.checkDestinationFilePathRestrictions. The diff changes no other DownloadProvider entry points.",
      "Fail-open behavior: if the MediaStore ContentProviderClient cannot be acquired (client == null) or the query throws RemoteException, the method logs a warning and returns without denying the insert.",
      "If no MediaStore row matches DATA=filePath, the insert is allowed, so the check does not cover files in Downloads that MediaStore has not indexed.",
      "If the matching row's OWNER_PACKAGE_NAME is null, or getPackagesForUid returns null, the check is skipped and the insert proceeds.",
      "Authorization is by package name membership in the caller UID's package list, so any package sharing the caller's UID is treated as the owner.",
      "Matching is an exact string comparison of file.getPath() against the DATA column. The diff does not show whether the path is normalized before this check."
     ],
     "behavior_changes": [
      "Insert requests whose destination file already has a MediaStore record owned by a different package now fail with SecurityException(\"Caller does not have access to this path\").",
      "Each call to the destination check now runs an additional query to MediaStore (including pending rows).",
      "New warning logs under Constants.TAG when MediaStore cannot be acquired or queried. In those cases the old (unchecked) behavior remains."
     ],
     "preconditions": [
      "Caller invokes DownloadProvider insert with a destination file path that reaches the destination check (the code calling Helpers.checkDestinationFilePathRestrictions with allowDownloadsDirOnly=true).",
      "To be denied after the fix: MediaStore has a record (including pending) whose DATA equals the destination path and whose OWNER_PACKAGE_NAME is a package not belonging to the calling UID.",
      "MediaProvider must be reachable from DownloadProvider. If it is not, the new check is bypassed (fail-open)."
     ],
     "per_major": {
      "14": "same fix: commit d37a58ed0acb in android-security-14.0.0_r18; all 8/8 patched-region lines present at android-security-14.0.0_r29.",
      "15": "same fix: commit ed764e06106a in android-security-15.0.0_r6, identical diff (same blob indices 77fe8832..7ae06574); 8/8 lines present at android-security-15.0.0_r17.",
      "16": "not affected (the bulletin does not list it); patched code present (8/8 lines) at android-security-16.0.0_r8.",
      "17": "not affected (the bulletin does not list it); patched code present (8/8 lines) at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Single-commit, additive change, identical on 14 and 15. It depends on Helpers.getContentUriForPath, Constants.TAG and the existing Helpers.checkDestinationFilePathRestrictions call site. For older branches (12/12L/13, listed by the bulletin), verify that those helpers exist and that the Downloads-dir-only destination check is the right place to add the call.",
      "MediaStore.setIncludePending and OWNER_PACKAGE_NAME are public MediaStore APIs available since Android 10 (general platform knowledge), so no framework change should be needed."
     ],
     "confidence": "high",
     "unknowns": [
      "The name of the enclosing method at line ~1120 and how insert() reaches it are not shown in the provided hunk.",
      "Whether the destination path is canonicalized before this check is not visible in the material.",
      "The commit message describes the exact disclosure mechanism only at a high level.",
      "Whether Android 12/12L/13 received an adapted commit is 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."
     }
    }
   }
  },
  "15": {
   "counts": {
    "announced": 26,
    "certain": 26,
    "probable": 0,
    "not_published": 0,
    "not_covered": 0,
    "awaiting": 0
   },
   "advisories": [
    {
     "cve": "CVE-2025-0074",
     "osv_id": "ASB-A-375408314",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "Critical",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Two log::warn statements in system/stack/sdp/sdp_discovery.cc read p_cmd->len / p_msg->len after a failed L2CA_DataWrite. They now log the locally computed length (p - p_start), so the buffer that may have been freed is no longer dereferenced.",
      "confidence": "high",
      "backport_notes": [
       "This is a single two-line commit with no dependencies shown. If your tree lacks this exact log::warn text, find every log statement that follows a failed L2CA_DataWrite in sdp_discovery.cc and replace reads of the sent buffer (p_cmd->len / p_msg->len) with the local length p - p_start."
      ],
      "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_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "37bcf769c1aa8dfa8e5524858d47f6a80b765fa4",
       "tag": "android-security-15.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-0075",
     "osv_id": "ASB-A-375407167",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "Critical",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "In system/stack/sdp/sdp_server.cc process_service_search_attr_req, the warning logged when L2CA_DataWrite fails no longer reads p_buf->len, because p_buf may already have been freed. It now computes the length from the local pointers p_rsp - p_rsp_start.",
      "confidence": "high",
      "backport_notes": [
       "This is a single one-line change. In trees with a different logging form, apply the same transformation: replace the read of p_buf after L2CA_DataWrite with p_rsp - p_rsp_start (or a length saved before the call). Bluetooth is a Mainline module (general platform knowledge)."
      ],
      "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_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "5959f8bcf4efe924b0ba4dbcbfe83e602f0eb0ac",
       "tag": "android-security-15.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-0081",
     "osv_id": "ASB-A-347735428",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "Critical",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a null check at the top of dng_lossless_decoder::HuffDecode in external/dng_sdk. A null HuffmanTable pointer now causes ThrowBadFormat () instead of being dereferenced.",
      "confidence": "medium",
      "backport_notes": [
       "The change is 4 self-contained lines in dng_lossless_decoder::HuffDecode. The bulletin lists 12, 12L and 13 as affected, but the material has no commit for those branches."
      ],
      "meta": {
       "generated": "2026-10-03",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 9,
       "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_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/external/dng_sdk",
       "sha": "7fc02c8d5af37c97b325dc2956f4a6117c145c2f",
       "tag": "android-security-15.0.0_r6",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/external/dng_sdk"
     ]
    },
    {
     "cve": "CVE-2025-0084",
     "osv_id": "ASB-A-291281168",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "Critical",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds a guard in bta_hf_client_do_disc that aborts discovery when the HF client control block already holds a discovery database, and a NULL check on p_ccb->p_db in process_service_search_attr_rsp that disconnects the SDP connection instead of using an absent database.",
      "confidence": "high",
      "backport_notes": [
       "Single commit with two independent hunks. Only the logging macros differ between 14 (APPL_TRACE_ERROR / SDP_TRACE_WARNING) and 15 (log::error / log::warn). The code does not reference the flag named in the commit message, so no aconfig flag plumbing is needed.",
       "Bluetooth is a mainline module, so devices may receive fixes through module updates rather than the platform tag (general platform knowledge)."
      ],
      "meta": {
       "generated": "2026-10-03",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 2,
       "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_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "94c565214e3496fbaade9efed8be41d6425ba21e",
       "tag": "android-security-15.0.0_r6",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-22403",
     "osv_id": "ASB-A-375409435",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "Critical",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Replaces two log::warn arguments in system/stack/sdp/sdp_discovery.cc. They read p_cmd->len / p_msg->len after the buffer had been passed to L2CA_DataWrite, which per the commit message may have freed it in exceptional cases. The fix logs the locally computed length p - p_start instead.",
      "confidence": "high",
      "backport_notes": [
       "Trivial 2-line change with no dependencies. Where the surrounding logging code differs, apply the same principle: log a length computed from p and p_start, and do not read p_cmd/p_msg after L2CA_DataWrite."
      ],
      "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_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "37bcf769c1aa8dfa8e5524858d47f6a80b765fa4",
       "tag": "android-security-15.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-22408",
     "osv_id": "ASB-A-375397164",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "Critical",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Across nine L2CAP send sites in eight Bluetooth stack files (AVCTP, BNEP, HID device, RFCOMM, SDP client and server), the failure-path log::warn no longer reads ->len from the BT_HDR buffer after L2CA_DataWrite. The length is now saved in a local before the call, or taken from the pointer difference already computed for it.",
      "confidence": "medium",
      "backport_notes": [
       "The change is self-contained and mechanical. Per index search, android-15.0.0_r36 calls stack::l2cap::get_interface().L2CA_DataWrite(...) and compares against tL2CAP_DW_RESULT::SUCCESS (seen in bnepu_check_send_packet, with the local len capture already in place). On code with that form, apply the same local-variable capture around the refactored call rather than the raw diff hunks."
      ],
      "meta": {
       "generated": "2026-10-03",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 9,
       "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_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "806774b1cf641e0c0e7df8024e327febf23d7d7c",
       "tag": "android-security-15.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-22409",
     "osv_id": "ASB-A-375397370",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "Critical",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Nine failure-path log statements in the Bluetooth stack (AVCT, BNEP, HID device, RFCOMM, SDP) read the buffer length after passing the buffer to L2CA_DataWrite. They now use a length captured before the call, or a pointer difference that was already computed, so they no longer read a buffer that may already have been freed.",
      "confidence": "high",
      "backport_notes": [
       "The change is self-contained: at each site, capture the length into a local before the L2CA_DataWrite call and log the local. Where the call is spelled `stack::l2cap::get_interface().L2CA_DataWrite(...) != tL2CAP_DW_RESULT::SUCCESS` (seen per index search in bnep_utils.cc on Android 15 android-15.0.0_r36), apply the same change by hand rather than applying the raw diff.",
       "Bluetooth is a mainline (APEX) module, so fixes may also ship through module updates (general platform knowledge)."
      ],
      "meta": {
       "generated": "2026-10-03",
       "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-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "806774b1cf641e0c0e7df8024e327febf23d7d7c",
       "tag": "android-security-15.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-22410",
     "osv_id": "ASB-A-375397720",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "Critical",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Across nine L2CA_DataWrite call sites in the Bluetooth stack (AVCTP, BNEP, HID device, RFCOMM, SDP), the failure-path log statement is changed to use a length captured before the call (a local variable or a pointer difference) instead of reading the BT_HDR buffer, which may have been freed by the time the log runs.",
      "confidence": "high",
      "backport_notes": [
       "The change is self-contained and local to each log statement. In a tree that calls L2CA_DataWrite through stack::l2cap::get_interface() and compares against tL2CAP_DW_RESULT::SUCCESS (as in the Android 15 r36 index snapshot of bnepu_check_send_packet), only the call expression differs; the same local-variable capture applies.",
       "Bluetooth is delivered as a Mainline module (general platform knowledge)."
      ],
      "meta": {
       "generated": "2026-10-03",
       "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-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "806774b1cf641e0c0e7df8024e327febf23d7d7c",
       "tag": "android-security-15.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-22411",
     "osv_id": "ASB-A-375398779",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "Critical",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "In nine log::warn statements across the AVCT, BNEP, HID device, RFCOMM and SDP layers of the Bluetooth stack, the fix stops reading the BT_HDR buffer's len field after the buffer has been passed to L2CA_DataWrite. It either captures the length in a local before the call or recomputes it with pointer arithmetic.",
      "confidence": "medium",
      "backport_notes": [
       "Single commit. Each hunk is independent and can be applied per file. Where the call is written as stack::l2cap::get_interface().L2CA_DataWrite(...) != tL2CAP_DW_RESULT::SUCCESS (seen per index search), the hunk context differs, so apply the same change by hand: capture len before the call and log the local.",
       "In hidd_conn.cc, correct the indentation of the inserted lines inside the if (hd_cb.pending_data) block."
      ],
      "meta": {
       "generated": "2026-10-03",
       "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-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "806774b1cf641e0c0e7df8024e327febf23d7d7c",
       "tag": "android-security-15.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-22412",
     "osv_id": "ASB-A-375404242",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "Critical",
     "types": [
      "RCE"
     ],
     "status": "resolved",
     "brief": {
      "summary": "At nine Bluetooth stack call sites, the log::warn issued after a failed L2CA_DataWrite no longer reads the length from a BT_HDR buffer (p_buf->len, p->len, hd_cb.pending_data->len) that may already have been freed. The length is now captured before the call or taken from a pointer difference computed earlier.",
      "confidence": "high",
      "backport_notes": [
       "The change is self-contained and local to each call site. Per index search, Android 15 at android-15.0.0_r36 calls L2CA_DataWrite through stack::l2cap::get_interface() and compares the result with tL2CAP_DW_RESULT::SUCCESS. On code like that, apply the same 'capture len before the call' pattern around the refactored call.",
       "Bluetooth is a mainline module, so the fix may also ship through module updates, independent of the platform security tag (general platform knowledge)."
      ],
      "meta": {
       "generated": "2026-10-03",
       "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-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "806774b1cf641e0c0e7df8024e327febf23d7d7c",
       "tag": "android-security-15.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2024-43090",
     "osv_id": "ASB-A-331180422",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Removes the com.android.systemui.validate_keyboard_shortcut_helper_icon_uri flag gate so SystemUI's keyboard shortcut helper always calls KeyboardShortcuts.sanitiseShortcuts (which clears app/IME-provided icons) on shortcut groups received from apps and IMEs.",
      "confidence": "high",
      "backport_notes": [
       "For a branch without sanitiseShortcuts/clearIcon, port the Android 14 commit 4677d3ee0ec2 rather than this flag-removal commit. It needs both the core change (the hidden KeyboardShortcutInfo.clearIcon()) and the SystemUI call sites. Add the call wherever the branch receives app or IME shortcut lists; the Android 15 code has separate app and IME paths in each class.",
       "For a branch that already has the flag-gated calls, this commit only removes the guards. If the aconfig flag declaration is also deleted, make sure no reference to Flags.validateKeyboardShortcutHelperIconUri or FLAG_VALIDATE_KEYBOARD_SHORTCUT_HELPER_ICON_URI remains, because aconfig-generated Flags symbols disappear when the flag is removed (general platform knowledge)."
      ],
      "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_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "f1a15b5ef2539113c882fd2644f301a23e50f961",
       "tag": "android-security-15.0.0_r6",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "first_announced": "2024-11-01",
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-43093",
     "osv_id": "ASB-A-341680936",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "ExternalStorageProvider now decides whether a document lies under Android/data, Android/obb or Android/sandbox by comparing the filesystem identity of the path and its parents with Files.isSameFile. It no longer uses a case-insensitive regex over the document-id path string.",
      "confidence": "medium",
      "backport_notes": [
       "Single-file, single-commit change that applied identically to Android 14 and 15. It uses getRootFromDocId, getPathFromDocId, RootInfo.rootId, ROOT_ID_PRIMARY_EMULATED and UserHandle.myUserId; check that these exist on the target branch. Also check that the root mount path assumptions (/storage/emulated/<user> and /storage/<rootId>) hold for the device's volumes."
      ],
      "meta": {
       "generated": "2026-10-03",
       "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-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": "7f83c671626f9bf993581f4598c22482d87cba10",
       "tag": "android-security-15.0.0_r2",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 117,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2024-49740",
     "osv_id": "ASB-A-308932906",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "DoS"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds server-side enforcement in PhoneInterfaceManager that only the visual voicemail package (default dialer, system dialer or carrier VVM app, per commit message) may enable or disable the visual voicemail SMS filter, and adds length/size limits (256 chars per string, 100 list elements) to VisualVoicemailSmsFilterSettings.Builder.",
      "confidence": "medium",
      "backport_notes": [
       "Two commits in two projects linked by the same bug (Telephony PhoneInterfaceManager caller check; frameworks/base Builder limits); no code dependency between them is visible in the diffs. On branches without enforceTelephonyFeatureWithException (as on 14), the call goes right after mAppOps.checkPackage; confirm enforceVisualVoicemailPackage exists in the target PhoneInterfaceManager and that both enable and disable are covered.",
       "The frameworks/base change adds new IllegalArgumentException paths to public Builder setters; callers passing oversized values will now fail."
      ],
      "meta": {
       "generated": "2026-10-03",
       "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-15.0.0_r4",
      "date": "2025-01-06",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r4",
      "date": "2025-01-06",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "bcb1316835dc31f33f0c3b409ee847c389c09d2b",
       "tag": "android-security-15.0.0_r4",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/packages/services/Telephony",
       "sha": "b1ab472f0f56146387d3822318394cb2525ad34c",
       "tag": "android-security-15.0.0_r4",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 2,
     "public_before_announcement_days": 54,
     "projects": [
      "platform/frameworks/base",
      "platform/packages/services/Telephony"
     ]
    },
    {
     "cve": "CVE-2025-0078",
     "osv_id": "ASB-A-382775095",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "servicemanager now calls setRequestingSid(true) on its own ServiceManager object before self-registering it as the \"manager\" service, so the self-registered object has the flag set consistently with its use as the context object.",
      "confidence": "medium",
      "backport_notes": [
       "This is a single-line change with no dependencies: insert manager->setRequestingSid(true); between the sp<ServiceManager>::make(...) call and the addService(\"manager\", ...) call in cmds/servicemanager/main.cpp. The added line is the same on 14 and 15, but the surrounding context differs: 15 has disableBackgroundScheduling(true) just before it, while the 14 hunk context shows setCallRestriction."
      ],
      "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_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/native",
       "sha": "c32d4defe0f4e5cad86437d6672de7a76caf1a79",
       "tag": "android-security-15.0.0_r6",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/native"
     ]
    },
    {
     "cve": "CVE-2025-0079",
     "osv_id": "ASB-A-345258562",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Adds the encryption requirement (BTA_SEC_ENCRYPT / BTM_SEC_OUT_ENCRYPT) to the L2CAP security mask used when registering and when opening the AVCTP control, AVCTP browsing and AVDTP PSMs. These channels now require encryption as well as authentication.",
      "confidence": "high",
      "backport_notes": [
       "The change only touches the security-mask argument. Android 14 uses L2CA_Register2 / L2CA_ConnectReq2 (see the 14 commit). At android-15.0.0_r36 the calls go through stack::l2cap::get_interface() with BT_PSM_AVCTP / BT_PSM_AVCTP_BROWSE constants (per index search). Match on the call sites rather than on literal lines.",
       "Update both the PSM registration sites and the outgoing connect-request sites for all three PSMs."
      ],
      "meta": {
       "generated": "2026-10-03",
       "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-15.0.0_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "b1e6d8d1e393d246a0738c92747a0bef98e67a30",
       "tag": "android-security-15.0.0_r6",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-0080",
     "osv_id": "ASB-A-370958259",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "The fix hardens the PackageInstaller unarchive confirmation UI against overlays in two ways: it adds SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS to UnarchiveActivity's window, and it disables the dialog's Restore button whenever UnarchiveFragment is paused, then re-enables it on resume.",
      "confidence": "high",
      "backport_notes": [
       "A single self-contained commit touching two files in packages/PackageInstaller. It only applies to branches that already contain UnarchiveActivity/UnarchiveFragment. SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS is a hidden/system API that platform-built apps can use (general platform knowledge)."
      ],
      "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_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "5916a3de10fa9ca6a9b31f489be1838c0a1613f4",
       "tag": "android-security-15.0.0_r6",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2025-0082",
     "osv_id": "ASB-A-376461551",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Replaces the Uri.getEncodedUserInfo()-based cross-user check on URI-type icons in StatusHints and TelecomServiceImpl with a new StatusHints.getUserIdFromAuthority() helper that derives the user id from the URI authority (text before the last '@'), so icons whose user id does not match, or cannot be parsed to, the calling user are dropped (StatusHints) or rejected (TelecomServiceImpl).",
      "confidence": "high",
      "backport_notes": [
       "Two-repo fix with a build dependency: apply the frameworks/base StatusHints commit (adds getUserIdFromAuthority) before the Telecomm commit, which imports android.telecom.StatusHints and calls the new static helper.",
       "If a tree cannot take the framework change, the Telecomm side would need the same parse logic inlined (getAuthority(), lastIndexOf('@'), parseInt with NumberFormatException mapped to USER_NULL); keep both sites consistent."
      ],
      "meta": {
       "generated": "2026-10-03",
       "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-15.0.0_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "7ba8c8f63f1b13b127c871749314a242ff022ae2",
       "tag": "android-security-15.0.0_r6",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/packages/services/Telecomm",
       "sha": "685c2fc2f6b40bb2113db77da270c7b7220791c4",
       "tag": "android-security-15.0.0_r6",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 2,
     "projects": [
      "platform/frameworks/base",
      "platform/packages/services/Telecomm"
     ]
    },
    {
     "cve": "CVE-2025-0083",
     "osv_id": "ASB-A-376259166",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Replaces the Uri.getEncodedUserInfo()-based cross-user check on URI-type icons in StatusHints and TelecomServiceImpl (phone account registration) with a new shared helper StatusHints.getUserIdFromAuthority that derives the user id from the authority and rejects unparsable or mismatching user ids.",
      "confidence": "high",
      "backport_notes": [
       "Two-repo fix with a dependency: the Telecomm change calls the new StatusHints.getUserIdFromAuthority, so the frameworks/base StatusHints commit must land first (or together). Both carry Flag: EXEMPT bugfix.",
       "If the framework change cannot be taken, the same logic can be inlined in TelecomServiceImpl, but keep both sites consistent (getAuthority(), lastIndexOf('@'), USER_NULL on parse failure)."
      ],
      "meta": {
       "generated": "2026-10-03",
       "author_model": "claude-fable-5-1",
       "review_model": "claude-opus-5-5",
       "review_corrections": 1,
       "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_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "7ba8c8f63f1b13b127c871749314a242ff022ae2",
       "tag": "android-security-15.0.0_r6",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      },
      {
       "project": "platform/packages/services/Telecomm",
       "sha": "685c2fc2f6b40bb2113db77da270c7b7220791c4",
       "tag": "android-security-15.0.0_r6",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 2,
     "projects": [
      "platform/frameworks/base",
      "platform/packages/services/Telecomm"
     ]
    },
    {
     "cve": "CVE-2025-0086",
     "osv_id": "ASB-A-364269936",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "AccountManagerService now rejects a getAuthToken response from an AbstractAccountAuthenticator whose KEY_ACCOUNT_TYPE does not match the session's own account type (mAccountType), returning ERROR_CODE_INVALID_RESPONSE instead of storing the token.",
      "confidence": "high",
      "backport_notes": [
       "The hunk is self-contained. It relies only on the Session field mAccountType and on the existing name/type emptiness check immediately above it in the getAuthToken onResult, so apply it directly after that check. Line offsets differ per branch (3124 on 14, 3190 on 15)."
      ],
      "meta": {
       "generated": "2026-10-03",
       "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-15.0.0_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/frameworks/base",
       "sha": "c1aa9e662464b8fa49765d53a82efa8e06bb176a",
       "tag": "android-security-15.0.0_r6",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/frameworks/base"
     ]
    },
    {
     "cve": "CVE-2025-0092",
     "osv_id": "ASB-A-289375038",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "When a remote device transitions to BOND_NONE, the Bluetooth stack now resets that device's Message Access (MAP), Phonebook Access (PBAP) and SIM Access permissions to ACCESS_UNKNOWN, so previously granted access does not survive unbonding.",
      "confidence": "high",
      "backport_notes": [
       "The hook location differs by branch. Android 14 hooks BondStateMachine (before the ACTION_BOND_STATE_CHANGED intent is sent) and calls the AdapterService setters through mAdapterService. Android 15 hooks the AdapterService handler that calls mDatabaseManager.handleBondStateChanged. Make sure the three set*AccessPermission methods exist on AdapterService in the target branch."
      ],
      "meta": {
       "generated": "2026-10-03",
       "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-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "090ca53cc13c12e3763777a6a3c7367641e9808f",
       "tag": "android-security-15.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-0093",
     "osv_id": "ASB-A-289811388",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "When a device transitions to BOND_NONE, the Bluetooth stack now resets that device's Message Access (MAP), Phonebook Access (PBAP) and SIM Access permissions to ACCESS_UNKNOWN, so previously stored profile access does not survive unbonding.",
      "confidence": "high",
      "backport_notes": [
       "The insertion point differs between majors. On 14 the reset is in BondStateMachine.java, calling mAdapterService.setXxxAccessPermission before the ACTION_BOND_STATE_CHANGED intent is built. On 15 it is in AdapterService's own bond state handler, after mDatabaseManager.handleBondStateChanged. Put it where the branch centrally handles bond-state transitions. Both variants call existing setters on AdapterService."
      ],
      "meta": {
       "generated": "2026-10-03",
       "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-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "090ca53cc13c12e3763777a6a3c7367641e9808f",
       "tag": "android-security-15.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-22404",
     "osv_id": "ASB-A-375159480",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Before each L2CA_DataWrite call, the fix saves the BT_HDR length (or uses pointer arithmetic), so the failure-path log::warn statements in AVCT, BNEP, HID device, RFCOMM and SDP no longer read a buffer that the call may already have freed.",
      "confidence": "high",
      "backport_notes": [
       "The fix has no dependencies. At each of the nine sites, move the length read above the L2CA_DataWrite call, or use the pointer difference already used to set ->len. On branches that write the call through the stack::l2cap::get_interface() wrapper, make the same change around the wrapper call."
      ],
      "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_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "806774b1cf641e0c0e7df8024e327febf23d7d7c",
       "tag": "android-security-15.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-22405",
     "osv_id": "ASB-A-375159652",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "At nine Bluetooth stack call sites in eight files, the failure log after L2CA_DataWrite() no longer reads the BT_HDR buffer that was passed to that call (the commit message says such a buffer may already be freed). The length is now saved in a local variable before the call or recomputed from existing pointers.",
      "confidence": "high",
      "backport_notes": [
       "The change is self-contained and mechanical: wherever L2CA_DataWrite is followed by a log of the buffer length, save the length in a local before the call. Where the call is written as stack::l2cap::get_interface().L2CA_DataWrite(...) != tL2CAP_DW_RESULT::SUCCESS (the index shows this form for android-15.0.0_r36), apply the same change by hand, because the patch may not apply cleanly."
      ],
      "meta": {
       "generated": "2026-10-03",
       "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-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "806774b1cf641e0c0e7df8024e327febf23d7d7c",
       "tag": "android-security-15.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-22406",
     "osv_id": "ASB-A-375160214",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "EoP"
     ],
     "status": "resolved",
     "brief": {
      "summary": "At nine L2CAP send sites in eight Bluetooth stack files (AVCT, BNEP, HID device, RFCOMM, SDP), the log::warn on the failure path no longer reads the BT_HDR buffer after it has been passed to L2CA_DataWrite. The length is now saved in a local before the call or computed from pointers the code already has.",
      "confidence": "high",
      "backport_notes": [
       "This is a single commit with no other commits it depends on. Some trees call L2CA_DataWrite through stack::l2cap::get_interface() and compare against tL2CAP_DW_RESULT::SUCCESS (seen in android-15.0.0_r36 per index search). When porting to such a tree, add the same `len` capture before the call and keep that tree's comparison form."
      ],
      "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_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "806774b1cf641e0c0e7df8024e327febf23d7d7c",
       "tag": "android-security-15.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-22407",
     "osv_id": "ASB-A-375396810",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "Across nine L2CA_DataWrite call sites in the Bluetooth stack (AVCT, BNEP, HID device, RFCOMM, SDP), the failure-path log::warn no longer dereferences the BT_HDR buffer that was passed to L2CA_DataWrite; instead the length is stored in a local before the call or recomputed from pointer arithmetic.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit with no dependency shown. Per index search (android-15.0.0_r36), some code calls stack::l2cap::get_interface().L2CA_DataWrite(...) != tL2CAP_DW_RESULT::SUCCESS. On such code the context lines differ, but the 'capture len before the call' pattern is the same."
      ],
      "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_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r5",
      "date": "2025-02-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/modules/Bluetooth",
       "sha": "806774b1cf641e0c0e7df8024e327febf23d7d7c",
       "tag": "android-security-15.0.0_r5",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "public_before_announcement_days": 26,
     "projects": [
      "platform/packages/modules/Bluetooth"
     ]
    },
    {
     "cve": "CVE-2025-26417",
     "osv_id": "ASB-A-304497167",
     "source": "osv",
     "announced": "2025-03-01",
     "severity": "High",
     "types": [
      "ID"
     ],
     "status": "resolved",
     "brief": {
      "summary": "DownloadProvider's insert path now queries MediaStore for an existing record at the requested destination file path and throws SecurityException when that record's OWNER_PACKAGE_NAME does not belong to the calling UID.",
      "confidence": "high",
      "backport_notes": [
       "Single self-contained commit; the insertion point requires the existing Helpers.checkDestinationFilePathRestrictions(file, ..., isLegacyMode, /* allowDownloadsDirOnly */ true) call and Helpers.getContentUriForPath. Binder, RemoteException, MediaStore and Uri imports are shown in the Android 15 file context; confirm ContentProviderClient and Cursor imports and helper signatures on older branches."
      ],
      "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_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "last_fix": {
      "tag": "android-security-15.0.0_r6",
      "date": "2025-03-03",
      "provenance": "security_tag"
     },
     "public_commits": [
      {
       "project": "platform/packages/providers/DownloadProvider",
       "sha": "ed764e06106adef1cff5178c6df038fd054e7bec",
       "tag": "android-security-15.0.0_r6",
       "provenance": "security_tag",
       "method": "bug_id",
       "confidence": "certain",
       "evidence": null,
       "similarity": null
      }
     ],
     "n_public_commits": 1,
     "projects": [
      "platform/packages/providers/DownloadProvider"
     ]
    }
   ],
   "tags": [
    "android-security-15.0.0_r6"
   ],
   "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-2025-0074": {
     "cve": "CVE-2025-0074",
     "summary": "Two log::warn statements in system/stack/sdp/sdp_discovery.cc read p_cmd->len / p_msg->len after a failed L2CA_DataWrite. They now log the locally computed length (p - p_start), so the buffer that may have been freed is no longer dereferenced.",
     "component": "platform/packages/modules/Bluetooth, SDP client (system/stack/sdp/sdp_discovery.cc)",
     "weakness": "use after free (the buffer is read after a preceding call may have freed it)",
     "root_cause": "In sdp_snd_service_search_req and process_service_search_attr_rsp, the outgoing SDP PDU buffer (p_cmd / p_msg) is passed to L2CA_DataWrite. When L2CA_DataWrite does not return L2CAP_DW_SUCCESS, the code emits a log::warn whose arguments read p_cmd->len / p_msg->len. The commit message says that in exceptional cases the preceding call has already freed that structure, so the log statement reads freed memory.",
     "fix_analysis": [
      "system/stack/sdp/sdp_discovery.cc:sdp_snd_service_search_req: after a failed L2CA_DataWrite, the log::warn now logs `p - p_start` (the value stored into p_cmd->len on line 178 at r17) instead of dereferencing p_cmd->len.",
      "system/stack/sdp/sdp_discovery.cc:process_service_search_attr_rsp: the equivalent log::warn after a failed L2CA_DataWrite now logs `p - p_start` instead of p_msg->len.",
      "L2CA_DataWrite ownership semantics are unchanged; the fix only removes the two post-call reads of the buffer. The commit is labelled a trivial logic fix and lists a researcher POC as a test."
     ],
     "completeness": [
      "The fix covers exactly the two L2CA_DataWrite failure log statements named in the commit (sdp_snd_service_search_req and process_service_search_attr_rsp). Both now use only local variables.",
      "In the shown context for sdp_snd_service_search_req, the buffer is not touched after L2CA_DataWrite: the function goes on to alarm_set_on_mloop with p_ccb. The material does not show the rest of process_service_search_attr_rsp.",
      "The material does not show whether other L2CA_DataWrite call sites in sdp_discovery.cc or elsewhere in the SDP stack have the same post-write logging pattern."
     ],
     "behavior_changes": [
      "No functional change. Only the memory read in the warning path is removed. In sdp_snd_service_search_req the logged value matches what was stored in p_cmd->len (apart from the uint16_t cast). The material does not show the matching assignment for p_msg->len."
     ],
     "preconditions": [
      "An SDP client transaction with a remote device is in progress, and sdp_snd_service_search_req or process_service_search_attr_rsp is sending an SDP PDU through L2CA_DataWrite.",
      "L2CA_DataWrite for that PDU returns a value other than L2CAP_DW_SUCCESS, so the log::warn path is taken. The commit describes the freed-buffer case as exceptional."
     ],
     "per_major": {
      "14": "Not affected per the bulletin. At android-security-14.0.0_r29 only 2/8 lines of the patched region are present, so the region differs from the Android 15 code.",
      "15": "Same fix: commit 37bcf769c1aa in android-security-15.0.0_r5, a cherry-pick with Change-Id I1c8816721588acba9110257b61b4e993cf2720d6. At android-security-15.0.0_r17, 6/8 lines of the patched region are present, and the shown context has the fixed `p - p_start` argument in sdp_snd_service_search_req.",
      "16": "Not affected per the bulletin. At android-security-16.0.0_r8, 4/8 lines of the patched region are present, so the region differs from the Android 15 code.",
      "17": "Not affected per the bulletin. At android-security-17.0.0_r1, 4/8 lines of the patched region are present, so the region differs from the Android 15 code."
     },
     "backport_notes": [
      "This is a single two-line commit with no dependencies shown. If your tree lacks this exact log::warn text, find every log statement that follows a failed L2CA_DataWrite in sdp_discovery.cc and replace reads of the sent buffer (p_cmd->len / p_msg->len) with the local length p - p_start."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show the exact failure conditions under which the buffer is freed before the log statement.",
      "The material does not show whether other L2CA_DataWrite call sites in the SDP stack have similar post-write logging.",
      "The material does not show why Android 16 and 17 are not listed by the bulletin, beyond the line-presence counts.",
      "The material does not show the full context of process_service_search_attr_rsp around the fixed site."
     ],
     "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-2025-0075": {
     "cve": "CVE-2025-0075",
     "summary": "In system/stack/sdp/sdp_server.cc process_service_search_attr_req, the warning logged when L2CA_DataWrite fails no longer reads p_buf->len, because p_buf may already have been freed. It now computes the length from the local pointers p_rsp - p_rsp_start.",
     "component": "platform/packages/modules/Bluetooth, SDP server (system/stack/sdp/sdp_server.cc)",
     "weakness": "Use after free (read of p_buf->len after the buffer may have been freed by preceding calls)",
     "root_cause": "process_service_search_attr_req builds an SDP response in buffer p_buf and passes it to L2CA_DataWrite(p_ccb->connection_id, p_buf). If the call did not return L2CAP_DW_SUCCESS, the warning log read p_buf->len. The commit message says the structure may, in exceptional cases, have been freed by preceding calls, so this read could be a use after free.",
     "fix_analysis": [
      "system/stack/sdp/sdp_server.cc:process_service_search_attr_req: in the log::warn call, the argument p_buf->len is replaced by p_rsp - p_rsp_start. These are local pointers. The code context shows p_buf->len = p_rsp - p_rsp_start being set just before the write, so the logged value is the same, but p_buf is no longer read after the call.",
      "No other logic changes: the write, its return check and the log text stay the same. The change is one line in one hunk."
     ],
     "completeness": [
      "The fix only changes the failure-path log in process_service_search_attr_req. Within the diff, it removes the read of p_buf after L2CA_DataWrite.",
      "The code context at android-security-15.0.0_r17 (lines 275-310, labeled process_service_search_attr_req) shows the log already using p_rsp - p_rsp_start. The body of that snippet writes handle counts and handles, so it is unclear whether it is the patched function or another response path. The material does not show whether any other SDP response path in sdp_server.cc reads p_buf after L2CA_DataWrite.",
      "The fix does not change L2CA_DataWrite itself."
     ],
     "behavior_changes": [
      "None functionally. The logged length is the same number (p_rsp - p_rsp_start is the value assigned to p_buf->len before the write). Only the source of the value changes."
     ],
     "preconditions": [
      "A peer sends an SDP request that reaches process_service_search_attr_req and produces a response.",
      "L2CA_DataWrite must return a value other than L2CAP_DW_SUCCESS, and p_buf must have been freed in that exceptional case (commit message)."
     ],
     "per_major": {
      "14": "Not affected per the bulletin (not listed). At android-security-14.0.0_r29, 1/4 lines of the patched region are present. The material does not show whether the same log pattern exists.",
      "15": "Same fix: commit 5959f8bcf4ef in android-security-15.0.0_r5, cherry-picked from an internal change (Change-Id I1037e592ab8910eeae5c28a41a53a2fc60a298d8). At android-security-15.0.0_r17, 3/4 lines of the region are present, and the log uses p_rsp - p_rsp_start.",
      "16": "Not affected per the bulletin (not listed). At android-security-16.0.0_r8, 2/4 lines of the patched region are present. The material does not show the state of the patched line.",
      "17": "Not affected per the bulletin (not listed). At android-security-17.0.0_r1, 2/4 lines of the patched region are present. The material does not show the state of the patched line."
     },
     "backport_notes": [
      "This is a single one-line change. In trees with a different logging form, apply the same transformation: replace the read of p_buf after L2CA_DataWrite with p_rsp - p_rsp_start (or a length saved before the call). Bluetooth is a Mainline module (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "Which L2CA_DataWrite paths or preceding calls free p_buf. The material only says it may be freed in exceptional cases.",
      "Whether other SDP response handlers in sdp_server.cc read p_buf after the write, and which function the r17 context snippet actually belongs to.",
      "The exact state of the patched line in the Android 14, 16 and 17 trees. Only line-match counts are given.",
      "Whether and how the fix is delivered through Mainline module updates."
     ],
     "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-2025-0081": {
     "cve": "CVE-2025-0081",
     "summary": "Adds a null check at the top of dng_lossless_decoder::HuffDecode in external/dng_sdk. A null HuffmanTable pointer now causes ThrowBadFormat () instead of being dereferenced.",
     "component": "platform/external/dng_sdk, lossless JPEG decoder (source/dng_lossless_jpeg.cpp)",
     "weakness": "Missing null check leading to NULL pointer dereference (CWE-476) while decoding image data",
     "root_cause": "dng_lossless_decoder::HuffDecode(HuffmanTable *htbl) used the table pointer it was given, starting with the fast table lookup path, without checking it for null. The commit title is \"Catch null HuffmanTables when decoding jpeg\". The bulletin classifies the issue as DoS, rated Critical.",
     "fix_analysis": [
      "source/dng_lossless_jpeg.cpp : dng_lossless_decoder::HuffDecode inserts `if (htbl == nullptr) { ThrowBadFormat (); }` before the fast lookup path, so a null table is rejected before htbl is used.",
      "This is a single-commit fix: 4 added lines, with no header or caller changes. Android 15 has 7fc02c8d5af3 (Change-Id Iaf36c076467d18e4e31d8436a6d199c3276a8786, a cherry-pick of 6fd49d6ecdf5). Android 14 has 4b02aff0777b with an identical diff."
     ],
     "completeness": [
      "The check sits in HuffDecode, so it covers any call that passes a null table to HuffDecode.",
      "The fix validates at the point of use, not where the table pointer is chosen. Any other direct use of the table pointers outside HuffDecode is not touched by this diff and is not visible in the material.",
      "Only HuffDecode on the decoder side is changed. Nothing in the encoder path is modified."
     ],
     "behavior_changes": [
      "When HuffDecode receives a null table, it now calls ThrowBadFormat (). Previously it dereferenced the null pointer.",
      "Well-formed streams are not affected. The added branch is a single pointer compare per HuffDecode call."
     ],
     "preconditions": [
      "Image data must reach the lossless JPEG decoder in external/dng_sdk in a state where HuffDecode is called with a null HuffmanTable pointer. The conditions that produce this are not shown."
     ],
     "per_major": {
      "14": "same fix: commit 4b02aff0777b in android-security-14.0.0_r18, with a diff identical to the Android 15 commit. At android-security-14.0.0_r29, 3/4 lines of the patched region are present.",
      "15": "same fix: commit 7fc02c8d5af3 in android-security-15.0.0_r6 (cherry-pick of 6fd49d6ecdf5). At android-security-15.0.0_r17, 3/4 lines of the patched region are present.",
      "16": "not affected per the bulletin. At android-security-16.0.0_r8, 3/4 lines of the patched region are present.",
      "17": "not affected per the bulletin. At android-security-17.0.0_r1, 3/4 lines of the patched region are present."
     },
     "backport_notes": [
      "The change is 4 self-contained lines in dng_lossless_decoder::HuffDecode. The bulletin lists 12, 12L and 13 as affected, but the material has no commit for those branches."
     ],
     "confidence": "medium",
     "unknowns": [
      "Fix commits for Android 12, 12L and 13 are not in the material.",
      "How htbl becomes null (for example, a scan referencing an undefined table) is not shown.",
      "Whether other code in dng_lossless_jpeg.cpp uses the Huffman table pointers directly, bypassing HuffDecode, cannot be confirmed.",
      "The exception type raised by ThrowBadFormat and how callers handle it are not shown.",
      "The Android caller stack from untrusted input to the dng_sdk decoder (for example, through Skia) is not shown in the material.",
      "The material does not explain why only 3/4 lines of the patched region are reported present on each branch."
     ],
     "meta": {
      "generated": "2026-10-03",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 9,
      "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-2025-0084": {
     "cve": "CVE-2025-0084",
     "summary": "Adds a guard in bta_hf_client_do_disc that aborts discovery when the HF client control block already holds a discovery database, and a NULL check on p_ccb->p_db in process_service_search_attr_rsp that disconnects the SDP connection instead of using an absent database.",
     "component": "platform/packages/modules/Bluetooth, system/bta/hf_client (HFP client SDP) and system/stack/sdp (SDP discovery client)",
     "weakness": "Use-after-free (dangling discovery database pointer shared between two SDP connections)",
     "root_cause": "bta_hf_client_do_disc always allocated a new tSDP_DISCOVERY_DB into client_cb->p_disc_db and started SDP discovery, without checking whether the control block already had a database. Per the commit message, a modified client could open two connections against the same SDP discovery database. Once the first connection was closed, the second connection could reference the freed database. Separately, process_service_search_attr_rsp in system/stack/sdp/sdp_discovery.cc had no NULL check on p_ccb->p_db before building a first-time or continuation request. The commit adds one as a guard against unchecked use of the discovery database.",
     "fix_analysis": [
      "system/bta/hf_client/bta_hf_client_sdp.cc:bta_hf_client_do_disc: before the osi_malloc of a new database, if client_cb->p_disc_db != NULL, the function logs an error, sets client_cb->p_disc_db = NULL (it does not free it) and sets client_cb->state = 0 (BTA_HF_CLIENT_INIT_ST). Per the code comment, the state is set by hand because the function can be entered from an OPEN state, where a discovery-fail event would be ignored. It then returns without allocating, calling SDP_InitDiscoveryDb or starting discovery.",
      "system/stack/sdp/sdp_discovery.cc:process_service_search_attr_rsp: just before a first-time or continuation request is built, if p_ccb->p_db == NULL, the function logs a warning, calls sdp_disconnect(p_ccb, tSDP_STATUS::SDP_INVALID_CONT_STATE) and returns.",
      "The commit metadata names Flag: com.android.bluetooth.flags.btsec_check_valid_discovery_database, but the diff contains no flag check. Both guards are unconditional in the code shown."
     ],
     "completeness": [
      "Covers the HF client path: bta_hf_client_do_disc refuses a second discovery on a control block that already owns a database.",
      "In the SDP stack, only process_service_search_attr_rsp is changed (NULL p_db). The diff does not touch the other response handlers in sdp_discovery.cc, and the material does not show whether they check p_ccb->p_db.",
      "The NULL check is defensive only. It does not detect a freed but non-NULL p_db. Protection against the dangling pointer relies on the bta_hf_client_do_disc guard.",
      "The guard drops the existing p_disc_db pointer without freeing it. The material does not show whether that leaks memory or whether the pointer is owned elsewhere."
     ],
     "behavior_changes": [
      "When a discovery database already exists, bta_hf_client_do_disc now logs an error, resets the control block state to BTA_HF_CLIENT_INIT_ST and returns early instead of starting a second discovery.",
      "When p_ccb->p_db is NULL, process_service_search_attr_rsp now logs a warning and disconnects the SDP connection with tSDP_STATUS::SDP_INVALID_CONT_STATE."
     ],
     "preconditions": [
      "Bluetooth is enabled and the HFP client (hf_client) role is in use. Index search lists bta_hf_client_rfc_acp_open in system/bta/hf_client/bta_hf_client_act.cc as a related user of bta_hf_client_do_disc, but the excerpt does not show the call path.",
      "Per the commit message, a modified client must open two connections against the same discovery database, and the first connection must then be closed.",
      "The sdp_discovery.cc guard is reached when a service search attribute response is processed and a first-time or continuation request would be issued for a connection without a valid database."
     ],
     "per_major": {
      "14": "adapted fix: commit c4d8043ef4ea in android-security-14.0.0_r18. Same logic, but it logs with APPL_TRACE_ERROR and SDP_TRACE_WARNING instead of log::error and log::warn. 6/6 lines of the patched region are present at android-security-14.0.0_r29.",
      "15": "same fix: commit 94c565214e34 in android-security-15.0.0_r6 (cherry-pick of internal 27d31199637c). 6/6 lines of the patched region are present at android-security-15.0.0_r17.",
      "16": "not affected per the bulletin. The patched region is present at android-security-16.0.0_r8 (6/6 lines).",
      "17": "not affected per the bulletin. The patched region is present at android-security-17.0.0_r1 (6/6 lines)."
     },
     "backport_notes": [
      "Single commit with two independent hunks. Only the logging macros differ between 14 (APPL_TRACE_ERROR / SDP_TRACE_WARNING) and 15 (log::error / log::warn). The code does not reference the flag named in the commit message, so no aconfig flag plumbing is needed.",
      "Bluetooth is a mainline module, so devices may receive fixes through module updates rather than the platform tag (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact sequence by which a modified client opens two connections against one database (which API or event path) is not shown.",
      "The call path from HF client connection handling (e.g. bta_hf_client_rfc_acp_open) into bta_hf_client_do_disc is not shown.",
      "The material does not show whether other response handlers in sdp_discovery.cc use p_ccb->p_db without checking it.",
      "Whether the existing p_disc_db that the new guard drops is owned and freed elsewhere, or leaks.",
      "Why the commit names an aconfig flag that does not appear in the diff."
     ],
     "meta": {
      "generated": "2026-10-03",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 2,
      "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-2025-22403": {
     "cve": "CVE-2025-22403",
     "summary": "Replaces two log::warn arguments in system/stack/sdp/sdp_discovery.cc. They read p_cmd->len / p_msg->len after the buffer had been passed to L2CA_DataWrite, which per the commit message may have freed it in exceptional cases. The fix logs the locally computed length p - p_start instead.",
     "component": "platform/packages/modules/Bluetooth, SDP discovery (system/stack/sdp/sdp_discovery.cc)",
     "weakness": "use after free (read of the outgoing buffer after it was passed to L2CA_DataWrite)",
     "root_cause": "In sdp_snd_service_search_req and process_service_search_attr_rsp, the outgoing SDP buffer (p_cmd / p_msg) is passed to L2CA_DataWrite. The commit message says that in exceptional cases the preceding call may have freed that buffer. When L2CA_DataWrite returned something other than L2CAP_DW_SUCCESS, the failure log statement dereferenced the same buffer (p_cmd->len / p_msg->len) to print the length, which could read freed memory.",
     "fix_analysis": [
      "system/stack/sdp/sdp_discovery.cc:sdp_snd_service_search_req: the log::warn after a failed L2CA_DataWrite now prints `p - p_start` instead of dereferencing p_cmd->len. This is the same value stored in p_cmd->len at line 178.",
      "system/stack/sdp/sdp_discovery.cc:process_service_search_attr_rsp: the equivalent log::warn after a failed L2CA_DataWrite now prints `p - p_start` instead of dereferencing p_msg->len.",
      "No ownership or control-flow logic is changed. This is a single commit that changes 2 lines."
     ],
     "completeness": [
      "Covers exactly the two log statements named in the commit message. In sdp_snd_service_search_req, the shown context has no further access to p_cmd after L2CA_DataWrite. The material does not show the rest of process_service_search_attr_rsp after the write.",
      "The fix does not change L2CA_DataWrite's ownership/free semantics. This commit does not address any other caller that reads a buffer after passing it to L2CA_DataWrite. The material shows no such caller.",
      "Only the failure branch (L2CA_DataWrite != L2CAP_DW_SUCCESS) is changed. Success-path code is unchanged."
     ],
     "behavior_changes": [
      "No functional change; only the length argument of a warning log changes. In sdp_snd_service_search_req the logged value is identical to the previous p_cmd->len. No new error codes, timeouts or validation."
     ],
     "preconditions": [
      "The SDP discovery code sends a request: sdp_snd_service_search_req sends a service search request, and process_service_search_attr_rsp sends an L2CAP write while processing a received reply on an SDP connection.",
      "L2CA_DataWrite on p_ccb->connection_id must return a value other than L2CAP_DW_SUCCESS. Per the commit message, the buffer must also have been freed in that exceptional path. The material does not show the exact failure conditions."
     ],
     "per_major": {
      "14": "Not affected per the bulletin. At android-security-14.0.0_r29 only 2/8 lines of the patched region are present. The material does not show whether an equivalent post-write dereference exists.",
      "15": "Same fix: commit 37bcf769c1aa in android-security-15.0.0_r5 (cherry-pick of internal bb2f54f9ed93). At android-security-15.0.0_r17 the patched line with `p - p_start` is present in sdp_snd_service_search_req (6/8 region lines match).",
      "16": "Not affected per the bulletin. At android-security-16.0.0_r8, 4/8 lines of the patched region are present. The material does not show the exact lines.",
      "17": "Not affected per the bulletin. At android-security-17.0.0_r1, 4/8 lines of the patched region are present. The material does not show the exact lines."
     },
     "backport_notes": [
      "Trivial 2-line change with no dependencies. Where the surrounding logging code differs, apply the same principle: log a length computed from p and p_start, and do not read p_cmd/p_msg after L2CA_DataWrite."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show the exact conditions under which L2CA_DataWrite frees the buffer and returns failure.",
      "The material does not show the rest of process_service_search_attr_rsp after the write, or whether p_msg->len was set to p - p_start there.",
      "The material does not show whether the pre-fix pattern exists in the Android 14/16/17 source; it reports only partial region matches."
     ],
     "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-2025-22408": {
     "cve": "CVE-2025-22408",
     "summary": "Across nine L2CAP send sites in eight Bluetooth stack files (AVCTP, BNEP, HID device, RFCOMM, SDP client and server), the failure-path log::warn no longer reads ->len from the BT_HDR buffer after L2CA_DataWrite. The length is now saved in a local before the call, or taken from the pointer difference already computed for it.",
     "component": "platform/packages/modules/Bluetooth, system/stack (avct, bnep, hid, rfcomm, sdp)",
     "weakness": "Use after free (buffer dereferenced in a log statement after being handed to a call that may free it)",
     "root_cause": "At each affected site the code passes a BT_HDR* (p_buf, p_msg, p, hd_cb.pending_data) to L2CA_DataWrite. When the call does not return L2CAP_DW_SUCCESS, it logs `...->len` from that same buffer. Per the commit message, the preceding call may already have freed the buffer in exceptional cases, so the log statement reads freed memory. The pattern was present in avct_lcb_msg_ind, bnep_congestion_ind, bnepu_check_send_packet, hidd_check_config_done, rfc_send_buf_uih, rfc_check_send_cmd, process_service_attr_rsp, process_service_search and process_service_attr_req.",
     "fix_analysis": [
      "system/stack/avct/avct_lcb_act.cc:avct_lcb_msg_ind - adds `uint16_t len = p_buf->len;` before L2CA_DataWrite on the AVCT_REJ path and logs `len` instead of `p_buf->len`.",
      "system/stack/bnep/bnep_main.cc:bnep_congestion_ind - in the loop that drains xmit_q once congestion clears, saves `len` from the dequeued p_buf before L2CA_DataWrite and logs the local.",
      "system/stack/bnep/bnep_utils.cc:bnepu_check_send_packet - in the non-congested branch, saves `len` before L2CA_DataWrite and logs the local.",
      "system/stack/hid/hidd_conn.cc:hidd_check_config_done - saves `len = hd_cb.pending_data->len` before L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data) and logs the local. The new block is irregularly indented but the logic is correct.",
      "system/stack/rfcomm/rfc_ts_frames.cc:rfc_send_buf_uih - in the branch for DLCIs other than RFCOMM_MX_DLCI, saves `len` before L2CA_DataWrite and logs the local.",
      "system/stack/rfcomm/rfc_utils.cc:rfc_check_send_cmd - in the cmd_q drain loop, saves `len = p->len` before L2CA_DataWrite and logs the local.",
      "system/stack/sdp/sdp_discovery.cc:process_service_attr_rsp - replaces `p_msg->len` in the log with `p - p_start`, the same value assigned to p_msg->len just before the call.",
      "system/stack/sdp/sdp_server.cc:process_service_search and process_service_attr_req - replace `p_buf->len` in the log with `p_rsp - p_rsp_start`, the value assigned to p_buf->len just before the call.",
      "L2CA_DataWrite itself and the buffer ownership model are not changed. The fix only removes the read of the buffer after the call at the logging sites."
     ],
     "completeness": [
      "Nine sites across eight files are changed in the same way. The android-security-15.0.0_r17 code context shows the fixed form in bnep_congestion_ind, bnepu_check_send_packet, hidd_check_config_done, rfc_send_buf_uih, rfc_check_send_cmd, process_service_attr_rsp and process_service_search. The avct_lcb_msg_ind excerpt does not include the patched lines, and process_service_attr_req is not shown.",
      "The fix only touches the log statements: it removes the read of `->len` after the call. In the diff hunks, no other buffer field is read after the call at these sites.",
      "The commit title says 'more' memory-unsafe logging, which implies at least one related earlier commit covering other sites. That commit is not in the material, so this diff alone cannot show whether every L2CA_DataWrite failure-path log in the stack is covered."
     ],
     "behavior_changes": [
      "None functionally. The warnings log the same length value, now taken from a local or from the pointer difference that produced it, instead of from the possibly freed buffer."
     ],
     "preconditions": [
      "L2CA_DataWrite must return a result other than L2CAP_DW_SUCCESS at one of the patched sites, because only the failure path logs.",
      "Some sites sit on paths that process peer traffic. avct_lcb_msg_ind builds an AVCT_REJ while handling an incoming AVCTP message. The SDP server functions process_service_search and process_service_attr_req build responses to SDP requests. bnep_congestion_ind is an L2CAP congestion callback. Per index search, bnepu_send_peer_our_filters and bnepu_send_peer_filter_rsp call bnepu_check_send_packet.",
      "An established L2CAP channel for the relevant profile (AVCTP, BNEP, HID device, RFCOMM or SDP)."
     ],
     "per_major": {
      "14": "Not affected per the bulletin. At android-security-14.0.0_r29, 4/8 lines of the patched region are present. The material does not show whether an equivalent change exists or the code differs.",
      "15": "Same fix, applied via cherry-pick to android-security-15.0.0_r5 (Change-Id I6289907e86786eb2e10a163f7fb5d2557eab00bc). At android-security-15.0.0_r17 the resolver finds 7/8 lines of the patched region, and the visible context shows the fixed form at the sites it covers.",
      "16": "Not affected per the bulletin. At android-security-16.0.0_r8, 4/8 lines of the patched region are present. The material includes no Android 16 code that explains the difference.",
      "17": "Not affected per the bulletin. At android-security-17.0.0_r1, 4/8 lines of the patched region are present. The material includes no Android 17 code that explains the difference."
     },
     "backport_notes": [
      "The change is self-contained and mechanical. Per index search, android-15.0.0_r36 calls stack::l2cap::get_interface().L2CA_DataWrite(...) and compares against tL2CAP_DW_RESULT::SUCCESS (seen in bnepu_check_send_packet, with the local len capture already in place). On code with that form, apply the same local-variable capture around the refactored call rather than the raw diff hunks."
     ],
     "confidence": "medium",
     "unknowns": [
      "The material does not show the L2CA_DataWrite implementation. That it can free the buffer on failure comes only from the commit message.",
      "The related commit implied by the title 'Fix more memory-unsafe logging', and which of the nine bug IDs maps to which site, are not in the material.",
      "Whether Android 14, 16 and 17 contain an equivalent change, refactored code, or an unpatched form cannot be determined from the 4/8 line match alone.",
      "Which patched line is missing from the 7/8 match at android-security-15.0.0_r17, and the r17 state of avct_lcb_msg_ind and process_service_attr_req, are not shown."
     ],
     "meta": {
      "generated": "2026-10-03",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 9,
      "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-2025-22409": {
     "cve": "CVE-2025-22409",
     "summary": "Nine failure-path log statements in the Bluetooth stack (AVCT, BNEP, HID device, RFCOMM, SDP) read the buffer length after passing the buffer to L2CA_DataWrite. They now use a length captured before the call, or a pointer difference that was already computed, so they no longer read a buffer that may already have been freed.",
     "component": "platform/packages/modules/Bluetooth, system/stack (avct, bnep, hid, rfcomm, sdp)",
     "weakness": "Use after free (BT_HDR fields read after the buffer was passed to L2CA_DataWrite, which per the commit message may, in exceptional cases, have freed it)",
     "root_cause": "Several stack layers followed the same pattern: call L2CA_DataWrite(cid, p_buf), and if it does not return L2CAP_DW_SUCCESS, call log::warn(\"Unable to write L2CAP data ... len:{}\", ..., p_buf->len). Per the commit message, the buffer may, in exceptional cases, have been freed by the preceding call, so the log argument read a possibly freed buffer. Affected sites: avct_lcb_act.cc:avct_lcb_msg_ind (AVCT_REJ packet), bnep_main.cc:bnep_congestion_ind (draining xmit_q), bnep_utils.cc:bnepu_check_send_packet, hidd_conn.cc:hidd_check_config_done (hd_cb.pending_data), rfc_ts_frames.cc:rfc_send_buf_uih, rfc_utils.cc:rfc_check_send_cmd (draining cmd_q), sdp_discovery.cc:process_service_attr_rsp, and sdp_server.cc:process_service_search and process_service_attr_req.",
     "fix_analysis": [
      "system/stack/avct/avct_lcb_act.cc:avct_lcb_msg_ind: adds `uint16_t len = p_buf->len;` before L2CA_DataWrite and logs `len` instead of p_buf->len.",
      "system/stack/bnep/bnep_main.cc:bnep_congestion_ind: inside the dequeue loop, captures `len = p_buf->len` before L2CA_DataWrite and logs the local.",
      "system/stack/bnep/bnep_utils.cc:bnepu_check_send_packet: in the non-congested branch, captures `len` before L2CA_DataWrite and logs the local.",
      "system/stack/hid/hidd_conn.cc:hidd_check_config_done: captures `len = hd_cb.pending_data->len` before L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data) and logs the local. The new block is badly indented, but the logic is otherwise unchanged.",
      "system/stack/rfcomm/rfc_ts_frames.cc:rfc_send_buf_uih: in the non-MX-DLCI branch, captures `len` before L2CA_DataWrite and logs the local.",
      "system/stack/rfcomm/rfc_utils.cc:rfc_check_send_cmd: inside the cmd_q drain loop, captures `len = p->len` before L2CA_DataWrite and logs the local.",
      "system/stack/sdp/sdp_discovery.cc:process_service_attr_rsp: logs `p - p_start` (the value just assigned to p_msg->len) instead of p_msg->len.",
      "system/stack/sdp/sdp_server.cc:process_service_search and process_service_attr_req: log `p_rsp - p_rsp_start` (the value just assigned to p_buf->len) instead of p_buf->len.",
      "L2CA_DataWrite itself and the control flow are unchanged. Only the log arguments change, so they no longer depend on the buffer after the call."
     ],
     "completeness": [
      "Covers nine L2CA_DataWrite failure-log sites across eight files. At each site, the buffer is no longer read after the call.",
      "The fix is entirely at the call sites. L2CA_DataWrite's behavior on failure is unchanged, so any other caller that touches the buffer after a failed L2CA_DataWrite would still be affected. The material does not show the full set of L2CA_DataWrite callers.",
      "The commit title 'Fix more memory-unsafe logging' suggests an earlier related change covered other sites. That change is not in the material.",
      "The hidd_conn.cc hunk introduces misaligned indentation but is functionally correct."
     ],
     "behavior_changes": [
      "No functional change: the same warning messages are logged with the same length value, now taken before the write call. At the SDP sites, the logged length is the pointer difference that was just assigned to the len field."
     ],
     "preconditions": [
      "L2CA_DataWrite must return something other than L2CAP_DW_SUCCESS, and the buffer must have been freed on that path. The commit message says only that this can happen 'in exceptional cases'. The internals of L2CA_DataWrite are not in the material.",
      "Sites per the code: avct_lcb_msg_ind on incoming AVCT control-channel messages, where it builds an AVCT_REJ packet; process_service_search and process_service_attr_req in the SDP server; process_service_attr_rsp in SDP discovery; bnep_congestion_ind when L2CAP reports that congestion has cleared; rfc_send_buf_uih and rfc_check_send_cmd on RFCOMM transmit; hidd_check_config_done when a HID device connection finishes configuration with pending data.",
      "Per index search, bnepu_check_send_packet is called from bnepu_send_peer_our_filters and bnepu_send_peer_filter_rsp. The r17 context also shows a command-not-understood sender calling it."
     ],
     "per_major": {
      "14": "Not affected per the bulletin (not listed). At android-security-14.0.0_r29, 4/8 lines of the patched region are present.",
      "15": "Fixed by commit 806774b1cf64 in android-security-15.0.0_r5 (cherry-picked from internal commit 43cfd234de9b, Change-Id I6289907e86786eb2e10a163f7fb5d2557eab00bc). At android-security-15.0.0_r17, 7/8 lines of the patched region are present. The context there shows the fixed form at eight of the nine sites; the avct_lcb_msg_ind hunk is not shown in the context.",
      "16": "Not affected per the bulletin (not listed). At android-security-16.0.0_r8, 4/8 lines of the patched region are present.",
      "17": "Not affected per the bulletin (not listed). At android-security-17.0.0_r1, 4/8 lines of the patched region are present."
     },
     "backport_notes": [
      "The change is self-contained: at each site, capture the length into a local before the L2CA_DataWrite call and log the local. Where the call is spelled `stack::l2cap::get_interface().L2CA_DataWrite(...) != tL2CAP_DW_RESULT::SUCCESS` (seen per index search in bnep_utils.cc on Android 15 android-15.0.0_r36), apply the same change by hand rather than applying the raw diff.",
      "Bluetooth is a mainline (APEX) module, so fixes may also ship through module updates (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "The failure paths inside L2CA_DataWrite that free the buffer before returning a non-success code are not in the material.",
      "Which of the nine sites the 'researcher POC' exercised, and which of the nine bug IDs maps to which site.",
      "The earlier companion commit implied by the title 'Fix more memory-unsafe logging', and the sites it covered.",
      "Whether other L2CA_DataWrite callers outside these eight files still read the buffer after a failed write.",
      "Why only 4/8 patched-region lines match on Android 14, 16 and 17, and whether those branches have the same pattern.",
      "Whether the avct_lcb_msg_ind fix is present at android-security-15.0.0_r17 (not shown in the context)."
     ],
     "meta": {
      "generated": "2026-10-03",
      "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-2025-22410": {
     "cve": "CVE-2025-22410",
     "summary": "Across nine L2CA_DataWrite call sites in the Bluetooth stack (AVCTP, BNEP, HID device, RFCOMM, SDP), the failure-path log statement is changed to use a length captured before the call (a local variable or a pointer difference) instead of reading the BT_HDR buffer, which may have been freed by the time the log runs.",
     "component": "platform/packages/modules/Bluetooth, system/stack (avct, bnep, hid, rfcomm, sdp)",
     "weakness": "Use after free (read of BT_HDR::len in a log statement after the buffer was handed to L2CA_DataWrite)",
     "root_cause": "In several stack modules the code called L2CA_DataWrite(cid, p_buf) and, if the result was not L2CAP_DW_SUCCESS, ran log::warn(\"Unable to write L2CAP data ... len:{}\", ..., p_buf->len). The commit message says these structures may, in exceptional cases, already have been freed by the preceding call. The log argument therefore read a possibly freed BT_HDR (p_buf->len, p->len, p_msg->len, hd_cb.pending_data->len).",
     "fix_analysis": [
      "system/stack/avct/avct_lcb_act.cc:avct_lcb_msg_ind: in the AVCT_REJ send path, adds `uint16_t len = p_buf->len;` before L2CA_DataWrite and logs `len` instead of `p_buf->len`.",
      "system/stack/bnep/bnep_main.cc:bnep_congestion_ind: in the loop that drains the transmit queue after congestion clears, stores `len = p_buf->len` after the dequeue and before L2CA_DataWrite; the log uses `len`.",
      "system/stack/bnep/bnep_utils.cc:bnepu_check_send_packet: in the non-congested branch, stores `len` before L2CA_DataWrite and logs it.",
      "system/stack/hid/hidd_conn.cc:hidd_check_config_done: stores `len = hd_cb.pending_data->len` before L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data) and logs `len`; hd_cb.pending_data is still set to NULL afterwards.",
      "system/stack/rfcomm/rfc_ts_frames.cc:rfc_send_buf_uih: for DLCIs other than the multiplexer DLCI, stores `len = p_buf->len` before L2CA_DataWrite and logs it.",
      "system/stack/rfcomm/rfc_utils.cc:rfc_check_send_cmd: in the loop that drains cmd_q, stores `len = p->len` after the dequeue and before L2CA_DataWrite; the log uses `len`.",
      "system/stack/sdp/sdp_discovery.cc:process_service_attr_rsp: the log now uses `p - p_start`, the same value just assigned to p_msg->len, so p_msg is no longer read after the write.",
      "system/stack/sdp/sdp_server.cc:process_service_search and process_service_attr_req: the log now uses `p_rsp - p_rsp_start`, the value just assigned to p_buf->len, instead of `p_buf->len`.",
      "Control flow and return values are unchanged; only the value passed to the log statement changes (plus re-indentation in hidd_conn.cc)."
     ],
     "completeness": [
      "Covers nine log sites after L2CA_DataWrite in eight files: avct_lcb_act.cc, bnep_main.cc, bnep_utils.cc, hidd_conn.cc (hidd_check_config_done only), rfc_ts_frames.cc, rfc_utils.cc, sdp_discovery.cc and sdp_server.cc (two sites).",
      "The fix only removes the stale read in the log statement. It does not change L2CA_DataWrite or add ownership tracking, so any other code that touches a BT_HDR after passing it to L2CA_DataWrite is not addressed by this commit.",
      "The commit title 'Fix more memory-unsafe logging' suggests an earlier change of the same kind. That change is not in the material, so the full set of sites fixed across the series cannot be judged.",
      "In hidd_conn.cc only hidd_check_config_done is patched; the material does not show whether other L2CA_DataWrite call sites exist in that file."
     ],
     "behavior_changes": [
      "None functional. The logged length is the same value, either stored before the call or computed from the same pointer difference that set the len field."
     ],
     "preconditions": [
      "An established L2CAP channel with a remote peer on one of the affected paths: AVCTP control channel (avct_lcb_msg_ind handles incoming AVCTP data and sends an AVCT_REJ), BNEP (bnep_congestion_ind is the L2CAP congestion callback; per index search, bnepu_send_peer_our_filters and bnepu_send_peer_filter_rsp call bnepu_check_send_packet), HID device role (hidd_check_config_done when configuration completes with pending interrupt data), RFCOMM (rfc_send_buf_uih / rfc_check_send_cmd), or SDP client/server (process_service_attr_rsp, process_service_search, process_service_attr_req).",
      "L2CA_DataWrite must return something other than L2CAP_DW_SUCCESS for the log::warn branch to run; the material does not show the conditions under which the buffer is freed before the call returns."
     ],
     "per_major": {
      "14": "Not affected per the bulletin. At android-security-14.0.0_r29 only 4/8 lines of the patched region match; the material does not show whether the pattern is present there.",
      "15": "Same fix: commit 806774b1cf64 in android-security-15.0.0_r5 (cherry-pick of internal 43cfd234de9b, Change-Id I6289907e86786eb2e10a163f7fb5d2557eab00bc). At android-security-15.0.0_r17, 7/8 patched lines are present, and the code context there shows the fixed form at every site it includes (sdp_server.cc process_service_attr_req is not shown).",
      "16": "Not affected per the bulletin. At android-security-16.0.0_r8, 4/8 lines of the patched region match; the material shows no Android 16 code, so it cannot tell whether the fix form is present.",
      "17": "Not affected per the bulletin. At android-security-17.0.0_r1, 4/8 lines of the patched region match; the material shows no Android 17 code."
     },
     "backport_notes": [
      "The change is self-contained and local to each log statement. In a tree that calls L2CA_DataWrite through stack::l2cap::get_interface() and compares against tL2CAP_DW_RESULT::SUCCESS (as in the Android 15 r36 index snapshot of bnepu_check_send_packet), only the call expression differs; the same local-variable capture applies.",
      "Bluetooth is delivered as a Mainline module (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "The earlier commit implied by 'Fix more memory-unsafe logging' and which sites it covered.",
      "The code path inside L2CA_DataWrite that frees the buffer before returning a non-success result.",
      "Which of the nine sites the 'researcher POC' exercised.",
      "Whether the Android 14, 16 and 17 trees contain the pre-fix pattern or the fixed form at the sites where line matching failed.",
      "Why only 7/8 patched lines match at android-security-15.0.0_r17."
     ],
     "meta": {
      "generated": "2026-10-03",
      "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-2025-22411": {
     "cve": "CVE-2025-22411",
     "summary": "In nine log::warn statements across the AVCT, BNEP, HID device, RFCOMM and SDP layers of the Bluetooth stack, the fix stops reading the BT_HDR buffer's len field after the buffer has been passed to L2CA_DataWrite. It either captures the length in a local before the call or recomputes it with pointer arithmetic.",
     "component": "platform/packages/modules/Bluetooth, system/stack (avct, bnep, hid, rfcomm, sdp)",
     "weakness": "Use after free (logging reads a BT_HDR that a preceding L2CA_DataWrite call may have freed)",
     "root_cause": "In each changed site, the log statement in the failure branch after L2CA_DataWrite still dereferenced the buffer just passed to it (p_buf->len, p->len, p_msg->len, hd_cb.pending_data->len). The commit message says these structures 'may, in exceptional cases, have been freed by preceding calls', so the logging could read freed memory.",
     "fix_analysis": [
      "system/stack/avct/avct_lcb_act.cc:avct_lcb_msg_ind: copies p_buf->len into a local uint16_t len before L2CA_DataWrite and logs len instead of p_buf->len (AVCT_REJ response path).",
      "system/stack/bnep/bnep_main.cc:bnep_congestion_ind: in the uncongested drain loop over p_bcb->xmit_q, stores p_buf->len in a local before L2CA_DataWrite and logs the local.",
      "system/stack/bnep/bnep_utils.cc:bnepu_check_send_packet: in the non-congested branch, stores p_buf->len in a local before L2CA_DataWrite and logs the local.",
      "system/stack/hid/hidd_conn.cc:hidd_check_config_done: stores hd_cb.pending_data->len in a local before L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data) and logs the local. The new lines are indented wrongly in the diff, but the logic is not affected.",
      "system/stack/rfcomm/rfc_ts_frames.cc:rfc_send_buf_uih: for DLCIs other than the multiplexer DLCI, stores p_buf->len in a local before L2CA_DataWrite and logs the local.",
      "system/stack/rfcomm/rfc_utils.cc:rfc_check_send_cmd: in the cmd_q drain loop, stores p->len in a local before L2CA_DataWrite and logs the local.",
      "system/stack/sdp/sdp_discovery.cc:process_service_attr_rsp: logs p - p_start instead of p_msg->len. This is the same value assigned to p_msg->len just before the call, so the buffer is not touched.",
      "system/stack/sdp/sdp_server.cc:process_service_search and process_service_attr_req: log p_rsp - p_rsp_start instead of p_buf->len. This is the value previously written into p_buf->len.",
      "The fix does not change L2CA_DataWrite itself; it only removes reads of the buffer after the call."
     ],
     "completeness": [
      "Covers nine L2CA_DataWrite error-log sites in eight files. After the fix, none of the changed sites touches the buffer after the call.",
      "The commit title, 'Fix more memory-unsafe logging', points to earlier fixes of the same pattern. The material does not show those earlier commits, or whether other L2CA_DataWrite callers in system/stack still read the buffer after the call.",
      "In hidd_conn.cc only the hidd_check_config_done path is changed. The material does not show any other L2CA_DataWrite sites in that file.",
      "L2CA_DataWrite is not modified. The fix is limited to the call sites."
     ],
     "behavior_changes": [
      "None functionally. Only the source of the length value in log::warn messages changes; the logged values match the intended length (a local copy, or the same pointer difference that was stored into len)."
     ],
     "preconditions": [
      "The changed log statements run only when L2CA_DataWrite does not return L2CAP_DW_SUCCESS. The buffer must also have been freed by that point for the read to touch freed memory (the material does not show when that happens).",
      "Sites involved: avct_lcb_msg_ind (reassembles an incoming AVCT message, per index search) sends an AVCT_REJ. process_service_search and process_service_attr_req in sdp_server.cc build SDP responses. process_service_attr_rsp in sdp_discovery.cc sends a follow-up SDP request as client. bnepu_check_send_packet is called from bnepu_send_peer_our_filters and bnepu_send_peer_filter_rsp, among others (per index search). bnep_congestion_ind drains its queue when L2CAP congestion clears. rfc_check_send_cmd drains cmd_q while L2CAP is not congested and is also called from rfc_send_buf_uih for the multiplexer DLCI. hidd_check_config_done sends pending data when the HID device connection leaves the CONFIG state.",
      "The commit message notes 'Test: researcher POC', but the material does not describe the trigger."
     ],
     "per_major": {
      "14": "Not affected: the bulletin does not list Android 14. At android-security-14.0.0_r29 only 4/8 lines of the patched region are present. The material does not show whether the vulnerable log statements exist on that branch.",
      "15": "Same fix: commit 806774b1cf64 in android-security-15.0.0_r5, a cherry-pick of internal commit 43cfd234de9b (Change-Id I6289907e86786eb2e10a163f7fb5d2557eab00bc). At android-security-15.0.0_r17, 7/8 lines of the patched region are present. Per index search (android-15.0.0_r36), bnepu_check_send_packet captures the local len before a stack::l2cap::get_interface().L2CA_DataWrite call.",
      "16": "Not affected: the bulletin does not list Android 16. At android-security-16.0.0_r8, 4/8 lines of the patched region are present.",
      "17": "Not affected: the bulletin does not list Android 17. At android-security-17.0.0_r1, 4/8 lines of the patched region are present."
     },
     "backport_notes": [
      "Single commit. Each hunk is independent and can be applied per file. Where the call is written as stack::l2cap::get_interface().L2CA_DataWrite(...) != tL2CAP_DW_RESULT::SUCCESS (seen per index search), the hunk context differs, so apply the same change by hand: capture len before the call and log the local.",
      "In hidd_conn.cc, correct the indentation of the inserted lines inside the if (hd_cb.pending_data) block."
     ],
     "confidence": "medium",
     "unknowns": [
      "Which conditions inside L2CA_DataWrite (or other preceding calls) free the buffer; L2CA_DataWrite is not shown.",
      "Whether other L2CA_DataWrite call sites in system/stack still read the buffer after the call; the commit describes 'more' fixes, but the earlier commits are not provided.",
      "Why the bulletin lists only Android 15; the per-major line-match counts do not settle whether the pattern exists on 14, 16 and 17.",
      "Details of the researcher POC referenced in the commit message."
     ],
     "meta": {
      "generated": "2026-10-03",
      "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-2025-22412": {
     "cve": "CVE-2025-22412",
     "summary": "At nine Bluetooth stack call sites, the log::warn issued after a failed L2CA_DataWrite no longer reads the length from a BT_HDR buffer (p_buf->len, p->len, hd_cb.pending_data->len) that may already have been freed. The length is now captured before the call or taken from a pointer difference computed earlier.",
     "component": "platform/packages/modules/Bluetooth, system/stack (AVCT, BNEP, HID device, RFCOMM, SDP client and server)",
     "weakness": "Use after free: a buffer passed to L2CA_DataWrite is read in a log statement after the call, when, per the commit message, it may in exceptional cases already have been freed.",
     "root_cause": "Several profiles send a BT_HDR with L2CA_DataWrite(cid, p_buf). When the call does not return L2CAP_DW_SUCCESS, they log the length by reading p_buf->len (or p->len, or hd_cb.pending_data->len) after the call. Per the commit message, these structures may in exceptional cases have been freed by the preceding call, so the log statement can read freed memory. Affected sites: avct_lcb_act.cc:avct_lcb_msg_ind (AVCT_REJ response), bnep_main.cc:bnep_congestion_ind (draining xmit_q), bnep_utils.cc:bnepu_check_send_packet, hidd_conn.cc:hidd_check_config_done (pending interrupt data), rfc_ts_frames.cc:rfc_send_buf_uih, rfc_utils.cc:rfc_check_send_cmd (draining cmd_q), sdp_discovery.cc:process_service_attr_rsp, and sdp_server.cc:process_service_search and process_service_attr_req.",
     "fix_analysis": [
      "avct_lcb_act.cc:avct_lcb_msg_ind: adds `uint16_t len = p_buf->len;` before L2CA_DataWrite and logs `len` instead of p_buf->len.",
      "bnep_main.cc:bnep_congestion_ind: same pattern inside the xmit_q drain loop. `len` is captured after fixed_queue_try_dequeue and before L2CA_DataWrite.",
      "bnep_utils.cc:bnepu_check_send_packet: captures `len` in the non-congested branch before L2CA_DataWrite. The congested branch (enqueue or osi_free) is unchanged.",
      "hidd_conn.cc:hidd_check_config_done: captures `uint16_t len = hd_cb.pending_data->len;` before L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data) and logs `len`. hd_cb.pending_data is still set to NULL afterwards. The new lines are indented inconsistently, but the logic is correct.",
      "rfc_ts_frames.cc:rfc_send_buf_uih: captures `len` in the non-RFCOMM_MX_DLCI branch before L2CA_DataWrite(p_mcb->lcid, p_buf).",
      "rfc_utils.cc:rfc_check_send_cmd: captures `uint16_t len = p->len;` for each dequeued command buffer before L2CA_DataWrite.",
      "sdp_discovery.cc:process_service_attr_rsp: logs `p - p_start`, the value just assigned to p_msg->len, instead of reading p_msg.",
      "sdp_server.cc:process_service_search and process_service_attr_req: log `p_rsp - p_rsp_start`, the value just assigned to p_buf->len, instead of reading p_buf.",
      "L2CA_DataWrite itself is not changed. The fix only removes reads of the buffer after the call at these call sites."
     ],
     "completeness": [
      "Covers nine L2CA_DataWrite call sites in eight files. At each site, the only use of the buffer after the call was the length argument of log::warn, and that read is removed.",
      "The commit title 'Fix more memory-unsafe logging' suggests an earlier change fixed other sites. That commit is not in the material, so coverage across the whole stack cannot be judged here.",
      "The material does not show other L2CA_DataWrite callers that may read the buffer after the call, and this commit does not modify any.",
      "The logged values have the same meaning as before (the BT_HDR length at call time)."
     ],
     "behavior_changes": [
      "No functional change. The same length value is logged, now read from a local variable or recomputed from pointers instead of from the buffer after the call."
     ],
     "preconditions": [
      "L2CA_DataWrite must return something other than L2CAP_DW_SUCCESS on one of the patched paths, with the buffer already freed (the commit message calls these 'exceptional cases').",
      "The patched paths are transmit paths on Bluetooth channels: the AVCT_REJ response in avct_lcb_msg_ind, BNEP congestion clearing and BNEP control sends (per index search, bnepu_check_send_packet is called from bnepu_send_peer_our_filters and bnepu_send_peer_filter_rsp), HID device config completion, RFCOMM UIH and command sends, SDP client attribute requests, and SDP server responses to service search and service attribute requests.",
      "The bulletin rates the issue Critical / RCE. The material does not say which of the nine sites the researcher POC exercised."
     ],
     "per_major": {
      "14": "Not affected per the bulletin (not listed). At android-security-14.0.0_r29, 4/8 lines of the patched region are present.",
      "15": "Same fix: commit 806774b1cf64 in android-security-15.0.0_r5 (cherry-picked from internal 43cfd234de9b, Change-Id I6289907e86786eb2e10a163f7fb5d2557eab00bc). At android-security-15.0.0_r17 the code context shows all nine sites in fixed form, with a 7/8 line match of the patched region.",
      "16": "Not affected per the bulletin (not listed). At android-security-16.0.0_r8, 4/8 lines of the patched region are present.",
      "17": "Not affected per the bulletin (not listed). At android-security-17.0.0_r1, 4/8 lines of the patched region are present."
     },
     "backport_notes": [
      "The change is self-contained and local to each call site. Per index search, Android 15 at android-15.0.0_r36 calls L2CA_DataWrite through stack::l2cap::get_interface() and compares the result with tL2CAP_DW_RESULT::SUCCESS. On code like that, apply the same 'capture len before the call' pattern around the refactored call.",
      "Bluetooth is a mainline module, so the fix may also ship through module updates, independent of the platform security tag (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "Which of the nine sites the researcher POC targeted, and the exact condition under which the buffer is freed before the log statement.",
      "What the earlier companion commit implied by 'Fix more memory-unsafe logging' contains, and whether other L2CA_DataWrite callers still read the buffer after the call.",
      "The state of these sites on Android 14, 16 and 17. The bulletin does not list them, and only 4/8 lines of the patched region match.",
      "Why only 7/8 lines of the patched region match at android-security-15.0.0_r17."
     ],
     "meta": {
      "generated": "2026-10-03",
      "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-43090": {
     "cve": "CVE-2024-43090",
     "summary": "Removes the com.android.systemui.validate_keyboard_shortcut_helper_icon_uri flag gate so SystemUI's keyboard shortcut helper always calls KeyboardShortcuts.sanitiseShortcuts (which clears app/IME-provided icons) on shortcut groups received from apps and IMEs.",
     "component": "platform/frameworks/base, SystemUI keyboard shortcut helper (KeyboardShortcuts, KeyboardShortcutListSearch), plus core KeyboardShortcutInfo on Android 14",
     "weakness": "Icon objects supplied by apps and IMEs reached SystemUI's keyboard shortcut helper without sanitisation, because the sanitisation was conditional on a feature flag. The bulletin classifies it as information disclosure.",
     "root_cause": "The keyboard shortcut helper in SystemUI receives KeyboardShortcutGroup lists from apps and from the IME and adds them to its displayed groups, including each KeyboardShortcutInfo's Icon. On Android 15 the sanitisation step KeyboardShortcuts.sanitiseShortcuts only ran when the aconfig flag validateKeyboardShortcutHelperIconUri() returned true. On Android 14 that step was introduced by a fix that clears every app-provided icon through a new hidden KeyboardShortcutInfo.clearIcon(). With the flag off, icons supplied by apps and IMEs were kept unchanged. The flag name and the Android 14 commit title (\"Clear app-provided shortcut icons\") point to app-supplied icon URIs as the concern. The material does not describe the exact disclosure mechanism.",
     "fix_analysis": [
      "Android 14 (4677d3ee0ec2): core/java/android/view/KeyboardShortcutInfo.java makes mIcon non-final and adds a hidden clearIcon(). packages/SystemUI/.../KeyboardShortcuts.java adds a static sanitiseShortcuts(List<KeyboardShortcutGroup>) that goes through every group and item and calls info.clearIcon(). It is called in the KeyboardShortcuts onKeyboardShortcutsReceived callback before the system and default shortcuts are appended. It is also called in KeyboardShortcutListSearch before reMapToKeyboardShortcutMultiMappingGroup(result) for the app-specific group.",
      "Android 15 (f1a15b5ef253, this commit), packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java: in the two places that fill mReceivedAppShortcutGroups and mReceivedImeShortcutGroups, the `if (validateKeyboardShortcutHelperIconUri())` guard is removed. sanitiseShortcuts(...) now always runs before maybeMergeAndShowKeyboardShortcuts(). The static import of com.android.systemui.Flags.validateKeyboardShortcutHelperIconUri is dropped.",
      "Android 15, packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java: the same guard is removed in the app-specific path (before mSpecificAppGroup.addAll(reMapToKeyboardShortcutMultiMappingGroup(result))) and in the IME path (before mInputGroup.addAll(...)). The static Flags import is removed.",
      "Tests: KeyboardShortcutsTest and KeyboardShortcutListSearchTest drop the @EnableFlags(Flags.FLAG_VALIDATE_KEYBOARD_SHORTCUT_HELPER_ICON_URI) annotations from requestAppKeyboardShortcuts_callback_sanitisesIcons and requestImeKeyboardShortcuts_callback_sanitisesIcons, so these tests now check the default behaviour."
     ],
     "completeness": [
      "Covers all four ingestion points visible in the diff: the app and IME shortcut paths in both KeyboardShortcuts and KeyboardShortcutListSearch.",
      "The mitigation removes icons entirely instead of validating them, so every icon provided by an app or IME is dropped. This is judged from the Android 14 sanitiseShortcuts body; the Android 15 body is not shown in the material.",
      "The Android 14 commit adds the call only to the app-specific path of KeyboardShortcutListSearch and to one onKeyboardShortcutsReceived callback in KeyboardShortcuts. The material does not show whether a separate IME path existed on 14.",
      "The diff does not remove the aconfig flag declaration. The commit message says the flag check is removed, but the diff only touches Java usages."
     ],
     "behavior_changes": [
      "Icons supplied by apps and IMEs in KeyboardShortcutInfo are always cleared by the SystemUI keyboard shortcut helper, whatever the flag state.",
      "KeyboardShortcuts and KeyboardShortcutListSearch no longer read the validateKeyboardShortcutHelperIconUri flag, so flag configuration can no longer let icons through unsanitised.",
      "On Android 14, KeyboardShortcutInfo.mIcon becomes mutable and a hidden clearIcon() API is added."
     ],
     "preconditions": [
      "An app or IME supplies KeyboardShortcutGroup/KeyboardShortcutInfo entries that carry Icon objects, and SystemUI consumes them.",
      "The keyboard shortcut helper is opened (the tests use KeyboardShortcuts.toggle(context, deviceId)), so SystemUI requests the shortcuts.",
      "On Android 15 before this fix: the com.android.systemui.validate_keyboard_shortcut_helper_icon_uri flag evaluated false on the device."
     ],
     "per_major": {
      "14": "adapted fix: commit 4677d3ee0ec2 (android-security-14.0.0_r14) introduces KeyboardShortcutInfo.clearIcon() and KeyboardShortcuts.sanitiseShortcuts() and calls the method with no flag in KeyboardShortcuts.onKeyboardShortcutsReceived and in the KeyboardShortcutListSearch app-specific path. 8/8 patched lines are present at android-security-14.0.0_r29.",
      "15": "same fix: commit f1a15b5ef253 (android-security-15.0.0_r6) removes the validateKeyboardShortcutHelperIconUri() gate around the existing sanitiseShortcuts calls in both classes. 7/8 lines of the patched region are present at android-security-15.0.0_r17.",
      "16": "not affected: the bulletin does not list Android 16. 7/8 lines of the patched region are present at android-security-16.0.0_r8.",
      "17": "not affected: the bulletin does not list Android 17. The patched files (KeyboardShortcuts.java, KeyboardShortcutListSearch.java, KeyboardShortcutListSearchTest.java) are absent at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "For a branch without sanitiseShortcuts/clearIcon, port the Android 14 commit 4677d3ee0ec2 rather than this flag-removal commit. It needs both the core change (the hidden KeyboardShortcutInfo.clearIcon()) and the SystemUI call sites. Add the call wherever the branch receives app or IME shortcut lists; the Android 15 code has separate app and IME paths in each class.",
      "For a branch that already has the flag-gated calls, this commit only removes the guards. If the aconfig flag declaration is also deleted, make sure no reference to Flags.validateKeyboardShortcutHelperIconUri or FLAG_VALIDATE_KEYBOARD_SHORTCUT_HELPER_ICON_URI remains, because aconfig-generated Flags symbols disappear when the flag is removed (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not describe the exact disclosure mechanism (what an unsanitised app-provided Icon exposes in SystemUI).",
      "The body of KeyboardShortcuts.sanitiseShortcuts on Android 15 is not shown. It is assumed to match the Android 14 version.",
      "Whether the aconfig flag declaration was removed in the same change or a separate one.",
      "Whether Android 14 had an IME shortcut path that needed the same treatment.",
      "Which line of the patched region differs on 15.0.0_r17 and 16.0.0_r8.",
      "Where the keyboard shortcut helper code lives on Android 17."
     ],
     "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-43093": {
     "cve": "CVE-2024-43093",
     "summary": "ExternalStorageProvider now decides whether a document lies under Android/data, Android/obb or Android/sandbox by comparing the filesystem identity of the path and its parents with Files.isSameFile. It no longer uses a case-insensitive regex over the document-id path string.",
     "component": "platform/frameworks/base, packages/ExternalStorageProvider (the Storage Access Framework DocumentsProvider for external storage)",
     "weakness": "Improper access restriction: the path check matched the path string against a pattern instead of resolving the actual file",
     "root_cause": "In packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java, the check that restricts these subtrees took a path string from getPathFromDocId(documentId) and matched it against PATTERN_RESTRICTED_ANDROID_SUBTREES (\"^Android/(?:data|obb|sandbox)(?:/.+)?\", CASE_INSENSITIVE). The decision looked only at the text of the path. The commit message says the pattern match was replaced with a file equality check, which implies that some path strings not matching the regex could still refer to restricted locations. The material does not show the exact form of such a path.",
     "fix_analysis": [
      "ExternalStorageProvider.java, in the restriction method that used PATTERN_RESTRICTED_ANDROID_SUBTREES (its name is not visible in the diff hunk): the regex is removed. The method now gets the RootInfo from getRootFromDocId(documentId) and the path from getPathFromDocId(documentId), then returns isRestrictedPath(root.rootId, canonicalPath). Any exception makes it return true (restricted).",
      "ExternalStorageProvider.java:isRestrictedPath (new): returns true if rootId or canonicalPath is null. It builds rootPath as \"/storage/emulated/\" + UserHandle.myUserId() when rootId equalsIgnoreCase ROOT_ID_PRIMARY_EMULATED, and as \"/storage/\" + rootId otherwise. It then builds <rootPath>/Android/{data,obb,sandbox} and keeps only the paths for which Files.exists returns true.",
      "ExternalStorageProvider.java:isRestrictedPath: builds Paths.get(rootPath, canonicalPath) and walks that path and each getParent() up to the top, calling Files.isSameFile(restrictedPath, filePathToCheck) against each existing restricted directory. A match sets isRestricted = true and ends the walk. Any exception during the walk logs a warning and sets isRestricted = true (fails closed).",
      "Imports: java.util.regex.Pattern and CASE_INSENSITIVE removed; java.nio.file.Files, java.nio.file.Paths, java.util.Arrays and java.util.stream.Collectors added. Constants PRIMARY_EMULATED_STORAGE_PATH and STORAGE_PATH added."
     ],
     "completeness": [
      "Covers the single restriction method in ExternalStorageProvider. The check now depends on the filesystem identity (isSameFile) of the target and each of its parents, not on the text of the document id.",
      "Only Android/data, Android/obb and Android/sandbox are restricted. This is the same set of directories the regex covered.",
      "A restricted directory that does not exist on the volume (Files.exists returns false) is left out of the comparison list, so that directory is not restricted at check time.",
      "The root path is derived on the assumption that the primary emulated root is at /storage/emulated/<myUserId> and every other root is at /storage/<rootId>. For a root whose mount path does not follow these conventions, none of the candidate directories would exist, so this method would not restrict it. The material does not show which rootIds exist.",
      "Error paths (an exception from getRootFromDocId, a null rootId or path, I/O errors in isSameFile) fail closed: the document is treated as restricted.",
      "The commit changes only ExternalStorageProvider.java. No other providers and no superclass code are modified."
     ],
     "behavior_changes": [
      "Each run of the restriction check now does filesystem I/O (Files.exists on three directories, plus Files.isSameFile at each parent level) instead of an in-memory regex match.",
      "The case-insensitive text match is gone. Whether two paths are the same is now decided by what the filesystem reports through isSameFile.",
      "Any exception during root lookup, path derivation or the identity walk now causes the document to be treated as restricted.",
      "Two log lines are added: a verbose \"Restricting access for path: ...\" and a warning when the comparison fails."
     ],
     "preconditions": [
      "The caller uses the ExternalStorageProvider DocumentsProvider with a document id whose path is evaluated by the restriction check. The exact document-id shape involved is not shown in the material.",
      "The new check restricts a directory only if that directory exists on the volume (Files.exists filter)."
     ],
     "per_major": {
      "14": "Same fix: platform/frameworks/base 67d6e0832201 in android-security-14.0.0_r14, with the same diff (same blob indices) as the Android 15 commit. At android-security-14.0.0_r29, 7 of the 8 patched-region lines are present.",
      "15": "Same fix: platform/frameworks/base 7f83c671626f in android-security-15.0.0_r2 (cherry-pick, Change-Id I8879900e57e1702d11797b81e86d0cc3f55bac22). At android-security-15.0.0_r17, 7 of the 8 patched-region lines are present.",
      "16": "Not affected (not listed by the bulletin). At android-security-16.0.0_r8, 7 of the 8 patched-region lines are present.",
      "17": "Not affected (not listed by the bulletin). At android-security-17.0.0_r1, 7 of the 8 patched-region lines are present."
     },
     "backport_notes": [
      "Single-file, single-commit change that applied identically to Android 14 and 15. It uses getRootFromDocId, getPathFromDocId, RootInfo.rootId, ROOT_ID_PRIMARY_EMULATED and UserHandle.myUserId; check that these exist on the target branch. Also check that the root mount path assumptions (/storage/emulated/<user> and /storage/<rootId>) hold for the device's volumes."
     ],
     "confidence": "medium",
     "unknowns": [
      "The name of the modified method (the diff hunk header does not show it) and which DocumentsProvider entry points call it.",
      "The specific document-id form that got past the regex while referring to a restricted location.",
      "Whether Android 12, 12L and 13 received the same change or an adapted one (the bulletin lists them as affected, but no commit is provided).",
      "Which 1 of the 8 patched-region lines differs at the latest security tags, and why."
     ],
     "meta": {
      "generated": "2026-10-03",
      "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-49740": {
     "cve": "CVE-2024-49740",
     "summary": "Adds server-side enforcement in PhoneInterfaceManager that only the visual voicemail package (default dialer, system dialer or carrier VVM app, per commit message) may enable or disable the visual voicemail SMS filter, and adds length/size limits (256 chars per string, 100 list elements) to VisualVoicemailSmsFilterSettings.Builder.",
     "component": "platform/packages/services/Telephony (PhoneInterfaceManager, visual voicemail SMS filter) and platform/frameworks/base (telephony/java/android/telephony/VisualVoicemailSmsFilterSettings)",
     "weakness": "Missing authorization check on a Binder entry point combined with missing input size bounds (unbounded string/list in filter settings)",
     "root_cause": "ITelephony.enableVisualVoicemailSmsFilter and disableVisualVoicemailSmsFilter in PhoneInterfaceManager only verified that callingPackage belonged to the calling UID (mAppOps.checkPackage) and, on 15, that the device has FEATURE_TELEPHONY_CALLING. Per the commit message, the documented requirement that the caller be the default dialer was never enforced server side, so any app could pass VisualVoicemailSmsFilterSettings for itself to VisualVoicemailSmsFilterConfig.enableVisualVoicemailSmsFilter. In addition, VisualVoicemailSmsFilterSettings.Builder accepted a clientPrefix of any length and an originatingNumbers list of any size with elements of any length, so arbitrarily large settings could be handed to the phone process. The bulletin classifies the result as DoS.",
     "fix_analysis": [
      "packages/services/Telephony src/com/android/phone/PhoneInterfaceManager.java:enableVisualVoicemailSmsFilter: after mAppOps.checkPackage and enforceTelephonyFeatureWithException, adds enforceVisualVoicemailPackage(callingPackage, subId) before clearing the calling identity and calling VisualVoicemailSmsFilterConfig.enableVisualVoicemailSmsFilter. Per the commit message this verifies the caller is the default dialer, system dialer or carrier visual voicemail app; the body of enforceVisualVoicemailPackage is not in the material.",
      "packages/services/Telephony src/com/android/phone/PhoneInterfaceManager.java:disableVisualVoicemailSmsFilter: same enforceVisualVoicemailPackage(callingPackage, subId) call added before VisualVoicemailSmsFilterConfig.disableVisualVoicemailSmsFilter.",
      "frameworks/base telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java: adds @hide constants MAX_STRING_LENGTH = 256 and MAX_LIST_SIZE = 100.",
      "VisualVoicemailSmsFilterSettings.Builder.setClientPrefix: throws IllegalArgumentException when clientPrefix.length() > MAX_STRING_LENGTH (existing null check kept).",
      "VisualVoicemailSmsFilterSettings.Builder.setOriginatingNumbers: throws IllegalArgumentException when originatingNumbers.size() > MAX_LIST_SIZE, and when any non-null element has length() > MAX_STRING_LENGTH (existing null-list check kept). The list-size exception message text interpolates MAX_STRING_LENGTH (256) instead of MAX_LIST_SIZE (100); the check itself uses MAX_LIST_SIZE."
     ],
     "completeness": [
      "Both write entry points in PhoneInterfaceManager (enableVisualVoicemailSmsFilter, disableVisualVoicemailSmsFilter) gain the enforceVisualVoicemailPackage check; the read entry points getVisualVoicemailSmsFilterSettings (mAppOps.checkPackage only) and getActiveVisualVoicemailSmsFilterSettings (enforceReadPrivilegedPermission), per index search, are untouched, consistent with them not modifying state.",
      "The size limits are enforced only in the Builder setters (setClientPrefix, setOriginatingNumbers). The material does not show size validation in the Parcel CREATOR / constructor or in VisualVoicemailSmsFilterConfig; the new caller check restricts who may call but does not bound sizes.",
      "setOriginatingNumbers skips null elements (num != null), so null entries are still accepted in the list.",
      "mDestinationPort and mPackageName are not bounded by the change."
     ],
     "behavior_changes": [
      "VisualVoicemailSmsFilterSettings.Builder.setClientPrefix now throws IllegalArgumentException for prefixes longer than 256 characters (public API behavior change, documented with @throws).",
      "VisualVoicemailSmsFilterSettings.Builder.setOriginatingNumbers now throws IllegalArgumentException for lists with more than 100 elements or any element longer than 256 characters.",
      "ITelephony.enableVisualVoicemailSmsFilter / disableVisualVoicemailSmsFilter (reached via TelephonyManager.setVisualVoicemailSmsFilterSettings, enableVisualVoicemailSmsFilter, disableVisualVoicemailSmsFilter, per index search) now reject callers that are not the visual voicemail package via enforceVisualVoicemailPackage; the exact exception type is not shown in the material. The TelephonyManager wrappers only catch RemoteException and NullPointerException (per index search), so a SecurityException (if that is what is thrown) would propagate to the app."
     ],
     "preconditions": [
      "Caller is an installed app able to reach ITelephony via TelephonyManager.setVisualVoicemailSmsFilterSettings / enableVisualVoicemailSmsFilter / disableVisualVoicemailSmsFilter (per index search); before the fix only mAppOps.checkPackage (callingPackage matches calling UID) and, on 15, FEATURE_TELEPHONY_CALLING were required.",
      "Device has telephony (FEATURE_TELEPHONY_CALLING on 15; the 14 code has no feature check in the patched region).",
      "For the size-limit part: the pre-fix Builder accepted any length clientPrefix and any size originatingNumbers list."
     ],
     "per_major": {
      "14": "adapted fix: platform/packages/services/Telephony 095be0bb467e in android-security-14.0.0_r16 adds enforceVisualVoicemailPackage(callingPackage, subId) to enableVisualVoicemailSmsFilter directly after mAppOps.checkPackage (the 14 code has no enforceTelephonyFeatureWithException line). The shown diff covers only the enable hunk; whether disableVisualVoicemailSmsFilter and the frameworks/base Builder limits were also applied on 14 is not shown. 5/5 patched lines present at android-security-14.0.0_r29.",
      "15": "same fix: platform/packages/services/Telephony b1ab472f0f56 and platform/frameworks/base bcb1316835dc in android-security-15.0.0_r4; 8/8 patched lines present at android-security-15.0.0_r17.",
      "16": "not affected (not listed by the bulletin); 8/8 lines of the patched region present at android-security-16.0.0_r8.",
      "17": "not affected (not listed by the bulletin); 8/8 lines of the patched region present at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Two commits in two projects linked by the same bug (Telephony PhoneInterfaceManager caller check; frameworks/base Builder limits); no code dependency between them is visible in the diffs. On branches without enforceTelephonyFeatureWithException (as on 14), the call goes right after mAppOps.checkPackage; confirm enforceVisualVoicemailPackage exists in the target PhoneInterfaceManager and that both enable and disable are covered.",
      "The frameworks/base change adds new IllegalArgumentException paths to public Builder setters; callers passing oversized values will now fail."
     ],
     "confidence": "medium",
     "unknowns": [
      "Body of enforceVisualVoicemailPackage (exact check and exception type) is not in the material.",
      "How VisualVoicemailSmsFilterConfig stores the settings and what exactly causes the DoS with oversized or unauthorized settings is not shown.",
      "Whether the frameworks/base Builder-limit commit and the disableVisualVoicemailSmsFilter hunk were applied on Android 14 (only the enable hunk of 095be0bb467e is shown).",
      "Whether the Parcel CREATOR / constructor of VisualVoicemailSmsFilterSettings or VisualVoicemailSmsFilterConfig validates sizes (not shown).",
      "Commits for Android 12/12L/13, which the bulletin lists as affected, are not in the material."
     ],
     "meta": {
      "generated": "2026-10-03",
      "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-2025-0078": {
     "cve": "CVE-2025-0078",
     "summary": "servicemanager now calls setRequestingSid(true) on its own ServiceManager object before self-registering it as the \"manager\" service, so the self-registered object has the flag set consistently with its use as the context object.",
     "component": "platform/frameworks/native, cmds/servicemanager (binder servicemanager)",
     "weakness": "Missing security attribute on a binder object: the requesting-SID flag was not set on the self-registered servicemanager object",
     "root_cause": "In cmds/servicemanager/main.cpp, main() creates the ServiceManager object (sp<ServiceManager>::make(std::make_unique<Access>())) and registers it with itself under the name \"manager\" via addService(). After that, it installs the object as the context object (IPCThreadState::self()->setTheContextObject(manager) and ps->becomeContextManager()). The commit message says SM has special flags set to become a context object, but these flags were not set when it registered as itself. The fix shows that the missing flag is requesting-SID: before the fix, the object was registered under \"manager\" without setRequestingSid(true).",
     "fix_analysis": [
      "cmds/servicemanager/main.cpp:main(): adds one line, manager->setRequestingSid(true);, right after the ServiceManager is constructed and before manager->addService(\"manager\", manager, ...). This sets the flag on the object before it is first registered. No other file is changed (diffstat: 1 file, 1 insertion)."
     ],
     "completeness": [
      "The fix covers the self-registration site in main.cpp. The flag is now set once on the object before both the addService(\"manager\", ...) call and the setTheContextObject call.",
      "The fix does not change Access or ServiceManager logic. The material does not show how those components treat a transaction with no SID.",
      "main.cpp contains a VENDORSERVICEMANAGER ifdef, which suggests the file is also built for vndservicemanager. If so, the change applies there too, but the build files are not in the material."
     ],
     "behavior_changes": [
      "The servicemanager object registered under \"manager\" now has requesting-SID set from before its registration.",
      "There are no new error codes or API changes in the diff. The commit was tested with 'boot w/ harsher checks'."
     ],
     "preconditions": [
      "A binder client reaches servicemanager through its self-registration under the name \"manager\". servicemanager must have self-registered successfully at boot; main.cpp logs an error if it did not.",
      "Setting requesting-SID on a BBinder makes the binder driver attach the sender's security context to incoming transactions for that node (general platform knowledge)."
     ],
     "per_major": {
      "12": "Listed as affected by the bulletin. The material includes no fix commit for 12/12L; status unknown.",
      "13": "Listed as affected by the bulletin. The material includes no fix commit for 13; status unknown.",
      "14": "Same fix: the same one-line addition of manager->setRequestingSid(true) in cmds/servicemanager/main.cpp (commit 1114faa38da8, android-security-14.0.0_r18). The patched region is fully present at android-security-14.0.0_r29.",
      "15": "Same fix: commit c32d4defe0f4 in android-security-15.0.0_r6 (cherry-pick of internal f7e88ce3). The patched region is fully present at android-security-15.0.0_r17.",
      "16": "Not affected per the bulletin. The patched region is present (4/4 lines) at android-security-16.0.0_r8.",
      "17": "Not affected per the bulletin. The patched region is present (4/4 lines) at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "This is a single-line change with no dependencies: insert manager->setRequestingSid(true); between the sp<ServiceManager>::make(...) call and the addService(\"manager\", ...) call in cmds/servicemanager/main.cpp. The added line is the same on 14 and 15, but the surrounding context differs: 15 has disableBackgroundScheduling(true) just before it, while the 14 hunk context shows setCallRestriction."
     ],
     "confidence": "medium",
     "unknowns": [
      "How ServiceManager/Access evaluate a transaction with no caller SID. Access.cpp and ServiceManager.cpp are not in the material, so the exact privilege that could be gained is also unknown.",
      "Which other flags, if any, the context-object path sets.",
      "Whether and how the fix was applied to Android 12, 12L and 13. The bulletin lists them as affected, but the material includes no commit for them.",
      "Whether vndservicemanager is built from the same main.cpp (build files are not shown)."
     ],
     "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-2025-0079": {
     "cve": "CVE-2025-0079",
     "summary": "Adds the encryption requirement (BTA_SEC_ENCRYPT / BTM_SEC_OUT_ENCRYPT) to the L2CAP security mask used when registering and when opening the AVCTP control, AVCTP browsing and AVDTP PSMs. These channels now require encryption as well as authentication.",
     "component": "platform/packages/modules/Bluetooth, system/stack/avct (AVCTP) and system/stack/avdt (AVDTP) L2CAP channel setup",
     "weakness": "Missing link-encryption requirement on L2CAP channels (authentication required but encryption not requested)",
     "root_cause": "AVCT_Register registered AVCT_PSM (0x0017) and AVCT_BR_PSM (0x001b), and AVDT_Register registered AVDT_PSM (0x0019), with the L2CAP security mask set to BTA_SEC_AUTHENTICATE only. The outgoing connect requests in avct_lcb_chnl_open and avct_bcb_chnl_open (BTA_SEC_AUTHENTICATE) and in avdt_ad_open_req (BTM_SEC_OUT_AUTHENTICATE) also asked only for authentication. Encryption was therefore never requested for AVDTP/AVCTP channels. The bulletin rates this as a High severity EoP.",
     "fix_analysis": [
      "system/stack/avct/avct_api.cc:AVCT_Register: introduces `uint16_t sec = BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT` and passes it to both L2CA_RegisterWithSecurity calls (AVCT_PSM with avct_l2c_appl, AVCT_BR_PSM with avct_l2c_br_appl).",
      "system/stack/avct/avct_lcb_act.cc:avct_lcb_chnl_open: outgoing L2CA_ConnectReqWithSecurity(AVCT_PSM, ...) now requests BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT.",
      "system/stack/avct/avct_bcb_act.cc:avct_bcb_chnl_open: outgoing L2CA_ConnectReqWithSecurity(AVCT_BR_PSM, ...) now requests BTA_SEC_AUTHENTICATE | BTA_SEC_ENCRYPT.",
      "system/stack/avdt/avdt_api.cc:AVDT_Register: introduces the same `sec` mask and passes it to L2CA_RegisterWithSecurity(AVDT_PSM, avdt_l2c_appl, ...).",
      "system/stack/avdt/avdt_ad.cc:avdt_ad_open_req: outgoing L2CA_ConnectReqWithSecurity(AVDT_PSM, ...) in the initiator branch now requests BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT.",
      "No logic is changed; only the security-requirement argument given to L2CAP is widened. Enforcement of the new mask is left to existing L2CAP/BTM code, which the material does not show."
     ],
     "completeness": [
      "Covers registration (AVCT_Register, AVDT_Register) and outgoing connect requests (avct_lcb_chnl_open, avct_bcb_chnl_open, avdt_ad_open_req) for all three PSMs.",
      "In the AVDT acceptor role (role == AVDT_ACP in avdt_ad_open_req) no connect request is issued, so that path depends on the registration mask set in AVDT_Register, which the fix updates.",
      "The AVDT outgoing path uses BTM_SEC_OUT_* constants while registration uses BTA_SEC_* constants. Their definitions and how L2CAP maps them are not shown.",
      "Only the AVCTP and AVDTP stack files are changed; the material shows nothing about other profile PSM registrations."
     ],
     "behavior_changes": [
      "AVDTP and AVCTP (control and browsing) L2CAP registrations and outgoing connect requests now include the encryption flag in addition to authentication. How a peer without an encrypted link is handled depends on L2CAP/BTM enforcement, which the material does not show.",
      "If L2CA_ConnectReqWithSecurity returns lcid 0, the existing immediate failure paths are taken (AVCT_LCB_LL_CLOSE_EVT in avct_*_chnl_open, avdt_ad_tc_close_ind in avdt_ad_open_req). The material does not show how a later security failure is reported."
     ],
     "preconditions": [
      "A remote Bluetooth device that connects to, or is connected by, the local AVDTP (PSM 0x0019) or AVCTP (PSM 0x0017 / 0x001b) services.",
      "Before the fix, only authentication was requested for these channels.",
      "AVCT_Register and AVDT_Register are registration functions; their callers are not shown in the material."
     ],
     "per_major": {
      "14": "adapted fix: commit 6893799a69f2 in android-security-14.0.0_r18 makes the same security-mask change, against the older API names L2CA_Register2 / L2CA_ConnectReq2 (and UNUSED_ATTR signatures). 7/8 patched lines present at android-security-14.0.0_r29.",
      "15": "same fix: commit b1e6d8d1e393 in android-security-15.0.0_r6 using L2CA_RegisterWithSecurity / L2CA_ConnectReqWithSecurity. Code at android-security-15.0.0_r17 shows the `sec` mask and the OR'd ENCRYPT flags at all six changed call sites in the five files (7/8 lines reported present).",
      "16": "not affected (not listed by the bulletin); 4/8 patched-region lines present at android-security-16.0.0_r8. The 16 code is not shown.",
      "17": "not affected (not listed by the bulletin); 4/8 patched-region lines present at android-security-17.0.0_r1. The 17 code is not shown."
     },
     "backport_notes": [
      "The change only touches the security-mask argument. Android 14 uses L2CA_Register2 / L2CA_ConnectReq2 (see the 14 commit). At android-15.0.0_r36 the calls go through stack::l2cap::get_interface() with BT_PSM_AVCTP / BT_PSM_AVCTP_BROWSE constants (per index search). Match on the call sites rather than on literal lines.",
      "Update both the PSM registration sites and the outgoing connect-request sites for all three PSMs."
     ],
     "confidence": "high",
     "unknowns": [
      "The concrete EoP consequence the bulletin refers to is not described in the material.",
      "Definitions of BTA_SEC_ENCRYPT vs BTM_SEC_OUT_ENCRYPT and how L2CAP/BTM enforce the mask are not shown.",
      "How an asynchronous security failure on an outgoing channel is reported to AVCT/AVDT is not shown.",
      "Whether Android 12, 12L and 13 (listed as affected) received the same change is not shown in the material.",
      "Exact content of the patched regions at the Android 16 and 17 security tags is not shown; only line-match counts are given."
     ],
     "meta": {
      "generated": "2026-10-03",
      "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-2025-0080": {
     "cve": "CVE-2025-0080",
     "summary": "The fix hardens the PackageInstaller unarchive confirmation UI against overlays in two ways: it adds SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS to UnarchiveActivity's window, and it disables the dialog's Restore button whenever UnarchiveFragment is paused, then re-enables it on resume.",
     "component": "platform/frameworks/base, packages/PackageInstaller (app unarchive / restore flow: UnarchiveActivity, UnarchiveFragment)",
     "weakness": "Missing protection of a security-sensitive confirmation dialog against overlay windows (UI redress / tapjacking class). There was no overlay-hiding window flag, and the confirm action was not disabled while another window was on top.",
     "root_cause": "UnarchiveActivity displayed the UnarchiveFragment AlertDialog (title built from APP_TITLE/INSTALLER_TITLE, positive button R.string.restore, negative button cancel) without setting SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS on its window. Non-system overlays could therefore be shown over the restore confirmation. The fragment also kept the Restore button enabled even when another window was shown on top of PackageInstaller.",
     "fix_analysis": [
      "packages/PackageInstaller/src/com/android/packageinstaller/UnarchiveActivity.java:onCreate calls getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) before super.onCreate(null), so non-system overlay windows are hidden while the unarchive activity is showing. It adds a new static import of WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS.",
      "packages/PackageInstaller/src/com/android/packageinstaller/UnarchiveFragment.java:onCreateDialog stores the created AlertDialog in a new field, mDialog, instead of returning it directly.",
      "packages/PackageInstaller/src/com/android/packageinstaller/UnarchiveFragment.java:onStart (new): after super.onStart(), if mDialog != null, it stores ((AlertDialog) mDialog).getButton(DialogInterface.BUTTON_POSITIVE) in a new field, mRestoreButton.",
      "packages/PackageInstaller/src/com/android/packageinstaller/UnarchiveFragment.java:onPause (new): after super.onPause(), it calls mRestoreButton.setEnabled(false) when the field is non-null, so Restore cannot be triggered while another window is shown on top.",
      "packages/PackageInstaller/src/com/android/packageinstaller/UnarchiveFragment.java:onResume (new): after super.onResume(), it calls mRestoreButton.setEnabled(true) when the field is non-null."
     ],
     "completeness": [
      "Covers the UnarchiveActivity window (overlay-hiding flag) and the positive Restore button of UnarchiveFragment (disabled while paused).",
      "Only the positive button (BUTTON_POSITIVE) is disabled while paused. The negative Cancel button stays enabled, which looks like a deliberate scope choice since Cancel is the non-privileged action.",
      "SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS hides non-system overlays only (general platform knowledge).",
      "The fix does not add touch filtering (for example filterTouchesWhenObscured) to the dialog. Protection relies on the window flag plus pause/resume gating."
     ],
     "behavior_changes": [
      "While UnarchiveActivity is visible, non-system overlay windows are hidden.",
      "The Restore button in the unarchive dialog is disabled whenever the fragment is paused (another window shown on top) and re-enabled on resume.",
      "No API change is visible in the diff. The commit names CtsPackageUninstallTestCases:ArchiveTest as its test."
     ],
     "preconditions": [
      "A build that includes the PackageInstaller unarchive flow (UnarchiveActivity/UnarchiveFragment). These files are absent at android-security-14.0.0_r29.",
      "UnarchiveActivity is launched for an archived package (its onCreate reads getLaunchedFromUid()) and the Restore confirmation dialog is displayed.",
      "A non-system window is shown on top of the UnarchiveActivity dialog. The exact trigger and the resulting privilege gain are not described in the material."
     ],
     "per_major": {
      "14": "not affected: not listed by the bulletin. At android-security-14.0.0_r29 both patched files (UnarchiveActivity.java, UnarchiveFragment.java) are absent.",
      "15": "same fix: commit 5916a3de10fa in android-security-15.0.0_r6 (cherry-pick of 799842233276351680f47420d8754f381dcbf86f, Change-Id If750c0a613136f3ad3040c544bd70ab428fe5ef2). 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, 8/8 lines of the patched region are present.",
      "17": "not affected: not listed by the bulletin. At android-security-17.0.0_r1, 8/8 lines of the patched region are present."
     },
     "backport_notes": [
      "A single self-contained commit touching two files in packages/PackageInstaller. It only applies to branches that already contain UnarchiveActivity/UnarchiveFragment. SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS is a hidden/system API that platform-built apps can use (general platform knowledge)."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not describe the concrete attack scenario, which overlay type was abused, or what privilege is gained. The bulletin only rates it High / EoP.",
      "Whether the ArchiveTest CTS coverage includes an overlay regression test is not shown.",
      "Whether mRestoreButton could remain null in some lifecycle path (for example fragment recreation), which would silently skip the pause gating, is not shown.",
      "Whether other PackageInstaller confirmation dialogs received equivalent hardening in separate commits is not shown."
     ],
     "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-2025-0082": {
     "cve": "CVE-2025-0082",
     "summary": "Replaces the Uri.getEncodedUserInfo()-based cross-user check on URI-type icons in StatusHints and TelecomServiceImpl with a new StatusHints.getUserIdFromAuthority() helper that derives the user id from the URI authority (text before the last '@'), so icons whose user id does not match, or cannot be parsed to, the calling user are dropped (StatusHints) or rejected (TelecomServiceImpl).",
     "component": "platform/frameworks/base (telecomm/java/android/telecom/StatusHints.java) and platform/packages/services/Telecomm (TelecomServiceImpl), Telecom phone account / status hint icon validation",
     "weakness": "Improper input validation / bypass of a user-boundary check through a percent-encoded URI authority (parser mismatch between encoded user info and decoded authority)",
     "root_cause": "The URI-icon user-boundary checks in StatusHints (frameworks/base) and TelecomServiceImpl (Telecomm) decided whether a URI-type icon (Icon.TYPE_URI or TYPE_URI_ADAPTIVE_BITMAP) belonged to the calling user by reading icon.getUri().getEncodedUserInfo(). If that returned null, the code assumed the URI targeted the calling user and accepted it. The commit message says a URI formatted as `userId%` is not parsed properly by Uri.encodedUserInfo. The new tests show the case: an authority with a percent-encoded separator (\"10%40media\", \"content://10%40play.ground\") must now be rejected, so the old check missed the foreign user id. The old code also called Integer.parseInt on the raw string without handling NumberFormatException.",
     "fix_analysis": [
      "frameworks/base, telecomm/java/android/telecom/StatusHints.java: adds public @hide static getUserIdFromAuthority(String auth, int defaultUserId). It returns defaultUserId when auth is null or has no '@'. Otherwise it parses auth.substring(0, lastIndexOf('@')) with Integer.parseInt(). On NumberFormatException it logs a warning and returns UserHandle.USER_NULL, so the caller's equality check fails.",
      "frameworks/base, StatusHints URI-icon check: for URI-type icons, computes requestingUserId = getUserIdFromAuthority(icon.getUri().getAuthority(), callingUserId) and returns null (drops the icon) if it differs from callingUserHandle.getIdentifier().",
      "Telecomm, src/com/android/server/telecom/TelecomServiceImpl.java URI-icon check: same replacement. callingUserId now comes from UserHandle.getCallingUserId(), and a mismatch still throws IllegalArgumentException(\"Attempting to register a phone account with an image icon belonging to another user.\"). The file now imports android.telecom.StatusHints.",
      "Telecomm, tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java testRegisterPhoneAccountImageIconCrossUser: adds negative cases for encodedAuthority(\"10%40media\") and Uri.parse(\"content://10%40play.ground\") and keeps the positive case \"content://0@media/...\"."
     ],
     "completeness": [
      "Both validation sites named in the commit message (StatusHints and TelecomServiceImpl) are updated and use one shared helper.",
      "The helper takes everything before the last '@' in the authority as the user id. A prefix that does not parse as an integer yields USER_NULL and is rejected instead of throwing NumberFormatException.",
      "Only icons of type TYPE_URI and TYPE_URI_ADAPTIVE_BITMAP are inspected; other Icon types are outside the check, as before."
     ],
     "behavior_changes": [
      "Icon URIs whose authority has a user prefix (text before the last '@') that is not the calling user are now rejected, including the percent-encoded test cases. StatusHints drops the icon (returns null); TelecomServiceImpl throws IllegalArgumentException during phone account registration.",
      "Icon URIs with a non-integer user prefix before '@' are now rejected (USER_NULL mismatch) instead of hitting an unhandled NumberFormatException.",
      "A new warning log line \"Error parsing userId.\" with tag StatusHints is emitted on parse failure.",
      "A new public @hide static API StatusHints.getUserIdFromAuthority(String, int) is added to the framework."
     ],
     "preconditions": [
      "The caller supplies a PhoneAccount with a URI-type Icon (TYPE_URI or TYPE_URI_ADAPTIVE_BITMAP) to TelecomServiceImpl.registerPhoneAccount, or supplies StatusHints with such an icon.",
      "The icon URI's authority carries another user's id in a form that Uri.getEncodedUserInfo() did not report (for example a percent-encoded separator, as in the tests).",
      "The material does not show whether the real service requires extra permissions for registration (the unit test grants MODIFY_PHONE_STATE)."
     ],
     "per_major": {
      "14": "same fix: Telecomm e1a0858925cb in android-security-14.0.0_r18 applies the same TelecomServiceImpl and test change (hunk at old line 3150 instead of 3421); 8/8 lines present at android-security-14.0.0_r29. It depends on the frameworks/base StatusHints.getUserIdFromAuthority helper, but the 14 commit for that helper is not shown in the material.",
      "15": "same fix: frameworks/base 7ba8c8f63f1b plus Telecomm 685c2fc2f6b4 in android-security-15.0.0_r6; 8/8 lines present at android-security-15.0.0_r17.",
      "16": "not affected (not listed by the bulletin); the patched region is present (8/8 lines) at android-security-16.0.0_r8.",
      "17": "not affected (not listed by the bulletin); telecomm/java/android/telecom/StatusHints.java is absent at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "Two-repo fix with a build dependency: apply the frameworks/base StatusHints commit (adds getUserIdFromAuthority) before the Telecomm commit, which imports android.telecom.StatusHints and calls the new static helper.",
      "If a tree cannot take the framework change, the Telecomm side would need the same parse logic inlined (getAuthority(), lastIndexOf('@'), parseInt with NumberFormatException mapped to USER_NULL); keep both sites consistent."
     ],
     "confidence": "high",
     "unknowns": [
      "The frameworks/base counterpart commit for Android 14 (and for 12/12L/13) is not shown in the material.",
      "Where, if anywhere, StatusHints.java and the helper live on Android 17.",
      "Whether other consumers of icon URIs need the same change; the material does not cover them.",
      "Which downstream component would have loaded the cross-user icon URI (the disclosure sink) is not shown."
     ],
     "meta": {
      "generated": "2026-10-03",
      "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-2025-0083": {
     "cve": "CVE-2025-0083",
     "summary": "Replaces the Uri.getEncodedUserInfo()-based cross-user check on URI-type icons in StatusHints and TelecomServiceImpl (phone account registration) with a new shared helper StatusHints.getUserIdFromAuthority that derives the user id from the authority and rejects unparsable or mismatching user ids.",
     "component": "platform/frameworks/base (telecomm/java/android/telecom/StatusHints.java) and platform/packages/services/Telecomm (TelecomServiceImpl), Telecom icon user-boundary validation",
     "weakness": "Improper input validation / parser differential in a cross-user authorization check (user id in content URI authority not canonically parsed)",
     "root_cause": "Both StatusHints (icon validation helper) and TelecomServiceImpl (icon check during phone account registration) determined the target user of a TYPE_URI / TYPE_URI_ADAPTIVE_BITMAP icon by calling icon.getUri().getEncodedUserInfo() and only compared it to the calling user when it was non-null. The commit message states that a URI formatted as `userId%` isn't parsed properly by Uri.encodedUserInfo; the new tests show this with an authority using a percent-encoded '@' (\"10%40media\", \"10%40play.ground\"), which the old check let through as if it belonged to the calling user. Additionally, the old code called Integer.parseInt on the user info without catching NumberFormatException.",
     "fix_analysis": [
      "frameworks/base, telecomm/java/android/telecom/StatusHints.java: adds public static int getUserIdFromAuthority(String auth, int defaultUserId) (@hide). Returns defaultUserId if auth is null or contains no '@'; otherwise takes auth.substring(0, auth.lastIndexOf('@')) and Integer.parseInt it; on NumberFormatException logs a warning (new TAG, android.util.Log import) and returns UserHandle.USER_NULL.",
      "frameworks/base, StatusHints.java icon validation method (hunk around line 150): for URI-type icons, computes callingUserId = callingUserHandle.getIdentifier() and requestingUserId = getUserIdFromAuthority(icon.getUri().getAuthority(), callingUserId); returns null (drops the icon) when they differ. getAuthority() returns the decoded authority (general platform knowledge), so a percent-encoded '@' is handled, and the previous null-skip branch is gone.",
      "packages/services/Telecomm, src/com/android/server/telecom/TelecomServiceImpl.java (phone account icon check, hunk around line 3421): imports android.telecom.StatusHints, computes callingUserId = UserHandle.getCallingUserId() and requestingUserId = StatusHints.getUserIdFromAuthority(icon.getUri().getAuthority(), callingUserId); throws IllegalArgumentException(\"Attempting to register a phone account with an image icon belonging to another user.\") when they differ.",
      "packages/services/Telecomm, tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java testRegisterPhoneAccountImageIconCrossUser: adds two negative cases, encodedAuthority(\"10%40media\") and Uri.parse(\"content://10%40play.ground\"), and keeps the positive case content://0@media/."
     ],
     "completeness": [
      "Both validation sites named in the commit message (StatusHints and TelecomServiceImpl registration path) are converted to the same helper, so the parsing logic is now single-sourced.",
      "Only Icon.TYPE_URI and Icon.TYPE_URI_ADAPTIVE_BITMAP are inspected; other icon types are unchanged.",
      "The helper parses the authority with lastIndexOf('@'); a user prefix that is not an integer now maps to USER_NULL and is rejected rather than throwing NumberFormatException. A missing '@' maps to the calling user.",
      "The helper does not validate the host/provider portion of the authority or the path; it only addresses which user the URI targets."
     ],
     "behavior_changes": [
      "URI icons whose authority encodes another user's id via percent-encoded '@' are now rejected (StatusHints: icon dropped to null; TelecomServiceImpl: IllegalArgumentException on registration).",
      "A non-numeric user prefix before '@' now results in rejection plus a Log.w with tag \"StatusHints\" and message \"Error parsing userId.\" instead of a NumberFormatException.",
      "TelecomServiceImpl now uses UserHandle.getCallingUserId() instead of UserHandle.getUserId(Binder.getCallingUid()) (equivalent value, general platform knowledge).",
      "New hidden public static method StatusHints.getUserIdFromAuthority in the framework."
     ],
     "preconditions": [
      "A caller supplies a PhoneAccount with a URI-type Icon to TelecomServiceImpl.registerPhoneAccount (the test grants MODIFY_PHONE_STATE for this path), or supplies StatusHints carrying a URI-type Icon that is validated through the StatusHints helper.",
      "The icon URI authority names a user other than the calling user in a form that Uri.getEncodedUserInfo() did not surface (percent-encoded separator).",
      "Multi-user / profile device with another user id to target; what is disclosed from the other user's content is not shown in the material."
     ],
     "per_major": {
      "14": "same fix: platform/packages/services/Telecomm e1a0858925cb in android-security-14.0.0_r18 (identical TelecomServiceImpl and test change, different line offsets, 3150 vs 3421); 8/8 patched lines present at android-security-14.0.0_r29. The matching frameworks/base StatusHints commit for 14 is not shown in the material but is needed since the Telecomm change calls StatusHints.getUserIdFromAuthority.",
      "15": "same fix: frameworks/base 7ba8c8f63f1b and Telecomm 685c2fc2f6b4 in android-security-15.0.0_r6; 8/8 patched lines present 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; telecomm/java/android/telecom/StatusHints.java is absent at that path at android-security-17.0.0_r1, status of the code at any new location not shown."
     },
     "backport_notes": [
      "Two-repo fix with a dependency: the Telecomm change calls the new StatusHints.getUserIdFromAuthority, so the frameworks/base StatusHints commit must land first (or together). Both carry Flag: EXEMPT bugfix.",
      "If the framework change cannot be taken, the same logic can be inlined in TelecomServiceImpl, but keep both sites consistent (getAuthority(), lastIndexOf('@'), USER_NULL on parse failure)."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact name of the StatusHints validation method and of the TelecomServiceImpl method containing the check (hunk headers show only the class).",
      "Which Android 14 frameworks/base commit carries the StatusHints half of the fix.",
      "What data from the other user's content provider was observable via the icon (the bulletin only rates it High / ID).",
      "Whether the StatusHints helper is reached from other callers beyond phone account registration (index search returned no relevant results)."
     ],
     "meta": {
      "generated": "2026-10-03",
      "author_model": "claude-fable-5-1",
      "review_model": "claude-opus-5-5",
      "review_corrections": 1,
      "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-2025-0086": {
     "cve": "CVE-2025-0086",
     "summary": "AccountManagerService now rejects a getAuthToken response from an AbstractAccountAuthenticator whose KEY_ACCOUNT_TYPE does not match the session's own account type (mAccountType), returning ERROR_CODE_INVALID_RESPONSE instead of storing the token.",
     "component": "platform/frameworks/base, services/core accounts (AccountManagerService)",
     "weakness": "Missing validation of authenticator-supplied data (account type in the getAuthToken response not checked against the authenticator's own type)",
     "root_cause": "In the getAuthToken Session.onResult(Bundle result) in AccountManagerService.java, when the response contained KEY_AUTHTOKEN, the service read KEY_ACCOUNT_NAME and KEY_ACCOUNT_TYPE from the authenticator's Bundle and only checked that they were non-empty. It then built Account(name, type) and, when customTokens is false, called saveAuthTokenToDatabase(mAccounts, resultAccount, authTokenType, authToken). The account type was never compared against the type the session already knew (mAccountType), so an authenticator could cause an auth token to be written against an account of a different account type than its own.",
     "fix_analysis": [
      "services/core/java/com/android/server/accounts/AccountManagerService.java, getAuthToken Session.onResult(Bundle): after the existing TextUtils.isEmpty(type)/isEmpty(name) check, the fix adds `if (!type.equals(mAccountType))`. This calls onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, \"incorrect account type\") and returns before Account resultAccount is constructed and before saveAuthTokenToDatabase / saveCachedToken run.",
      "Single-commit fix (Change-Id Ifc62866f4feaca43abc32bc542b97f3741953f56) with 6 added lines and no other files touched. The commit message says the name/type keys in the response look unnecessary, but the API cannot be changed at this moment."
     ],
     "completeness": [
      "Covers only the account type: the returned KEY_ACCOUNT_TYPE must equal mAccountType, so the token can no longer be stored under another authenticator's account type via the non-customTokens saveAuthTokenToDatabase path.",
      "The returned KEY_ACCOUNT_NAME is still not compared against the requested account.name. resultAccount can still name a different account as long as it is of the authenticator's own type (the context shows Account resultAccount = new Account(name, type) is unchanged).",
      "Only the getAuthToken session's onResult is modified. Other authenticator callbacks that return KEY_ACCOUNT_NAME/KEY_ACCOUNT_TYPE bundles are not in the provided material, so their handling is unknown.",
      "The saveCachedToken (customTokens) path already used the original `account`, not resultAccount, and is not changed."
     ],
     "behavior_changes": [
      "A getAuthToken response that carries an auth token with a KEY_ACCOUNT_TYPE different from the authenticator's type now fails with AccountManager.ERROR_CODE_INVALID_RESPONSE (\"incorrect account type\") instead of succeeding. The token is not saved, and the session reports the error through onError."
     ],
     "preconditions": [
      "An installed account authenticator (AbstractAccountAuthenticator implementation) handles a getAuthToken request and returns a Bundle containing KEY_AUTHTOKEN together with a KEY_ACCOUNT_TYPE that is not its own type.",
      "Storage into the accounts database happens on the non-customTokens path (saveAuthTokenToDatabase). The check now runs before both the database and cached-token paths."
     ],
     "per_major": {
      "14": "same fix: platform/frameworks/base b6dcda18039c in android-security-14.0.0_r18, an identical 6-line hunk at a different offset (line 3124). 4/4 patched lines are present at android-security-14.0.0_r29.",
      "15": "same fix: platform/frameworks/base c1aa9e662464 in android-security-15.0.0_r6. 4/4 patched lines are present at android-security-15.0.0_r17.",
      "16": "not affected (the bulletin does not list it). The patched region is present 4/4 at android-security-16.0.0_r8.",
      "17": "not affected (the bulletin does not list it). The patched region is present 4/4 at android-security-17.0.0_r1."
     },
     "backport_notes": [
      "The hunk is self-contained. It relies only on the Session field mAccountType and on the existing name/type emptiness check immediately above it in the getAuthToken onResult, so apply it directly after that check. Line offsets differ per branch (3124 on 14, 3190 on 15)."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show how Android 12, 12L and 13 (listed as affected) were patched.",
      "The material does not show whether other authenticator response paths in AccountManagerService validate KEY_ACCOUNT_TYPE, nor whether a mismatched KEY_ACCOUNT_NAME is handled elsewhere.",
      "No test accompanies the change (Test: manual)."
     ],
     "meta": {
      "generated": "2026-10-03",
      "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-2025-0092": {
     "cve": "CVE-2025-0092",
     "summary": "When a remote device transitions to BOND_NONE, the Bluetooth stack now resets that device's Message Access (MAP), Phonebook Access (PBAP) and SIM Access permissions to ACCESS_UNKNOWN, so previously granted access does not survive unbonding.",
     "component": "platform/packages/modules/Bluetooth, btservice (AdapterService / BondStateMachine bond-state handling; affects PBAP, MAP, SAP profile permissions)",
     "weakness": "Missing revocation of per-device access permissions on state change (stale authorization persisting after unbond)",
     "root_cause": "The per-device MAP, PBAP and SIM access permissions managed by AdapterService (setMessageAccessPermission, setPhonebookAccessPermission, setSimAccessPermission) were not cleared when a device's bond state changed to BOND_NONE. A permission granted while a device was bonded therefore stayed in effect after the bond was removed. Per the commit message, this goes against the PBAP requirement that the user confirm at least the first connection from each new PCE, and the MAP requirement that MCE and MSE be bonded before a connection is set up. The bulletin classifies the result as information disclosure (ID), High severity.",
     "fix_analysis": [
      "android/app/src/com/android/bluetooth/btservice/AdapterService.java, in the bond-state change handler that already forwards the transition to mCsipSetCoordinatorService.handleBondStateChanged and mDatabaseManager.handleBondStateChanged: after the database update, if toState == BOND_NONE, the code calls setMessageAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN), setPhonebookAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN) and setSimAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN).",
      "A static import of android.bluetooth.BluetoothDevice.BOND_NONE is added to AdapterService.java for the comparison.",
      "Single-commit fix; only AdapterService.java is changed on Android 15."
     ],
     "completeness": [
      "Covers all three per-device profile permissions exposed by AdapterService (message, phonebook, SIM) on the BOND_NONE transition.",
      "The reset only runs when a transition to BOND_NONE is processed through this handler. The fix does not change how permissions are granted, only when they are revoked.",
      "The material does not show whether every unbond path (for example, local bond removal vs. a removal reported by the remote, or BOND_BONDING to BOND_NONE after a failed pairing) flows through this handler."
     ],
     "behavior_changes": [
      "Any transition to BOND_NONE handled here sets the device's MAP, PBAP and SIM access permissions to ACCESS_UNKNOWN, whatever fromState was."
     ],
     "preconditions": [
      "Bluetooth enabled and a remote device that previously held a MAP, PBAP or SIM access permission.",
      "The device's bond state transitions to BOND_NONE, which is the event that triggers the reset."
     ],
     "per_major": {
      "14": "adapted fix: commit 142acc56658c in android-security-14.0.0_r17 adds the same three ACCESS_UNKNOWN resets to BondStateMachine.java, just before the ACTION_BOND_STATE_CHANGED intent is built. It calls mAdapterService.setMessageAccessPermission / setPhonebookAccessPermission / setSimAccessPermission when newState == BluetoothDevice.BOND_NONE. 3/3 patched lines are present at android-security-14.0.0_r29.",
      "15": "same fix: commit 090ca53cc13c in android-security-15.0.0_r5 adds the reset to the AdapterService bond-state handler. 8/8 patched lines are present at android-security-15.0.0_r17.",
      "16": "not affected: not listed by the bulletin. The patched region is present (8/8 lines) at android-security-16.0.0_r8.",
      "17": "not affected: not listed by the bulletin. 5/8 lines of the patched region are present at android-security-17.0.0_r1; the material does not show whether the reset logic exists in another form."
     },
     "backport_notes": [
      "The hook location differs by branch. Android 14 hooks BondStateMachine (before the ACTION_BOND_STATE_CHANGED intent is sent) and calls the AdapterService setters through mAdapterService. Android 15 hooks the AdapterService handler that calls mDatabaseManager.handleBondStateChanged. Make sure the three set*AccessPermission methods exist on AdapterService in the target branch."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact name of the enclosing AdapterService method on Android 15 is not shown in the hunk header or the context snippet.",
      "Whether all unbond code paths (including failed pairing) route through the patched handler.",
      "Why only 5/8 lines of the patched region are present on Android 17, and whether the reset logic is preserved there.",
      "Whether the stored permissions persist across reboots, and how stale entries from before the fix are handled.",
      "How each profile treats ACCESS_UNKNOWN on a later connection attempt."
     ],
     "meta": {
      "generated": "2026-10-03",
      "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-2025-0093": {
     "cve": "CVE-2025-0093",
     "summary": "When a device transitions to BOND_NONE, the Bluetooth stack now resets that device's Message Access (MAP), Phonebook Access (PBAP) and SIM Access permissions to ACCESS_UNKNOWN, so previously stored profile access does not survive unbonding.",
     "component": "platform/packages/modules/Bluetooth, btservice (AdapterService on 15 / BondStateMachine on 14 bond-state handling; MAP/PBAP/SAP access permissions)",
     "weakness": "Missing state reset on unbond (stale authorization): per-device access permissions persisted after the bond was removed",
     "root_cause": "The bond state change path in AdapterService (the handler that forwards to the profile services and to mDatabaseManager.handleBondStateChanged) did not touch the per-device Message/Phonebook/SIM access permissions when a device became unbonded. Stored grants for PBAP, MAP or SAP therefore remained after unbonding. The commit message says this conflicts with the PBAP requirement that the user confirm the first connection from each new PCE and with the MAP requirement that MCE and MSE be bonded.",
     "fix_analysis": [
      "android/app/src/com/android/bluetooth/btservice/AdapterService.java, in the bond state change handler (the method that calls mDatabaseManager.handleBondStateChanged; the hunk does not show its name): after the database update, if toState == BOND_NONE, it calls setMessageAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN), setPhonebookAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN) and setSimAccessPermission(device, BluetoothDevice.ACCESS_UNKNOWN).",
      "Adds a static import of android.bluetooth.BluetoothDevice.BOND_NONE in AdapterService.java.",
      "Android 14 variant (142acc56658c): the same three resets are placed in android/app/src/com/android/bluetooth/btservice/BondStateMachine.java, guarded by newState == BluetoothDevice.BOND_NONE. They are called through mAdapterService.setXxxAccessPermission just before the ACTION_BOND_STATE_CHANGED intent is built."
     ],
     "completeness": [
      "Covers the three per-device access permissions (message, phonebook, SIM) and resets them on every transition to BOND_NONE, whatever the fromState.",
      "Only acts on the bond state transition. The diff does not change how the PBAP/MAP/SAP services check the permission on an incoming connection, and it does not add a bond check at connection time.",
      "Permissions are reset only when the stack observes a transition to BOND_NONE. The diff shows no migration for grants that were already stale before the fix was installed.",
      "The hunk does not show whether other per-device trust state held by AdapterService or DatabaseManager is reset. Only these three setters are touched."
     ],
     "behavior_changes": [
      "After unbonding, or after a failed or cancelled bond that ends in BOND_NONE, the device's MAP, PBAP and SAP access permissions are set to ACCESS_UNKNOWN.",
      "A previously stored ACCESS_REJECTED is also cleared on unbond, not only ACCESS_ALLOWED."
     ],
     "preconditions": [
      "A remote device was previously bonded and has a stored phonebook, message or SIM access permission on the local device.",
      "The device later becomes unbonded (bond state transitions to BOND_NONE) while the stored permission remains.",
      "A later PBAP/MAP/SAP connection attempt from that device address checks the stored permission."
     ],
     "per_major": {
      "14": "adapted fix: commit 142acc56658c in android-security-14.0.0_r17 places the same three resets in BondStateMachine.java (newState == BOND_NONE), calling mAdapterService.setXxxAccessPermission; 3/3 lines of the patched region present at android-security-14.0.0_r29.",
      "15": "same fix: commit 090ca53cc13c in android-security-15.0.0_r5, in the AdapterService.java bond state handler; 8/8 lines present at android-security-15.0.0_r17.",
      "16": "not affected (not listed by the bulletin); the patched region is present (8/8 lines) at android-security-16.0.0_r8.",
      "17": "not affected (not listed by the bulletin); 5/8 lines of the patched region match at android-security-17.0.0_r1. The material does not show the exact form of the code there."
     },
     "backport_notes": [
      "The insertion point differs between majors. On 14 the reset is in BondStateMachine.java, calling mAdapterService.setXxxAccessPermission before the ACTION_BOND_STATE_CHANGED intent is built. On 15 it is in AdapterService's own bond state handler, after mDatabaseManager.handleBondStateChanged. Put it where the branch centrally handles bond-state transitions. Both variants call existing setters on AdapterService."
     ],
     "confidence": "high",
     "unknowns": [
      "The hunk header does not show the name of the enclosing AdapterService method on Android 15.",
      "Which profile (PBAP, MAP or SAP) was the reported trigger is not shown; the commit cites both the PBAP and MAP specifications and two bug IDs.",
      "How the PBAP/MAP/SAP services treat ACCESS_UNKNOWN on a later connection (for example, prompting the user) is not shown.",
      "The exact state of the patched region on Android 17 (5/8 lines matched) is not shown.",
      "The material does not cover whether the fix was also applied to Android 12/12L/13."
     ],
     "meta": {
      "generated": "2026-10-03",
      "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-2025-22404": {
     "cve": "CVE-2025-22404",
     "summary": "Before each L2CA_DataWrite call, the fix saves the BT_HDR length (or uses pointer arithmetic), so the failure-path log::warn statements in AVCT, BNEP, HID device, RFCOMM and SDP no longer read a buffer that the call may already have freed.",
     "component": "platform/packages/modules/Bluetooth, system/stack (avct, bnep, hid, rfcomm, sdp L2CAP senders)",
     "weakness": "Use after free: a failure-path log statement reads a BT_HDR that the preceding L2CA_DataWrite call may have freed",
     "root_cause": "Nine call sites pass a BT_HDR* to L2CA_DataWrite. When the call returns something other than L2CAP_DW_SUCCESS, they log p_buf->len (or hd_cb.pending_data->len, p->len or p_msg->len). Per the commit message, in exceptional cases the preceding call has already freed the buffer, so the log statement reads freed memory. The affected sites are: avct_lcb_act.cc:avct_lcb_msg_ind, bnep_main.cc:bnep_congestion_ind, bnep_utils.cc:bnepu_check_send_packet, hidd_conn.cc:hidd_check_config_done, rfc_ts_frames.cc:rfc_send_buf_uih, rfc_utils.cc:rfc_check_send_cmd, sdp_discovery.cc:process_service_attr_rsp, and sdp_server.cc:process_service_search and process_service_attr_req.",
     "fix_analysis": [
      "system/stack/avct/avct_lcb_act.cc:avct_lcb_msg_ind: adds `uint16_t len = p_buf->len;` before L2CA_DataWrite on the AVCT_REJ response path and logs `len` instead of `p_buf->len`.",
      "system/stack/bnep/bnep_main.cc:bnep_congestion_ind: in the loop that drains p_bcb->xmit_q when not congested, stores `len = p_buf->len` before L2CA_DataWrite and logs the local.",
      "system/stack/bnep/bnep_utils.cc:bnepu_check_send_packet: in the non-congested else branch, stores `len = p_buf->len` before L2CA_DataWrite and logs the local.",
      "system/stack/hid/hidd_conn.cc:hidd_check_config_done: stores `len = hd_cb.pending_data->len` before the L2CA_DataWrite of pending interrupt-channel data and logs the local. The indentation of the if block is slightly off; there is no logic change.",
      "system/stack/rfcomm/rfc_ts_frames.cc:rfc_send_buf_uih: for DLCIs other than the multiplexer DLCI, stores `len = p_buf->len` before L2CA_DataWrite and logs the local.",
      "system/stack/rfcomm/rfc_utils.cc:rfc_check_send_cmd: in the cmd_q drain loop, stores `len = p->len` before L2CA_DataWrite and logs the local.",
      "system/stack/sdp/sdp_discovery.cc:process_service_attr_rsp: the log now uses `p - p_start` instead of `p_msg->len`. This is the value assigned to p_msg->len just before the call, so p_msg is not read after the call.",
      "system/stack/sdp/sdp_server.cc:process_service_search and process_service_attr_req: the logs now use `p_rsp - p_rsp_start` instead of `p_buf->len`. This is the value assigned to p_buf->len just before the send."
     ],
     "completeness": [
      "None of the nine L2CA_DataWrite failure-path logs touched by the diff reads the buffer after the call any more, and the logged values are the same as before.",
      "The fix only changes logging. It does not change L2CA_DataWrite or how these call sites handle the buffer. No other post-call use of the buffer is visible in the provided context.",
      "The title 'Fix more memory-unsafe logging' suggests an earlier commit of the same kind. The material does not show whether other L2CA_DataWrite callers outside these eight files have the same pattern."
     ],
     "behavior_changes": [
      "Nothing observable changes: the log output carries the same length values, now taken from a local variable or from pointer arithmetic done before the call."
     ],
     "preconditions": [
      "L2CA_DataWrite must return a value other than L2CAP_DW_SUCCESS at one of the patched sites, and (per the commit message) the buffer must have been freed by that call, which happens only in exceptional cases.",
      "Per the code context, bnep_congestion_ind is a callback that L2CAP calls when congestion status changes. bnepu_check_send_packet is called from bnepu_send_peer_our_filters and bnepu_send_peer_filter_rsp (per index search) and from the BNEP command-not-understood sender (code context).",
      "The other sites run on active AVCT, RFCOMM, HID device or SDP connections. For each site, the material does not show exactly how a remote peer can trigger it."
     ],
     "per_major": {
      "14": "Not affected per the bulletin. android-security-14.0.0_r29 has 4/8 lines of the patched region. The material does not show whether the vulnerable log statements exist in this branch.",
      "15": "Same fix: commit 806774b1cf64 in android-security-15.0.0_r5 (cherry-pick of internal commit 43cfd234de9b, Change-Id I6289907e86786eb2e10a163f7fb5d2557eab00bc). At android-security-15.0.0_r17 the code context shows all nine sites patched (the resolver matched 7/8 lines).",
      "16": "Not affected per the bulletin. android-security-16.0.0_r8 has 4/8 lines of the patched region. Per index search, the indexed copy of bnepu_check_send_packet (labelled Android 15, android-15.0.0_r36) already has the `len` local and uses a refactored `stack::l2cap::get_interface().L2CA_DataWrite(...) != tL2CAP_DW_RESULT::SUCCESS` call. The lower match count may therefore reflect refactored code, but the material does not confirm this for Android 16.",
      "17": "Not affected per the bulletin. android-security-17.0.0_r1 has 4/8 lines of the patched region. Same caveat as Android 16."
     },
     "backport_notes": [
      "The fix has no dependencies. At each of the nine sites, move the length read above the L2CA_DataWrite call, or use the pointer difference already used to set ->len. On branches that write the call through the stack::l2cap::get_interface() wrapper, make the same change around the wrapper call."
     ],
     "confidence": "high",
     "unknowns": [
      "The material does not show which L2CA_DataWrite failure path frees the buffer, or the function's ownership contract. It only says the buffer may be freed in exceptional cases.",
      "The commit lists nine bug IDs. The material does not show which site belongs to this CVE's bug, or the content of the earlier 'memory-unsafe logging' commit.",
      "The material does not show whether Android 14/16/17 contain the vulnerable log statements, or whether a different commit fixed them there.",
      "How a remote peer reaches each patched site (for example, what triggers the AVCT_REJ path) 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-2025-22405": {
     "cve": "CVE-2025-22405",
     "summary": "At nine Bluetooth stack call sites in eight files, the failure log after L2CA_DataWrite() no longer reads the BT_HDR buffer that was passed to that call (the commit message says such a buffer may already be freed). The length is now saved in a local variable before the call or recomputed from existing pointers.",
     "component": "platform/packages/modules/Bluetooth, system/stack (AVCT, BNEP, HID device, RFCOMM, SDP)",
     "weakness": "use after free (a log statement reads the buffer after it was passed to L2CA_DataWrite, which can free it)",
     "root_cause": "At each affected site the code calls L2CA_DataWrite(cid, p_buf). Per the commit message, in exceptional cases the buffer may have been freed by that call. When the call does not return L2CAP_DW_SUCCESS, the log::warn(\"Unable to write L2CAP data ...\") statement read p_buf->len (or hd_cb.pending_data->len, p->len, p_msg->len) from a buffer that may already be freed. This is a read use-after-free in the warning path.",
     "fix_analysis": [
      "system/stack/avct/avct_lcb_act.cc:avct_lcb_msg_ind: adds `uint16_t len = p_buf->len;` before L2CA_DataWrite(p_lcb->ch_lcid, p_buf) and logs `len` instead of p_buf->len in the AVCT_REJ send path.",
      "system/stack/bnep/bnep_main.cc:bnep_congestion_ind: in the uncongested drain loop over p_bcb->xmit_q, saves `len = p_buf->len` before L2CA_DataWrite(l2cap_cid, p_buf) and logs the local.",
      "system/stack/bnep/bnep_utils.cc:bnepu_check_send_packet: in the direct-send else branch, saves `len = p_buf->len` before L2CA_DataWrite(p_bcb->l2cap_cid, p_buf) and logs the local.",
      "system/stack/hid/hidd_conn.cc:hidd_check_config_done: saves `len = hd_cb.pending_data->len` before L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data) and logs the local. hd_cb.pending_data is still set to NULL afterwards. The new lines are mis-indented, but the logic is correct.",
      "system/stack/rfcomm/rfc_ts_frames.cc:rfc_send_buf_uih: for DLCIs other than RFCOMM_MX_DLCI, saves `len = p_buf->len` before L2CA_DataWrite(p_mcb->lcid, p_buf) and logs the local.",
      "system/stack/rfcomm/rfc_utils.cc:rfc_check_send_cmd: in the cmd_q drain loop, saves `len = p->len` before L2CA_DataWrite(p_mcb->lcid, p) and logs the local.",
      "system/stack/sdp/sdp_discovery.cc:process_service_attr_rsp: logs `p - p_start` (the value just assigned to p_msg->len) instead of p_msg->len after L2CA_DataWrite(p_ccb->connection_id, p_msg).",
      "system/stack/sdp/sdp_server.cc:process_service_search and process_service_attr_req: log `p_rsp - p_rsp_start` (the value just assigned to p_buf->len) instead of p_buf->len after L2CA_DataWrite(p_ccb->connection_id, p_buf)."
     ],
     "completeness": [
      "The fix removes the read of the written buffer after the call at all nine changed call sites. At each site the logged length is the same value as before, either saved before the call or recomputed from pointers into the caller's own state.",
      "The fix changes only the call sites. It does not change how L2CA_DataWrite takes ownership of or frees the buffer, so any other L2CA_DataWrite caller that reads the buffer after the call would need the same change. The commit title 'Fix more memory-unsafe logging' suggests an earlier related commit, which is not in this material.",
      "The other values in the log statements (p_lcb->peer_addr, p_bcb->rem_bda, p_mcb->bd_addr, p_ccb->device_address, the cids) come from control blocks, not from the written buffer, and the fix leaves them unchanged."
     ],
     "behavior_changes": [
      "No functional change: only the source of the length value in the warning log messages changes.",
      "The hidd_conn.cc hunk changes indentation only. Control flow is the same."
     ],
     "preconditions": [
      "An outgoing write through L2CA_DataWrite that does not return L2CAP_DW_SUCCESS. This is the only case in which the affected log statement runs.",
      "The affected send paths are: AVCTP reject responses (avct_lcb_msg_ind); BNEP congestion clearing and packet sends (bnep_congestion_ind, and bnepu_check_send_packet, which is called from bnepu_send_peer_our_filters, bnepu_send_peer_filter_rsp and others per index search); HID device interrupt-channel pending data after configuration (hidd_check_config_done); RFCOMM UIH frame and command sends (rfc_send_buf_uih, rfc_check_send_cmd); SDP client requests and SDP server responses (process_service_attr_rsp, process_service_search, process_service_attr_req).",
      "The material does not show the exact condition under which L2CA_DataWrite frees the buffer and returns failure."
     ],
     "per_major": {
      "14": "Not affected per the bulletin (Android 14 is not listed). At android-security-14.0.0_r29, 4/8 lines of the patched region are present.",
      "15": "Same fix: commit 806774b1cf64 in android-security-15.0.0_r5, a cherry-pick of internal commit 43cfd234de9b (Change-Id I6289907e86786eb2e10a163f7fb5d2557eab00bc). At android-security-15.0.0_r17, 7/8 lines of the patched region are present, and the code context there shows all nine call sites fixed.",
      "16": "Not affected per the bulletin (Android 16 is not listed). At android-security-16.0.0_r8, 4/8 lines of the patched region are present. The material does not show the Android 16 code.",
      "17": "Not affected per the bulletin (Android 17 is not listed). At android-security-17.0.0_r1, 4/8 lines of the patched region are present. The material does not show the Android 17 code."
     },
     "backport_notes": [
      "The change is self-contained and mechanical: wherever L2CA_DataWrite is followed by a log of the buffer length, save the length in a local before the call. Where the call is written as stack::l2cap::get_interface().L2CA_DataWrite(...) != tL2CAP_DW_RESULT::SUCCESS (the index shows this form for android-15.0.0_r36), apply the same change by hand, because the patch may not apply cleanly."
     ],
     "confidence": "high",
     "unknowns": [
      "The exact conditions under which L2CA_DataWrite frees the buffer and returns a non-success result.",
      "Which call sites the researcher POC exercised, and which of the nine bug IDs maps to CVE-2025-22405.",
      "The content of any earlier 'memory-unsafe logging' commit that this change extends.",
      "What code Android 14, 16 and 17 have at these sites (only partial line matches are reported)."
     ],
     "meta": {
      "generated": "2026-10-03",
      "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-2025-22406": {
     "cve": "CVE-2025-22406",
     "summary": "At nine L2CAP send sites in eight Bluetooth stack files (AVCT, BNEP, HID device, RFCOMM, SDP), the log::warn on the failure path no longer reads the BT_HDR buffer after it has been passed to L2CA_DataWrite. The length is now saved in a local before the call or computed from pointers the code already has.",
     "component": "platform/packages/modules/Bluetooth, system/stack (avct, bnep, hid, rfcomm, sdp)",
     "weakness": "Use-after-free (read of a possibly freed BT_HDR in a log statement after it was passed to L2CA_DataWrite)",
     "root_cause": "At each patched site the code calls L2CA_DataWrite(cid, p_buf). When the call does not return L2CAP_DW_SUCCESS, it then logs p_buf->len (or hd_cb.pending_data->len, p->len, p_msg->len). The commit message says that in exceptional cases the buffer may already have been freed by the preceding call, so the log statement can read freed memory. The pattern was present in avct_lcb_msg_ind, bnep_congestion_ind, bnepu_check_send_packet, hidd_check_config_done, rfc_send_buf_uih, rfc_check_send_cmd, process_service_attr_rsp, process_service_search and process_service_attr_req.",
     "fix_analysis": [
      "system/stack/avct/avct_lcb_act.cc:avct_lcb_msg_ind: adds `uint16_t len = p_buf->len;` before L2CA_DataWrite and logs `len` instead of `p_buf->len` when sending the AVCT_REJ fails.",
      "system/stack/bnep/bnep_main.cc:bnep_congestion_ind: in the loop that drains p_bcb->xmit_q once congestion clears, saves `len = p_buf->len` after the dequeue and before L2CA_DataWrite. The log uses `len`.",
      "system/stack/bnep/bnep_utils.cc:bnepu_check_send_packet: in the not-congested branch, saves `len` before L2CA_DataWrite. The log uses `len`.",
      "system/stack/hid/hidd_conn.cc:hidd_check_config_done: saves `len = hd_cb.pending_data->len` before L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data). The log uses `len`. The new line is mis-indented but sits inside the `if (hd_cb.pending_data)` block, so the logic is correct.",
      "system/stack/rfcomm/rfc_ts_frames.cc:rfc_send_buf_uih: for a non-MX DLCI, saves `len = p_buf->len` before L2CA_DataWrite. The log uses `len`.",
      "system/stack/rfcomm/rfc_utils.cc:rfc_check_send_cmd: in the loop that drains cmd_q, saves `len = p->len` after the dequeue and before L2CA_DataWrite. The log uses `len`.",
      "system/stack/sdp/sdp_discovery.cc:process_service_attr_rsp: the log now uses `p - p_start` (the same expression just assigned to p_msg->len) instead of `p_msg->len`.",
      "system/stack/sdp/sdp_server.cc:process_service_search and process_service_attr_req: the log now uses `p_rsp - p_rsp_start` (the value assigned to p_buf->len) instead of `p_buf->len`.",
      "L2CA_DataWrite itself is not changed. The fix only removes the reads of the buffer after the call at these sites."
     ],
     "completeness": [
      "The fix covers nine log statements in eight files. Each one now gets the length before the call or from local pointer arithmetic.",
      "The commit title 'Fix more memory-unsafe logging' suggests it follows earlier fixes of the same pattern. The material does not show whether other L2CA_DataWrite callers in the stack still log buffer fields after the call.",
      "L2CA_DataWrite is unchanged, so its handling of the buffer is too. Any call site that logs the buffer after the call would bring the pattern back."
     ],
     "behavior_changes": [
      "No functional change. The warning now logs the length from before the call (saved in a local or computed from the same pointers) and no longer reads the buffer after L2CA_DataWrite."
     ],
     "preconditions": [
      "L2CA_DataWrite must return a value other than L2CAP_DW_SUCCESS so that the warning runs, and the buffer must have been freed during that call (the commit calls these cases exceptional).",
      "How each site is reached: avct_lcb_msg_ind runs on an incoming AVCTP message on the control channel (the AVCT_REJ send path). process_service_search and process_service_attr_req are in the SDP server (sdp_server.cc). process_service_attr_rsp is in the SDP client (sdp_discovery.cc). bnep_congestion_ind is an L2CAP congestion callback. Per index search, bnepu_check_send_packet is called from BNEP functions including bnepu_send_peer_our_filters and bnepu_send_peer_filter_rsp. rfc_send_buf_uih and rfc_check_send_cmd send RFCOMM frames. hidd_check_config_done runs when a HID device connection finishes configuration and data is pending.",
      "A Bluetooth connection with a peer on the relevant profile (AVCTP, BNEP, HID device, RFCOMM or SDP) is needed. The bulletin rates the CVE EoP, High."
     ],
     "per_major": {
      "14": "Not affected per the bulletin. At android-security-14.0.0_r29 only 4/8 patched-region lines match, so the code at these sites differs from the Android 15 form. Whether the vulnerable log statements exist there is not shown.",
      "15": "Fixed by commit 806774b1cf64 in android-security-15.0.0_r5 (cherry-pick of internal change 43cfd234de9b). At android-security-15.0.0_r17, 7/8 lines are present. The r17 context shows the corrected log statements in the bnep, hid, rfcomm and sdp sites. The avct site is not shown in that context. Per index search, android-15.0.0_r36 has bnepu_check_send_packet with the `len` capture and a refactored stack::l2cap::get_interface().L2CA_DataWrite(...) != tL2CAP_DW_RESULT::SUCCESS call.",
      "16": "Not affected per the bulletin. 4/8 lines match at android-security-16.0.0_r8. Whether the fix is present there in refactored form is not shown.",
      "17": "Not affected per the bulletin. 4/8 lines match at android-security-17.0.0_r1. The form of the code there is not shown."
     },
     "backport_notes": [
      "This is a single commit with no other commits it depends on. Some trees call L2CA_DataWrite through stack::l2cap::get_interface() and compare against tL2CAP_DW_RESULT::SUCCESS (seen in android-15.0.0_r36 per index search). When porting to such a tree, add the same `len` capture before the call and keep that tree's comparison form."
     ],
     "confidence": "high",
     "unknowns": [
      "Which site(s) the 'researcher POC' exercised, and the exact condition under which the buffer is freed before the log runs.",
      "Whether other L2CA_DataWrite callers in the stack still read buffer fields after the call (the commit follows earlier fixes that are not in the material).",
      "Whether the code in Android 14, 16 and 17 contains these log reads after the call, or the fix in another form.",
      "Why 1 of the 8 patched-region lines is missing at android-security-15.0.0_r17."
     ],
     "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-2025-22407": {
     "cve": "CVE-2025-22407",
     "summary": "Across nine L2CA_DataWrite call sites in the Bluetooth stack (AVCT, BNEP, HID device, RFCOMM, SDP), the failure-path log::warn no longer dereferences the BT_HDR buffer that was passed to L2CA_DataWrite; instead the length is stored in a local before the call or recomputed from pointer arithmetic.",
     "component": "platform/packages/modules/Bluetooth, system/stack (avct, bnep, hid, rfcomm, sdp)",
     "weakness": "Use-after-free read (a buffer field read in a log statement after the buffer was passed to L2CA_DataWrite, which per the commit message may have freed it)",
     "root_cause": "Several stack layers call L2CA_DataWrite(cid, p_buf). When it returns something other than L2CAP_DW_SUCCESS, they log a warning that reads p_buf->len (or hd_cb.pending_data->len, p->len, p_msg->len). Per the commit message, the structures used in these log statements may, in exceptional cases, have been freed by the preceding call, so the log can read a field of freed memory. Affected functions: avct_lcb_msg_ind (avct_lcb_act.cc), bnep_congestion_ind (bnep_main.cc), bnepu_check_send_packet (bnep_utils.cc), hidd_check_config_done (hidd_conn.cc), rfc_send_buf_uih (rfc_ts_frames.cc), rfc_check_send_cmd (rfc_utils.cc), process_service_attr_rsp (sdp_discovery.cc), process_service_search and process_service_attr_req (sdp_server.cc).",
     "fix_analysis": [
      "system/stack/avct/avct_lcb_act.cc:avct_lcb_msg_ind: adds 'uint16_t len = p_buf->len;' before L2CA_DataWrite and logs 'len' instead of p_buf->len in the AVCT_REJ send failure path.",
      "system/stack/bnep/bnep_main.cc:bnep_congestion_ind: in the un-congest drain loop, captures 'uint16_t len = p_buf->len;' after dequeue and before L2CA_DataWrite; the warn logs 'len'.",
      "system/stack/bnep/bnep_utils.cc:bnepu_check_send_packet: in the non-congested branch, captures len before L2CA_DataWrite and logs it.",
      "system/stack/hid/hidd_conn.cc:hidd_check_config_done: captures 'uint16_t len = hd_cb.pending_data->len;' before L2CA_DataWrite(p_hcon->intr_cid, hd_cb.pending_data) and logs 'len'. The new block is indented irregularly, but the logic is unchanged.",
      "system/stack/rfcomm/rfc_ts_frames.cc:rfc_send_buf_uih: in the non-MX-DLCI branch, captures len before L2CA_DataWrite and logs it.",
      "system/stack/rfcomm/rfc_utils.cc:rfc_check_send_cmd: in the cmd_q drain loop, captures 'uint16_t len = p->len;' after dequeue and before L2CA_DataWrite; logs 'len'.",
      "system/stack/sdp/sdp_discovery.cc:process_service_attr_rsp: replaces p_msg->len in the warn with 'p - p_start', the same expression just assigned to p_msg->len, so p_msg is not dereferenced after the write.",
      "system/stack/sdp/sdp_server.cc:process_service_search and process_service_attr_req: replace p_buf->len in the warn with 'p_rsp - p_rsp_start', the value just stored into p_buf->len, so p_buf is not dereferenced after the write.",
      "No change to L2CA_DataWrite itself; only the logging after the call stops dereferencing the buffer."
     ],
     "completeness": [
      "Covers nine L2CA_DataWrite failure-path log statements in eight files. In each shown site, the only buffer access after the call was the ->len read in log::warn, and that read is removed.",
      "The fix does not change L2CA_DataWrite. Any other site that dereferences a buffer after passing it to L2CA_DataWrite would need the same treatment. The commit title 'Fix more memory-unsafe logging' suggests an earlier commit addressed other sites, but that commit is not in the material.",
      "The logged value is the same before and after the fix: len is captured just before the call, and the SDP pointer differences equal the value assigned to ->len immediately before, so no diagnostics are lost."
     ],
     "behavior_changes": [
      "None observable: same log text and values; no new error codes, return values, or control-flow changes."
     ],
     "preconditions": [
      "Bluetooth enabled with an established L2CAP channel on the relevant profile (AVCTP, BNEP, HID device, RFCOMM, or SDP).",
      "L2CA_DataWrite must return a result other than L2CAP_DW_SUCCESS in a case where, per the commit message, the buffer may already have been freed.",
      "Context for several sites: avct_lcb_msg_ind builds an AVCT_REJ after reassembling an incoming message (per index search); bnep_congestion_ind is the callback L2CAP calls when congestion status changes; bnepu_check_send_packet is called from BNEP_Write, BNEP_WriteBuf, bnepu_send_peer_our_filters, bnepu_send_peer_filter_rsp and bnep_send_conn_req (per index search)."
     ],
     "per_major": {
      "14": "not affected per the bulletin; at android-security-14.0.0_r29 only 4/8 patched-region lines match. The exact state of these log statements on 14 is not shown in the material.",
      "15": "same fix: commit 806774b1cf64 in android-security-15.0.0_r5 (cherry-pick of internal 43cfd234de9b, Change-Id I6289907e86786eb2e10a163f7fb5d2557eab00bc). At android-security-15.0.0_r17, 7/8 patched-region lines are present. The code context there shows the patched form at eight of the nine sites; the avct_lcb_msg_ind site is not shown in that context.",
      "16": "not affected per the bulletin; at android-security-16.0.0_r8 4/8 patched-region lines match. The material does not show the state of the individual sites.",
      "17": "not affected per the bulletin; at android-security-17.0.0_r1 4/8 patched-region lines match. The material does not show the state of the individual sites."
     },
     "backport_notes": [
      "Single self-contained commit with no dependency shown. Per index search (android-15.0.0_r36), some code calls stack::l2cap::get_interface().L2CA_DataWrite(...) != tL2CAP_DW_RESULT::SUCCESS. On such code the context lines differ, but the 'capture len before the call' pattern is the same."
     ],
     "confidence": "high",
     "unknowns": [
      "Under exactly which L2CA_DataWrite failure conditions the buffer is freed before return (the L2CAP implementation is not in the material).",
      "The earlier commit implied by 'Fix more memory-unsafe logging', and whether any other buffer dereferences after L2CA_DataWrite remain elsewhere in the stack.",
      "Why only 7/8 patched-region lines match at android-security-15.0.0_r17.",
      "Exact state of these log statements on Android 14, 16 and 17 (only line-match counts are provided)."
     ],
     "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-2025-26417": {
     "cve": "CVE-2025-26417",
     "summary": "DownloadProvider's insert path now queries MediaStore for an existing record at the requested destination file path and throws SecurityException when that record's OWNER_PACKAGE_NAME does not belong to the calling UID.",
     "component": "platform/packages/providers/DownloadProvider, DownloadProvider content provider (insert / destination file validation)",
     "weakness": "missing ownership / authorization check (information disclosure, per bulletin type ID)",
     "root_cause": "In src/com/android/providers/downloads/DownloadProvider.java, the destination-file validation performed during insert only called Helpers.checkDestinationFilePathRestrictions(file, getCallingPackage(), ...) with allowDownloadsDirOnly=true (suggesting a restriction to the Downloads directory). It did not check whether a MediaStore record already existed for that path or which package owned it. Per the commit message, this let apps access any file in Downloads by invoking the DownloadProvider insert method.",
     "fix_analysis": [
      "src/com/android/providers/downloads/DownloadProvider.java: immediately after Helpers.checkDestinationFilePathRestrictions(...) in the insert destination-validation method, a new call checkWhetherCallingAppHasAccess(file.getPath(), Binder.getCallingUid()) is added.",
      "src/com/android/providers/downloads/DownloadProvider.java:checkWhetherCallingAppHasAccess (new): acquires a ContentProviderClient for MediaStore.AUTHORITY, builds the files URI via MediaStore.setIncludePending(Helpers.getContentUriForPath(getContext(), filePath)), and queries projection {_ID, OWNER_PACKAGE_NAME} with selection DATA=? and the file path as argument.",
      "If a row is found and its OWNER_PACKAGE_NAME is non-null, the method fetches getPackageManager().getPackagesForUid(uid); if that array is non-null and does not contain the owner package name, it throws SecurityException(\"Caller does not have access to this path\"), aborting the insert.",
      "java.util.Arrays import added for the Arrays.asList(...).contains(...) membership test."
     ],
     "completeness": [
      "Covers only the insert path (the method that validates the destination file after checkDestinationFilePathRestrictions); no other DownloadProvider entry points are modified in this diff.",
      "The check fails open in several cases visible in the code: ContentProviderClient for MediaStore cannot be acquired (logs and returns), RemoteException from the query (logs and returns), null cursor or no matching row, OWNER_PACKAGE_NAME null for the existing row, or getPackagesForUid returning null. In all of these the insert proceeds as before.",
      "Only the first matching row (moveToFirst) is examined; the match is an exact string comparison on MediaStore DATA against file.getPath(), so correctness depends on the path form produced by the preceding validation.",
      "Authorization is granted if any package sharing the calling UID matches the owner package name."
     ],
     "behavior_changes": [
      "Insert requests whose destination path already has a MediaStore record owned by a different package now fail with SecurityException instead of succeeding.",
      "Inserts reaching this destination-validation method now perform an additional query to MediaProvider (including pending items); a RemoteException or failure to acquire the client is logged with Constants.TAG and does not block the insert."
     ],
     "preconditions": [
      "Caller invokes DownloadProvider insert with a destination that resolves to a file path and passes Helpers.checkDestinationFilePathRestrictions (called with allowDownloadsDirOnly=true).",
      "A file at that path already has a MediaStore record with a non-null OWNER_PACKAGE_NAME different from every package of the calling UID (for the new check to reject the request)."
     ],
     "per_major": {
      "14": "same fix: commit d37a58ed0acb in android-security-14.0.0_r18, identical diff to the Android 15 commit; 8/8 lines of patched region present at android-security-14.0.0_r29.",
      "15": "same fix: commit ed764e06106a in android-security-15.0.0_r6 (cherry-pick of bf66a79ddcd8); 8/8 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 self-contained commit; the insertion point requires the existing Helpers.checkDestinationFilePathRestrictions(file, ..., isLegacyMode, /* allowDownloadsDirOnly */ true) call and Helpers.getContentUriForPath. Binder, RemoteException, MediaStore and Uri imports are shown in the Android 15 file context; confirm ContentProviderClient and Cursor imports and helper signatures on older branches."
     ],
     "confidence": "high",
     "unknowns": [
      "The name of the enclosing method at line ~1120 is not shown in the hunk header (the commit message refers to it as the insert path).",
      "No fix commits are provided for Android 12, 12L or 13 although the bulletin lists them as affected.",
      "Exactly what information was disclosed is not shown beyond the commit message statement that apps could access any file in Downloads.",
      "Whether file.getPath() is canonicalized before this check (affects the exact-match DATA comparison) is not visible in the provided context.",
      "What Helpers.checkDestinationFilePathRestrictions enforces in detail, and which insert requests reach this validation method, 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."
     }
    }
   }
  },
  "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/2025-03-01",
  "latest_version": "1.1",
  "latest_revision": {
   "version": "1.1",
   "date": "March 20, 2025",
   "notes": "Updated issue list"
  },
  "revisions": [
   {
    "version": "1.0",
    "date": "March 3, 2025",
    "notes": "Bulletin published"
   },
   {
    "version": "1.1",
    "date": "March 20, 2025",
    "notes": "Updated issue list"
   }
  ],
  "tracked_since": "2026-09-30",
  "changes_since_tracking": [],
  "out_of_scope_rows": {
   "Kernel": 3,
   "MediaTek components": 2,
   "Qualcomm closed-source components": 3,
   "Qualcomm components": 5
  },
  "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."
 }
}