VYPR
High severityNVD Advisory· Published Jun 10, 2026

CVE-2026-44634

CVE-2026-44634

Description

Multiple stack buffer overflows in SimpleBLE versions prior to 0.14.0 could lead to remote code execution or denial of service.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Multiple stack buffer overflows in SimpleBLE versions prior to 0.14.0 could lead to remote code execution or denial of service.

Vulnerability

Multiple stack-based buffer overflow vulnerabilities exist in SimpleBLE versions 0.12.2 and earlier. These include a stack overflow in the dongl backend's Protocol::simpleble_write function, which is triggered by caller-controlled input. Additionally, two vulnerabilities exist when processing manufacturer-specific data and service data in BLE advertisements, which can be triggered remotely without pairing or connection [4]. These issues stem from insufficient bounds checking when handling variable-length data [4].

Exploitation

For the vulnerabilities related to BLE advertisements (EVE-2026-002 and EVE-2026-003), an attacker within radio range can exploit them by sending specially crafted BLE advertisement packets. No authentication, pairing, connection, or user interaction is required. The dongl backend vulnerability (EVE-2026-001) is local and requires caller-controlled input, affecting an unreleased prototype with limited real-world impact [4].

Impact

Successful exploitation of the advertisement-related vulnerabilities can lead to arbitrary code execution or a denial of service. The attack vector is remote, requiring no privileges or user interaction. The dongl backend vulnerability is local. The overall potential impact is considered high [4].

Mitigation

Users should upgrade to SimpleBLE version 0.14.0 or later, which addresses these vulnerabilities [3, 4]. This version was released on 2026-05-02 [3].

AI Insight generated on Jun 10, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

1
1501d59d76a4

Addressed a few vulnerability reports. (#466)

https://github.com/simpleble/simplebleKevin DewaldMay 1, 2026via body-scan-shorthand
8 files changed · +155 22
  • docs/content/docs/changelog.mdx+7 1 modified
    @@ -37,15 +37,21 @@ to learn more.
     
     - (SimpleRsBLE) Fixed linker errors on some 64-bit Linux systems. **(Thanks, davidedellagiustina!)**
     - (SimpleDBus) Fixed `bad_any_cast` exception in dictionaries with `ObjectPath` or `Signature` keys. **(Thanks, AndreiSvatko!)**
    -- (SimpleDBus) Fixed D-Bus parameter errors and strict validation rejections on BlueZ 5.83+ by properly skipping uninitialized optional properties. **(Thanks, @piranna!)**
    +- (SimpleDBus) Fixed D-Bus parameter errors and strict validation rejections on BlueZ 5.83+ by properly skipping uninitialized optional properties. **(Thanks, piranna!)**
     - (SimpleJavaBLE) Fixed missing macOS x64 `.dylib` artifact in the release package due to an omitted CI architecture target.
     - (SimpleJavaBLE) Fixed JNI symbol resolution errors (`UnsatisfiedLinkError`) on `Adapter.isBluetoothEnabled()` and `isPaired` flags.
     - (SimpleJavaBLE) Fixed `jvm.dll` initialization conflicts on Windows that prevented the native bindings from loading smoothly.
    +- (SimpleCBLE) Fixed remotely triggerable stack buffer overflows when handling manufacturer data and advertised services (EVE-2026-002, EVE-2026-003). **(Thanks, Mr-IoT!)**
    +- (Dongl) Fixed stack buffer overflow in simpleble_write (EVE-2026-001). **(Thanks, Mr-IoT!)**
     
     **Removed**
     
     - 
     
    +**Special Acknowledgements**
    +
    +We'd like to thank [Mr-IoT](https://github.com/V33RU) for reporting and providing patches for multiple security vulnerabilities (EVE-2026-001, EVE-2026-002, EVE-2026-003).
    +
     
     ## [0.12.1] - 2026-02-12
     
    
  • simpleble/CMakeLists.txt+7 1 modified
    @@ -442,13 +442,19 @@ if(SIMPLEBLE_TEST)
         add_executable(simpleble_test
             ${CMAKE_CURRENT_SOURCE_DIR}/test/src/main.cpp
             ${CMAKE_CURRENT_SOURCE_DIR}/test/src/test_utils.cpp
    -        ${CMAKE_CURRENT_SOURCE_DIR}/test/src/test_bytearray.cpp)
    +        ${CMAKE_CURRENT_SOURCE_DIR}/test/src/test_bytearray.cpp
    +        ${CMAKE_CURRENT_SOURCE_DIR}/test/src/test_buffer_overflow.cpp)
         set_target_properties(simpleble_test PROPERTIES
             CXX_VISIBILITY_PRESET hidden
             VISIBILITY_INLINES_HIDDEN YES
             CXX_STANDARD 17
             POSITION_INDEPENDENT_CODE ON
             WINDOWS_EXPORT_ALL_SYMBOLS ON)
     
    +    target_include_directories(simpleble_test PRIVATE
    +        ${CMAKE_CURRENT_SOURCE_DIR}/src
    +        ${CMAKE_CURRENT_SOURCE_DIR}/src/backends/dongl
    +        ${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/internal/include)
    +
         target_link_libraries(simpleble_test PRIVATE simpleble::simpleble GTest::gtest)
     endif()
    
  • simpleble/src/backends/dongl/serial/Protocol.cpp+4 0 modified
    @@ -153,6 +153,10 @@ simpleble_ReadRsp Protocol::simpleble_read(uint16_t conn_handle, uint16_t handle
     
     simpleble_WriteRsp Protocol::simpleble_write(uint16_t conn_handle, uint16_t handle, simpleble_WriteOperation operation,
                                                  const std::vector<uint8_t>& data) {
    +    if (data.size() > sizeof(simpleble_WriteCmd_data_t::bytes)) {
    +        throw std::length_error("Payload exceeds maximum size of 512 bytes");
    +    }
    +
         dongl_Command command = dongl_Command_init_zero;
         command.which_cmd = dongl_Command_simpleble_tag;
         command.cmd.simpleble.which_cmd = simpleble_Command_write_tag;
    
  • simpleble/test/src/test_buffer_overflow.cpp+22 0 added
    @@ -0,0 +1,22 @@
    +#include <gtest/gtest.h>
    +#include <stdexcept>
    +#include <vector>
    +#include "backends/dongl/serial/Protocol.h"
    +
    +using namespace SimpleBLE;
    +
    +TEST(BufferOverflowTest, DonglProtocolWriteOverflow) {
    +    try {
    +        SimpleBLE::Dongl::Serial::Protocol p("dummy");
    +        std::vector<uint8_t> data(1000, 'C');
    +        // This should throw std::length_error before trying to write to the serial port
    +        p.simpleble_write(0, 0, static_cast<simpleble_WriteOperation>(0), data);
    +        FAIL() << "Expected std::length_error";
    +    } catch (const std::length_error& e) {
    +        EXPECT_STREQ(e.what(), "Payload exceeds maximum size of 512 bytes");
    +    } catch (const std::runtime_error& e) {
    +        // If it throws runtime_error because dummy device doesn't exist, we can't fully test it this way,
    +        // but the compiler has the static_assert at least.
    +        SUCCEED();
    +    }
    +}
    
  • simplecble/CMakeLists.txt+20 15 modified
    @@ -97,20 +97,25 @@ install(
         DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/simplecble)
     
     if(SIMPLECBLE_TEST)
    -    message(STATUS "No tests are available for simplecble")
    -    # find_package(GTest REQUIRED)
    -
    -    # add_executable(simpleble_test
    -    #     ${CMAKE_CURRENT_SOURCE_DIR}/test/src/main.cpp
    -    #     ${CMAKE_CURRENT_SOURCE_DIR}/test/src/test_utils.cpp
    -    #     ${CMAKE_CURRENT_SOURCE_DIR}/test/src/test_bytearray.cpp)
    -    # set_target_properties(simpleble_test PROPERTIES
    -    #     CXX_VISIBILITY_PRESET hidden
    -    #     VISIBILITY_INLINES_HIDDEN YES
    -    #     CXX_STANDARD 17
    -    #     POSITION_INDEPENDENT_CODE ON
    -    #     WINDOWS_EXPORT_ALL_SYMBOLS ON)
    -
    -    # target_link_libraries(simpleble_test PRIVATE simpleble::simpleble GTest::gtest)
    +    message(STATUS "Building tests for simplecble")
    +    find_package(GTest REQUIRED)
    +
    +    add_executable(simplecble_test
    +        ${CMAKE_CURRENT_SOURCE_DIR}/test/src/test_buffer_overflow.cpp)
    +    set_target_properties(simplecble_test PROPERTIES
    +        CXX_VISIBILITY_PRESET hidden
    +        VISIBILITY_INLINES_HIDDEN YES
    +        CXX_STANDARD 17
    +        POSITION_INDEPENDENT_CODE ON
    +        WINDOWS_EXPORT_ALL_SYMBOLS ON)
    +
    +    target_include_directories(simplecble_test PRIVATE 
    +        ${CMAKE_CURRENT_SOURCE_DIR}/include
    +        ${CMAKE_CURRENT_SOURCE_DIR}/../simpleble/include
    +        ${CMAKE_CURRENT_SOURCE_DIR}/../simpleble/src
    +        ${CMAKE_CURRENT_SOURCE_DIR}/../simpleble/src/backends/dongl
    +        ${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/internal/include)
    +    
    +    target_link_libraries(simplecble_test PRIVATE simplecble simpleble::simpleble GTest::gtest GTest::gtest_main)
     endif()
     
    
  • simplecble/include/simplecble/types.h+4 2 modified
    @@ -37,7 +37,8 @@ typedef struct {
         simpleble_uuid_t uuid;
         size_t data_length;
         uint8_t data[27];
    -    // Note: The maximum length of a BLE advertisement is 31 bytes.
    +    // Note: The maximum length of a BLE 4.x advertisement is 31 bytes.
    +    // BLE 5.0 extended advertisements can be larger, so data may be truncated.
         // The first byte will be the length of the field,
         // the second byte will be the type of the field,
         // the next two bytes will be the service UUID,
    @@ -50,7 +51,8 @@ typedef struct {
         uint16_t manufacturer_id;
         size_t data_length;
         uint8_t data[27];
    -    // Note: The maximum length of a BLE advertisement is 31 bytes.
    +    // Note: The maximum length of a BLE 4.x advertisement is 31 bytes.
    +    // BLE 5.0 extended advertisements can be larger, so data may be truncated.
         // The first byte will be the length of the field,
         // the second byte will be the type of the field (0xFF for manufacturer data),
         // the next two bytes will be the manufacturer ID,
    
  • simplecble/src/peripheral.cpp+4 3 modified
    @@ -231,8 +231,9 @@ simpleble_err_t simpleble_peripheral_services_get(simpleble_peripheral_t handle,
     
             memcpy(services->uuid.value, service.uuid().c_str(), SIMPLEBLE_UUID_STR_LEN);
     
    +        const size_t copy_len = std::min(service.data().size(), sizeof(services->data));
             services->data_length = service.data().size();
    -        memcpy(services->data, service.data().data(), service.data().size());
    +        memcpy(services->data, service.data().data(), copy_len);
     
             services->characteristic_count = service.characteristics().size();
             if (services->characteristic_count > SIMPLEBLE_CHARACTERISTIC_MAX_COUNT) {
    @@ -304,9 +305,9 @@ simpleble_err_t simpleble_peripheral_manufacturer_data_get(simpleble_peripheral_
     
             auto& selected_manufacturer_data = *it;
             manufacturer_data->manufacturer_id = selected_manufacturer_data.first;
    +        const size_t copy_len = std::min(selected_manufacturer_data.second.size(), sizeof(manufacturer_data->data));
             manufacturer_data->data_length = selected_manufacturer_data.second.size();
    -        memcpy(manufacturer_data->data, selected_manufacturer_data.second.data(),
    -               selected_manufacturer_data.second.size());
    +        memcpy(manufacturer_data->data, selected_manufacturer_data.second.data(), copy_len);
     
             return SIMPLEBLE_SUCCESS;
         } catch (...) {
    
  • simplecble/test/src/test_buffer_overflow.cpp+87 0 added
    @@ -0,0 +1,87 @@
    +#include <gtest/gtest.h>
    +#include <cstring>
    +#include <stdexcept>
    +#include <vector>
    +#include "backends/common/PeripheralBase.h"
    +#include "backends/common/ServiceBase.h"
    +#include "simpleble/Peripheral.h"
    +#include "simplecble/peripheral.h"
    +#include "simplecble/types.h"
    +
    +using namespace SimpleBLE;
    +
    +class MockPeripheralBase : public PeripheralBase {
    +  public:
    +    MockPeripheralBase() = default;
    +    virtual ~MockPeripheralBase() = default;
    +
    +    void* underlying() const override { return nullptr; }
    +    std::string identifier() override { return ""; }
    +    BluetoothAddress address() override { return ""; }
    +    BluetoothAddressType address_type() override { return BluetoothAddressType::PUBLIC; }
    +    int16_t rssi() override { return 0; }
    +    int16_t tx_power() override { return 0; }
    +    uint16_t mtu() override { return 0; }
    +    void connect() override {}
    +    void disconnect() override {}
    +    bool is_connected() override { return false; }
    +    bool is_connectable() override { return false; }
    +    bool is_paired() override { return false; }
    +    void unpair() override {}
    +
    +    std::vector<std::shared_ptr<ServiceBase>> available_services() override { return {}; }
    +    std::vector<std::shared_ptr<ServiceBase>> advertised_services() override { return {}; }
    +
    +    std::map<uint16_t, ByteArray> manufacturer_data() override {
    +        // Return > 27 bytes to test buffer overflow
    +        ByteArray large_data(std::string(50, 'A'));
    +        return {{0x1234, large_data}};
    +    }
    +
    +    ByteArray read(BluetoothUUID const&, BluetoothUUID const&) override { return ""; }
    +    void write_request(BluetoothUUID const&, BluetoothUUID const&, ByteArray const&) override {}
    +    void write_command(BluetoothUUID const&, BluetoothUUID const&, ByteArray const&) override {}
    +    void notify(BluetoothUUID const&, BluetoothUUID const&, std::function<void(ByteArray)>) override {}
    +    void indicate(BluetoothUUID const&, BluetoothUUID const&, std::function<void(ByteArray)>) override {}
    +    void unsubscribe(BluetoothUUID const&, BluetoothUUID const&) override {}
    +    ByteArray read(BluetoothUUID const&, BluetoothUUID const&, BluetoothUUID const&) override { return ""; }
    +    void write(BluetoothUUID const&, BluetoothUUID const&, BluetoothUUID const&, ByteArray const&) override {}
    +    void set_callback_on_connected(std::function<void()>) override {}
    +    void set_callback_on_disconnected(std::function<void()>) override {}
    +};
    +
    +class MockPeripheralBaseService : public MockPeripheralBase {
    +  public:
    +    std::vector<std::shared_ptr<ServiceBase>> advertised_services() override {
    +        return {std::make_shared<ServiceBase>("1234", ByteArray(std::string(50, 'B')))};
    +    }
    +};
    +
    +class MockPeripheral : public SimpleBLE::Peripheral {
    +  public:
    +    MockPeripheral(std::shared_ptr<SimpleBLE::PeripheralBase> base) { this->internal_ = base; }
    +};
    +
    +TEST(BufferOverflowTest, ManufacturerDataOverflow) {
    +    auto base = std::make_shared<MockPeripheralBase>();
    +    MockPeripheral mp(base);
    +    simpleble_peripheral_t handle = static_cast<simpleble_peripheral_t>(&mp);
    +
    +    simpleble_manufacturer_data_t out_data;
    +    simpleble_err_t err = simpleble_peripheral_manufacturer_data_get(handle, 0, &out_data);
    +    EXPECT_EQ(err, SIMPLEBLE_SUCCESS);
    +    // Even though size is 50, memory should not be corrupted.
    +    // And length should report actual size 50 so user knows it was truncated in the 27 byte array.
    +    EXPECT_EQ(out_data.data_length, 50);
    +}
    +
    +TEST(BufferOverflowTest, ServicesOverflow) {
    +    auto base = std::make_shared<MockPeripheralBaseService>();
    +    MockPeripheral mp(base);
    +    simpleble_peripheral_t handle = static_cast<simpleble_peripheral_t>(&mp);
    +
    +    simpleble_service_t out_data;
    +    simpleble_err_t err = simpleble_peripheral_services_get(handle, 0, &out_data);
    +    EXPECT_EQ(err, SIMPLEBLE_SUCCESS);
    +    EXPECT_EQ(out_data.data_length, 50);
    +}
    

Vulnerability mechanics

Root cause

"Stack-based buffer overflows occur when processing oversized data in BLE advertisements and during write operations."

Attack vector

An attacker can trigger stack overflows by sending specially crafted BLE advertisements containing oversized manufacturer-specific data or service data. Additionally, a stack overflow can be triggered in the dongl backend's `Protocol::simpleble_write` function by providing input that exceeds the maximum allowed size. These vulnerabilities can be triggered remotely without requiring pairing or connection for advertisement-related overflows, and locally for the write operation overflow [ref_id=1].

Affected code

The vulnerabilities are located in the handling of BLE advertisement data and the `simpleble_write` function. Specifically, the `simplecble/src/peripheral.cpp` file is affected in the `simpleble_peripheral_services_get` and `simpleble_peripheral_manufacturer_data_get` functions, and the `simpleble/src/backends/dongl/serial/Protocol.cpp` file is affected in the `simpleble_write` function [patch_id=5422991].

What the fix does

The patch addresses stack buffer overflows by adding checks to ensure that data copied into fixed-size buffers does not exceed the buffer's capacity. Specifically, in `simplecble/src/peripheral.cpp`, `std::min` is used to limit the copy length for manufacturer data and service data to the size of the destination buffer. Similarly, in `simpleble/src/backends/dongl/serial/Protocol.cpp`, a check is added to throw a `std::length_error` if the input data size for `simpleble_write` exceeds 512 bytes, preventing buffer overflows [patch_id=5422991].

Preconditions

  • inputOversized manufacturer data or service data in BLE advertisements.
  • inputData exceeding 512 bytes provided to the `simpleble_write` function.

Generated on Jun 10, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.