← Back to CVE Explorer

CVE-2026-10849

Full vulnerability record from the local CVENow database.

Description

The hawkBit device management client in subsys/mgmt/hawkbit accumulates the body of an HTTP response from the update server into a heap buffer in response_json_cb() (subsys/mgmt/hawkbit/hawkbit.c). The buffer is sized to hold the received body bytes but reserves no space for a terminating NUL. When the full response has arrived, the code writes response_data[downloaded_size] = '\0' — and whenever the accumulated body length equals the allocation, that terminator lands one byte past the end of the heap object (a heap-based out-of-bounds write, CWE-122 / CWE-787). The body length and fragmentation are taken directly from the parsed HTTP response (rsp->body_frag_start / rsp->body_frag_len) and are fully controlled by the remote hawkBit server, which chooses its own response length. The precise trigger depends on how the buffer grows, and both forms are remotely reachable. Since v4.0.0 the reallocation is sized to exactly downloaded_size + body_len, so any response body larger than the 1100-byte initial buffer makes the out-of-bounds write deterministic; such response sizes are normal for hawkBit deployment metadata. Before v4.0.0 the buffer grew by doubling and the growth check ((downloaded_size + body_len) > response_buffer_size) is false at equality, so a response body whose length is exactly the current allocation — 1100 bytes with the default initial buffer — skips the reallocation entirely and writes the terminator at response_data[1100] of an 1100-byte object. The HTTP length-mismatch check does not catch this, because the declared and received lengths genuinely agree. Either form is reachable by a malicious, compromised, or man-in-the-middle update server (TLS is optional and, when enabled, does not protect against a hostile server), with no authentication of response content and no client-side length cap protecting the write. The out-of-bounds write is a fixed single NUL byte immediately following the allocation, corrupting adjacent allocator metadata or the next allocation. The practical impact is heap corruption leading to denial of service (fault on a subsequent allocation or free), with the bounded, allocator-dependent possibility of further corruption. The fix sizes the buffer to the body length plus one and copies with memcpy, ensuring the terminator always lands within the allocation.

Severity
HIGH
CVSS score
7.5 (v3.1)
Vulnerability status
Analyzed
Source identifier
Published
2026-08-03 22:16:47.963000
Last modified
2026-10-23 21:10:00.157000
View original CVE JSON
{
  "id": "CVE-2026-10849",
  "sourceIdentifier": "[email protected]",
  "published": "2026-08-03T22:16:47.963",
  "lastModified": "2026-10-23T21:10:00.157",
  "vulnStatus": "Analyzed",
  "cveTags": [],
  "descriptions": [
    {
      "lang": "en",
      "value": "The hawkBit device management client in subsys/mgmt/hawkbit accumulates the body of an HTTP response from the update server into a heap buffer in response_json_cb() (subsys/mgmt/hawkbit/hawkbit.c). The buffer is sized to hold the received body bytes but reserves no space for a terminating NUL. When the full response has arrived, the code writes response_data[downloaded_size] = '\\0' — and whenever the accumulated body length equals the allocation, that terminator lands one byte past the end of the heap object (a heap-based out-of-bounds write, CWE-122 / CWE-787).\n\nThe body length and fragmentation are taken directly from the parsed HTTP response (rsp->body_frag_start / rsp->body_frag_len) and are fully controlled by the remote hawkBit server, which chooses its own response length. The precise trigger depends on how the buffer grows, and both forms are remotely reachable. Since v4.0.0 the reallocation is sized to exactly downloaded_size + body_len, so any response body larger than the 1100-byte initial buffer makes the out-of-bounds write deterministic; such response sizes are normal for hawkBit deployment metadata. Before v4.0.0 the buffer grew by doubling and the growth check ((downloaded_size + body_len) > response_buffer_size) is false at equality, so a response body whose length is exactly the current allocation — 1100 bytes with the default initial buffer — skips the reallocation entirely and writes the terminator at response_data[1100] of an 1100-byte object. The HTTP length-mismatch check does not catch this, because the declared and received lengths genuinely agree. Either form is reachable by a malicious, compromised, or man-in-the-middle update server (TLS is optional and, when enabled, does not protect against a hostile server), with no authentication of response content and no client-side length cap protecting the write.\n\nThe out-of-bounds write is a fixed single NUL byte immediately following the allocation, corrupting adjacent allocator metadata or the next allocation. The practical impact is heap corruption leading to denial of service (fault on a subsequent allocation or free), with the bounded, allocator-dependent possibility of further corruption. The fix sizes the buffer to the body length plus one and copies with memcpy, ensuring the terminator always lands within the allocation."
    },
    {
      "lang": "es",
      "value": "El cliente de gestión de dispositivos hawkBit en subsys/mgmt/hawkbit acumula el cuerpo de una respuesta HTTP del servidor de actualización en un búfer de pila en response_json_cb() (subsys/mgmt/hawkbit/hawkbit.c). El búfer está dimensionado para contener los bytes del cuerpo recibidos, pero no reserva espacio para un NUL de terminación. Cuando ha llegado la respuesta completa, el código escribe response_data[downloaded_size] = ’\\0’ - y siempre que la longitud del cuerpo acumulado sea igual a la asignación, ese terminador cae un byte más allá del final del objeto de pila (una escritura fuera de límites basada en pila, CWE-122 / CWE-787).\n\nLa longitud del cuerpo y la fragmentación se toman directamente de la respuesta HTTP analizada (rsp  ->  body_frag_start / rsp  ->  body_frag_len) y están totalmente controladas por el servidor hawkBit remoto, que elige su propia longitud de respuesta. El disparador preciso depende de cómo crece el búfer, y ambas formas son accesibles de forma remota. Desde la v4.0.0 la reasignación se dimensiona exactamente a downloaded_size + body_len, por lo que cualquier cuerpo de respuesta mayor que el búfer inicial de 1100 bytes hace que la escritura fuera de límites sea determinista; tales tamaños de respuesta son normales para los metadatos de despliegue de hawkBit. Antes de la v4.0.0 el búfer crecía duplicándose y la comprobación de crecimiento ((downloaded_size + body_len) > response_buffer_size) es falsa en la igualdad, por lo que un cuerpo de respuesta cuya longitud es exactamente la asignación actual - 1100 bytes con el búfer inicial predeterminado - omite la reasignación por completo y escribe el terminador en response_data[1100] de un objeto de 1100 bytes. La comprobación de falta de coincidencia de longitud HTTP no detecta esto, porque las longitudes declaradas y recibidas coinciden genuinamente. Cualquiera de las formas es alcanzable por un servidor de actualización malicioso, comprometido o man-in-the-middle (TLS es opcional y, cuando está habilitado, no protege contra un servidor hostil), sin autenticación del contenido de la respuesta y sin límite de longitud del lado del cliente que proteja la escritura.\n\nLa escritura fuera de límites es un único byte NUL fijo inmediatamente después de la asignación, corrompiendo los metadatos adyacentes del asignador o la siguiente asignación. El impacto práctico es la corrupción de la pila que lleva a la denegación de servicio (fallo en una asignación o liberación posterior), con la posibilidad limitada y dependiente del asignador de una mayor corrupción. La solución dimensiona el búfer a la longitud del cuerpo más uno y copia con memcpy, asegurando que el terminador siempre caiga dentro de la asignación."
    }
  ],
  "affected": [
    {
      "source": "[email protected]",
      "affectedData": [
        {
          "vendor": "zephyrproject",
          "product": "zephyr",
          "defaultStatus": "unaffected",
          "collectionURL": "https://github.com/zephyrproject-rtos/zephyr",
          "packageName": "zephyr",
          "programFiles": [
            "subsys/mgmt/hawkbit/hawkbit.c"
          ],
          "versions": [
            {
              "version": "2.4.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:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H",
          "baseScore": 8.2,
          "baseSeverity": "HIGH",
          "attackVector": "NETWORK",
          "attackComplexity": "LOW",
          "privilegesRequired": "NONE",
          "userInteraction": "NONE",
          "scope": "UNCHANGED",
          "confidentialityImpact": "NONE",
          "integrityImpact": "LOW",
          "availabilityImpact": "HIGH"
        },
        "exploitabilityScore": 3.9,
        "impactScore": 4.2
      },
      {
        "source": "[email protected]",
        "type": "Primary",
        "cvssData": {
          "version": "3.1",
          "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
          "baseScore": 7.5,
          "baseSeverity": "HIGH",
          "attackVector": "NETWORK",
          "attackComplexity": "LOW",
          "privilegesRequired": "NONE",
          "userInteraction": "NONE",
          "scope": "UNCHANGED",
          "confidentialityImpact": "NONE",
          "integrityImpact": "NONE",
          "availabilityImpact": "HIGH"
        },
        "exploitabilityScore": 3.9,
        "impactScore": 3.6
      }
    ],
    "ssvcV203": [
      {
        "source": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
        "ssvcData": {
          "timestamp": "2026-08-04T19:29:17.471804Z",
          "id": "CVE-2026-10849",
          "options": [
            {
              "exploitation": "none"
            },
            {
              "automatable": "yes"
            },
            {
              "technicalImpact": "partial"
            }
          ],
          "role": "CISA Coordinator",
          "version": "2.0.3"
        }
      }
    ]
  },
  "weaknesses": [
    {
      "source": "[email protected]",
      "type": "Secondary",
      "description": [
        {
          "lang": "en",
          "value": "CWE-122"
        },
        {
          "lang": "en",
          "value": "CWE-787"
        }
      ]
    }
  ],
  "configurations": [
    {
      "nodes": [
        {
          "operator": "OR",
          "negate": false,
          "cpeMatch": [
            {
              "vulnerable": true,
              "criteria": "cpe:2.3:o:zephyrproject:zephyr:*:*:*:*:*:*:*:*",
              "versionStartIncluding": "2.4.0",
              "versionEndExcluding": "4.5.0",
              "matchCriteriaId": "00A2B469-12D7-40D8-BF4A-CEFDEB9DC72A"
            }
          ]
        }
      ]
    }
  ],
  "references": [
    {
      "url": "https://github.com/zephyrproject-rtos/zephyr/commit/59d7ab58d853489e6134081cadb11733730264ac",
      "source": "[email protected]",
      "tags": [
        "Patch"
      ]
    },
    {
      "url": "https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-39h3-7phx-pwhv",
      "source": "[email protected]",
      "tags": [
        "Exploit",
        "Patch",
        "Vendor Advisory"
      ]
    }
  ]
}