CVE-2026-12236
Full vulnerability record from the local CVENow database.
Description
The Bluetooth host GATT client function parse_read_std_char_desc() in subsys/bluetooth/host/gatt.c parses an ATT Read By Type Response received from a remote GATT server during BT_GATT_DISCOVER_STD_CHAR_DESC discovery. The per-entry stride rsp->len is taken directly from the peer's PDU, and the parse loop both tests its exit condition (length >= rsp->len) and advances (length -= rsp->len, pdu += rsp->len) using that value. The minimum value of rsp->len was never validated before the loop. A malicious or malfunctioning peer can reply with rsp->len = 0. Because length is unsigned and never decreases, the loop condition stays true forever and the read pointer never advances; as long as the body is at least a few bytes with a non-zero handle and a matching descriptor UUID, the host repeatedly re-parses the same bytes and invokes the discovery callback, never terminating. This hangs the Bluetooth host processing thread (CWE-835, loop with unreachable exit condition). The condition is reachable by any connected peer once the local device initiates standard-descriptor-value discovery; GATT discovery does not require bonding or encryption, so an unauthenticated adjacent attacker that the device connects to can trigger it. The impact is denial of service of the Bluetooth subsystem (and likely a watchdog reset on constrained targets); there is no memory disclosure or corruption. The fix adds a rsp->len < sizeof(struct bt_att_data) check before the loop, rejecting under-length responses so the stride is always non-zero and the loop terminates. The sibling parsers parse_include() and parse_characteristic() already validated rsp->len and are unaffected.
View original CVE JSON
{
"id": "CVE-2026-12236",
"sourceIdentifier": "[email protected]",
"published": "2026-08-13T18:17:17.017",
"lastModified": "2026-10-23T18:10:00.167",
"vulnStatus": "Awaiting Analysis",
"cveTags": [],
"descriptions": [
{
"lang": "en",
"value": "The Bluetooth host GATT client function parse_read_std_char_desc() in subsys/bluetooth/host/gatt.c parses an ATT Read By Type Response received from a remote GATT server during BT_GATT_DISCOVER_STD_CHAR_DESC discovery. The per-entry stride rsp->len is taken directly from the peer's PDU, and the parse loop both tests its exit condition (length >= rsp->len) and advances (length -= rsp->len, pdu += rsp->len) using that value. The minimum value of rsp->len was never validated before the loop.\n\nA malicious or malfunctioning peer can reply with rsp->len = 0. Because length is unsigned and never decreases, the loop condition stays true forever and the read pointer never advances; as long as the body is at least a few bytes with a non-zero handle and a matching descriptor UUID, the host repeatedly re-parses the same bytes and invokes the discovery callback, never terminating. This hangs the Bluetooth host processing thread (CWE-835, loop with unreachable exit condition).\n\nThe condition is reachable by any connected peer once the local device initiates standard-descriptor-value discovery; GATT discovery does not require bonding or encryption, so an unauthenticated adjacent attacker that the device connects to can trigger it. The impact is denial of service of the Bluetooth subsystem (and likely a watchdog reset on constrained targets); there is no memory disclosure or corruption.\n\nThe fix adds a rsp->len < sizeof(struct bt_att_data) check before the loop, rejecting under-length responses so the stride is always non-zero and the loop terminates. The sibling parsers parse_include() and parse_characteristic() already validated rsp->len and are unaffected."
},
{
"lang": "es",
"value": "La función de cliente GATT del host Bluetooth parse_read_std_char_desc() en subsys/bluetooth/host/gatt.c analiza una respuesta ATT Read By Type recibida de un servidor GATT remoto durante el descubrimiento BT_GATT_DISCOVER_STD_CHAR_DESC. El paso por entrada rsp -> len se toma directamente de la PDU del par, y el bucle de análisis tanto prueba su condición de salida (length >= rsp -> len) como avanza (length -= rsp -> len, pdu += rsp -> len) usando ese valor. El valor mínimo de rsp -> len nunca fue validado antes del bucle.\n\nUn par malicioso o que funciona mal puede responder con rsp -> len = 0. Debido a que length no tiene signo y nunca disminuye, la condición del bucle permanece verdadera para siempre y el puntero de lectura nunca avanza; siempre que el cuerpo tenga al menos unos pocos bytes con un identificador no nulo y un UUID de descriptor coincidente, el host vuelve a analizar repetidamente los mismos bytes e invoca la devolución de llamada de descubrimiento, sin terminar nunca. Esto cuelga el hilo de procesamiento del host Bluetooth (CWE-835, bucle con condición de salida inalcanzable).\n\nLa condición es alcanzable por cualquier par conectado una vez que el dispositivo local inicia el descubrimiento de valores de descriptor estándar; el descubrimiento GATT no requiere emparejamiento ni cifrado, por lo que un atacante adyacente no autenticado al que el dispositivo se conecta puede activarlo. El impacto es denegación de servicio del subsistema Bluetooth (y probablemente un reinicio por watchdog en objetivos restringidos); no hay divulgación ni corrupción de memoria.\n\nLa solución añade una comprobación rsp -> len < sizeof(struct bt_att_data) antes del bucle, rechazando respuestas de longitud insuficiente para que el paso sea siempre distinto de cero y el bucle termine. Los analizadores hermanos parse_include() y parse_characteristic() ya validaron rsp -> len y no se ven afectados."
}
],
"affected": [
{
"source": "[email protected]",
"affectedData": [
{
"vendor": "zephyrproject",
"product": "zephyr",
"defaultStatus": "unaffected",
"collectionURL": "https://github.com/zephyrproject-rtos/zephyr",
"packageName": "zephyr",
"programFiles": [
"subsys/bluetooth/host/gatt.c"
],
"versions": [
{
"version": "2.6.0",
"lessThan": "4.4.2",
"versionType": "semver",
"status": "affected"
}
]
}
]
}
],
"metrics": {
"cvssMetricV31": [
{
"source": "[email protected]",
"type": "Secondary",
"cvssData": {
"version": "3.1",
"vectorString": "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
"baseScore": 6.5,
"baseSeverity": "MEDIUM",
"attackVector": "ADJACENT_NETWORK",
"attackComplexity": "LOW",
"privilegesRequired": "NONE",
"userInteraction": "NONE",
"scope": "UNCHANGED",
"confidentialityImpact": "NONE",
"integrityImpact": "NONE",
"availabilityImpact": "HIGH"
},
"exploitabilityScore": 2.8,
"impactScore": 3.6
}
],
"ssvcV203": [
{
"source": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"ssvcData": {
"timestamp": "2026-08-13T17:58:20.588519Z",
"id": "CVE-2026-12236",
"options": [
{
"exploitation": "none"
},
{
"automatable": "no"
},
{
"technicalImpact": "partial"
}
],
"role": "CISA Coordinator",
"version": "2.0.3"
}
}
]
},
"weaknesses": [
{
"source": "[email protected]",
"type": "Secondary",
"description": [
{
"lang": "en",
"value": "CWE-835"
}
]
}
],
"references": [
{
"url": "https://github.com/zephyrproject-rtos/zephyr/commit/494283d469a95b294badaf45c639de433bf5e35a",
"source": "[email protected]"
},
{
"url": "https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-483r-jq2x-5cp9",
"source": "[email protected]"
}
]
}