CVE-2026-10685 Overview
CVE-2026-10685 is a use-after-free vulnerability [CWE-416] in the Zephyr real-time operating system's Bluetooth GATT client. The defect lives in gatt_write_ccc_rsp() inside subsys/bluetooth/host/gatt.c. The handler invokes the application's params->subscribe() callback after already calling params->notify(conn, params, NULL, 0). Per the public GATT API, a notify callback with NULL data signals that the subscription has terminated and the bt_gatt_subscribe_params struct may be freed or reused. Any subsequent subscribe() call, including the indirect call through the freed function pointer, operates on freed memory.
Critical Impact
An adjacent GATT server peer can return an ATT Error Response to a CCC write to trigger memory corruption, denial of service, or attacker-influenced control flow on a Zephyr GATT client.
Affected Products
- Zephyr RTOS Bluetooth host stack (subsys/bluetooth/host/gatt.c)
- Zephyr-based GATT client applications using bt_gatt_subscribe()
- Downstream firmware and IoT devices built on vulnerable Zephyr revisions
Discovery Timeline
- 2026-07-31 - CVE-2026-10685 published to NVD
- 2026-08-04 - Last updated in NVD database
Technical Details for CVE-2026-10685
Vulnerability Analysis
The vulnerability sits in the Zephyr Bluetooth host's Attribute Protocol (ATT) response path. When a Zephyr device acts as a GATT client and calls bt_gatt_subscribe(), the peer GATT server responds to the Client Characteristic Configuration (CCC) write. If the peer returns an ATT Error Response, the error code flows through att_error_rsp into att_handle_rsp and reaches gatt_write_ccc_rsp(). The handler then terminates the subscription by calling params->notify(conn, params, NULL, 0) before invoking params->subscribe().
Applications that free or recycle bt_gatt_subscribe_params inside the notification-termination handler leave the subsequent subscribe() call operating on dangling memory. The result is memory corruption, a crash, or potentially attacker-influenced control flow through the freed params->subscribe function pointer.
Root Cause
The root cause is ordering inversion between two documented API contracts. The GATT API defines notify(NULL) as the terminal signal authorizing the application to release the parameter struct. The error branch in gatt_write_ccc_rsp() fires that terminal signal first, then dereferences the same struct to reach subscribe(). Any application that follows the documented lifecycle triggers a use-after-free.
Attack Vector
The attack requires Bluetooth adjacency and a Zephyr device acting as a GATT client that initiates a subscription. A malicious or malfunctioning GATT server peer replies to the CCC write with an ATT Error Response. No authentication or user interaction is required beyond establishing a Bluetooth connection.
// Patch excerpt: subsys/bluetooth/host/gatt.c
// Reorders the subscribe() callback to run before notify(NULL)
return;
}
+ att_err = att_err_from_int(err);
+
+ if (params->subscribe) {
+ params->subscribe(conn, att_err, params);
+ }
+
prev = NULL;
SYS_SLIST_FOR_EACH_NODE_SAFE(&sub->list, node, tmp) {
Source: Zephyr commit c7292f2
Detection Methods for CVE-2026-10685
Indicators of Compromise
- Unexpected crashes, hard faults, or watchdog resets on Zephyr GATT clients shortly after issuing bt_gatt_subscribe() to a peer
- ATT Error Response frames on the CCC write during subscription establishment observed in Bluetooth sniffer captures
- Heap corruption diagnostics or MPU faults referencing addresses previously held by bt_gatt_subscribe_params
Detection Strategies
- Audit application code for handlers that free or recycle bt_gatt_subscribe_params in response to notify(NULL) while running on unpatched Zephyr revisions
- Enable Zephyr's memory instrumentation and sanitizers in test builds to surface use-after-free on the GATT subscription path
- Fuzz Zephyr GATT clients with ATT Error Response injection on CCC writes to reproduce the ordering defect
Monitoring Recommendations
- Collect crash telemetry and coredumps from fielded Zephyr devices and correlate faults with recent Bluetooth pairing or subscription activity
- Track firmware versions across the device fleet against the fixed Zephyr commit c7292f2
- Log ATT-layer errors returned by peers during CCC writes to identify anomalous or hostile GATT servers
How to Mitigate CVE-2026-10685
Immediate Actions Required
- Update the Zephyr Bluetooth host to a revision containing commit c7292f20223637232b6f962141725611a38f6a52 and rebuild affected firmware
- Inventory all products that ship a Zephyr GATT client and prioritize field updates for devices exposed to untrusted Bluetooth peers
- Review application-side subscription handlers that free or reuse bt_gatt_subscribe_params on notify(NULL) and validate them against the corrected ordering
Patch Information
The fix reorders gatt_write_ccc_rsp() so the subscribe() callback runs before the terminating notify(NULL) in both the error and unsubscribe paths. See the Zephyr commit c7292f2 and the GitHub Security Advisory GHSA-29xh-jm2m-4qvx for the authoritative source and affected version ranges.
Workarounds
- Defer freeing or reusing bt_gatt_subscribe_params until after both the notify(NULL) and subscribe() callbacks have returned
- Restrict GATT client connections to trusted, authenticated peers where feasible to reduce exposure to hostile ATT Error Response injection
- Where updates cannot be deployed immediately, patch the local Zephyr tree with the upstream fix and rebuild firmware
# Apply the upstream fix to a local Zephyr tree
cd zephyr
git fetch origin
git cherry-pick c7292f20223637232b6f962141725611a38f6a52
west build -b <board> <application>
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

