{"id":"CVE-2026-76787","kind":"vulnerability","aliases":["CVE-2026-76787"],"related":[],"title":"Zephyr UpdateHub: malformed CoAP probe reply crashes the device on each poll","description":"The UpdateHub firmware-over-the-air client parses the CoAP probe response with Zephyr's JSON library in z_impl_updatehub_probe() (subsys/mgmt/updatehub/updatehub.c). The decoder treats every descriptor field as optional — json_obj_parse() returns a bitmask of the fields it actually decoded and never fails on a missing one — so a response that omits the \"sha256sum\" string leaves the corresponding const char * in the zero-initialised struct resp_probe_any_boards / struct resp_probe_some_boards at NULL. Both metadata branches then computed sha256size = strlen(...objects.sha256sum) + 1 before any validation, dereferencing that NULL pointer; the SHA256_HEX_DIGEST_SIZE test that follows operates on a value the bad read has already produced and cannot prevent it.\n\nThe metadata is supplied entirely by the network peer: probe_cb() accepts the datagram, runs coap_packet_parse() and copies the payload with no token matching and no cryptographic check. With CONFIG_UPDATEHUB_DTLS unset — the default — start_coap_client() uses plain CoAP over UDP on port 5683 with no peer authentication and resolves the server via unauthenticated DNS, so an on-path attacker, a DNS spoofer, or an off-path attacker who wins the race with a forged source address can deliver the malformed metadata. A probe response as simple as \"objects\":[[{}],[{}]] suffices, and no user interaction is required because updatehub_autohandler() polls on CONFIG_UPDATEHUB_POLL_INTERVAL. When CONFIG_UPDATEHUB_DTLS=y the trigger narrows to a malicious or compromised update server.\n\nThe primitive is a read at address zero, not a write, so the impact is availability only. On targets where the low address range is unmapped or protected — MMU-based architectures, builds with CONFIG_NULL_POINTER_EXCEPTION_DETECTION_DWT/_MPU/_PMP, TrustZone non-secure images, and SoCs such as nRF54L whose 0x0–0x400 window is unmapped — the load faults and Zephyr's default fatal handler halts the system, giving a remotely re-triggerable denial of service on every poll. On classic Cortex-M targets where the vector table is readable at address zero the walk usually terminates immediately and the request is rejected by the length check, so the outcome is configuration- and SoC-dependent. There is no memory write, and the copied bytes are only compared against the locally computed image hash, so there is no information-disclosure channel.\n\nThe fix adds an explicit sha256sum == NULL test that returns UPDATEHUB_METADATA_ERROR ahead of the strlen() in both metadata branches. Debug builds (CONFIG_UPDATEHUB_LOG_LEVEL=4) still format the same pointers with %s in a LOG_DBG() loop that runs before the new checks, so that variant remains in debug configurations only.","summary":"The UpdateHub firmware-update client in Zephyr dereferences a NULL pointer when a CoAP probe response omits the sha256sum field. A network peer that sends such a response can crash the device every time it polls.","severity":"medium","cvss":5.9,"epss":null,"exploited":false,"exploited_at":null,"products":[],"ecosystems":[],"tags":["embedded","firmware-update","iot","runtime","updatehub","zephyr"],"not_affected_if":["dtls-enabled","no-polling","updatehub-not-used"],"how_to_check":"- Check whether the build enables UpdateHub, for example with `CONFIG_UPDATEHUB` in the project configuration.\n- Check whether `CONFIG_UPDATEHUB_DTLS` is unset, which leaves the probe on plain CoAP over UDP port 5683.\n- Check the Zephyr version in the tree with `west list zephyr` or the `VERSION` file.","fix":"- Move Zephyr to a release that includes the sha256sum NULL check in subsys/mgmt/updatehub/updatehub.c; the exact fixed version is unknown from the sources.\n- Enable `CONFIG_UPDATEHUB_DTLS=y` and point the client at a trusted update server to remove the on-path trigger.\n- Until patched, disable UpdateHub polling or the updatehub autohandler if the product allows it.","status":"open","published_at":"2026-10-19T21:18:01+00:00","first_seen_at":"2026-10-23T21:57:19+00:00","triaged_at":"2026-10-25T04:08:44+00:00","updated_at":"2026-10-25T04:08:44+00:00","category":"runtime","confidence":0.8,"triage":{"at":"2026-10-25T04:08:44Z","model":"claude-haiku-5-5","output":{"fix":"- Move Zephyr to a release that includes the sha256sum NULL check in subsys/mgmt/updatehub/updatehub.c; the exact fixed version is unknown from the sources.\n- Enable `CONFIG_UPDATEHUB_DTLS=y` and point the client at a trusted update server to remove the on-path trigger.\n- Until patched, disable UpdateHub polling or the updatehub autohandler if the product allows it.","reach":"network","title":"Zephyr UpdateHub: malformed CoAP probe reply crashes the device on each poll","impact":"low","summary":"The UpdateHub firmware-update client in Zephyr dereferences a NULL pointer when a CoAP probe response omits the sha256sum field. A network peer that sends such a response can crash the device every time it polls.","category":"runtime","nicknames":[],"who_cares":["zephyr","embedded","iot","firmware-update","updatehub"],"confidence":0.8,"needs_auth":"no","worst_case":"device halts on every poll, remotely repeatable denial of service","analyst_note":"","how_to_check":"- Check whether the build enables UpdateHub, for example with `CONFIG_UPDATEHUB` in the project configuration.\n- Check whether `CONFIG_UPDATEHUB_DTLS` is unset, which leaves the probe on plain CoAP over UDP port 5683.\n- Check the Zephyr version in the tree with `west list zephyr` or the `VERSION` file.","needs_analyst":false,"not_affected_if":["updatehub-not-used","dtls-enabled","no-polling"],"who_is_affected":"Zephyr devices that run the UpdateHub firmware-over-the-air client and poll a server for updates. The default build uses unauthenticated plain CoAP over UDP, so any network peer on the path or able to spoof DNS can trigger it. Systems that enable DTLS limit the trigger to a malicious or compromised update server, and devices without UpdateHub are not affected.","user_interaction":"no","needs_special_setup":"yes","severity_if_unknown":"medium"},"cost_usd":0.000786,"input_tokens":4232,"output_tokens":726,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-2026':14A,17A '-76787':15A,18A '0x0':360C '0x400':361C '1':153C '4':480C '5683':230C 'accept':194C 'actual':106C 'add':455C 'address':265C,315C,331C,402C 'ahead':466C 'air':70C 'alreadi':177C 'architectur':340C 'attack':247C,256C 'authent':234C 'autohandl':287C 'avail':324C 'bad':174C 'base':339C 'bitmask':101C 'board':137C,142C 'branch':147C,473C 'build':341C,475C 'byte':435C 'cannot':180C 'cb':193C 'channel':452C 'char':127C 'check':212C,417C,498C 'classic':390C 'client':32B,71C,222C 'coap':4A,41B,74C,198C,221C,225C 'compar':438C 'compromis':306C 'comput':149C,442C 'config':214C,290C,295C,343C,476C 'configur':422C,505C 'const':126C 'copi':202C,434C 'correspond':125C 'cortex':392C 'cortex-m':391C 'crash':7A,57B 'cryptograph':211C 'cve':13A,16A 'datagram':196C 'dbg':491C 'debug':474C,504C 'decod':89C,107C 'default':219C,371C 'deliv':267C 'denial':383C 'depend':426C 'derefer':35B 'dereferenc':157C 'descriptor':92C 'detect':347C 'devic':9A,59B 'digest':164C 'disclosur':451C 'dns':241C,249C 'dtls':216C,297C 'dwt/_mpu/_pmp':348C 'embed':19B 'entir':187C 'error':465C 'everi':60B,91C,387C 'except':346C 'explicit':457C 'fail':110C 'fatal':372C 'fault':367C 'field':47B,93C,104C 'firmwar':21B,30B,67C 'firmware-over-the-air':66C 'firmware-upd':20B,29B 'fix':454C 'follow':168C 'forg':263C 'format':482C 'give':377C 'halt':374C 'handler':373C 'hash':444C 'hex':163C 'imag':353C,443C 'immedi':408C 'impact':322C 'impl':84C 'inform':450C 'information-disclosur':449C 'initialis':132C 'interact':282C 'interv':293C 'iot':23B 'json':80C,96C 'leav':123C 'length':416C 'level':479C 'librari':81C 'load':366C 'local':441C 'log':478C,490C 'loop':492C 'low':330C 'm':393C 'malform':3A,269C 'malici':304C 'match':208C 'memori':430C 'metadata':146C,184C,270C,464C,472C 'miss':113C 'mmu':338C 'mmu-bas':337C 'narrow':301C 'network':49B,190C 'never':109C 'new':497C 'non':351C 'non-secur':350C 'nrf54l':358C 'null':37B,144C,159C,344C,459C 'obj':97C 'object':277C 'objects.sha256sum':152C 'off-path':253C 'omit':44B,119C 'on-path':244C 'one':114C 'oper':169C 'option':95C 'outcom':420C 'packet':199C 'pars':72C,98C,200C 'path':246C,255C 'payload':204C 'peer':50B,191C,233C 'plain':224C 'pointer':38B,160C,345C,485C 'poll':12A,63B,288C,292C,388C 'port':229C 'prevent':181C 'primit':310C 'probe':5A,42B,75C,86C,135C,140C,192C,272C 'produc':178C 'protect':336C 'race':260C 'rang':332C 're':381C 're-trigger':380C 'read':175C,313C 'readabl':400C 'reject':413C 'remain':502C 'remot':379C 'repli':6A 'request':411C 'requir':284C 'resolv':236C 'resp':134C,139C 'respons':43B,55B,76C,117C,273C 'return':99C,462C 'run':197C,494C 'runtim':24B 'secur':352C 'send':52B 'server':238C,308C 'servic':385C 'sha256':162C 'sha256size':150C 'sha256sum':46B,121C,458C 'simpl':275C 'size':165C 'soc':355C,425C 'soc-depend':424C 'sourc':264C 'spoofer':250C 'start':220C 'still':481C 'string':122C 'strlen':151C,469C 'struct':133C,138C 'subsys/mgmt/updatehub/updatehub.c':87C 'suffic':278C 'suppli':186C 'system':376C 'tabl':398C 'target':327C,394C 'termin':407C 'test':166C,460C 'time':61B 'token':207C 'treat':90C 'trigger':300C,382C 'trustzon':349C 'udp':227C 'unauthent':240C 'unmap':334C,364C 'unset':217C 'updat':22B,31B,307C 'updatehub':2A,25B,28B,65C,85C,215C,286C,291C,296C,463C,477C 'use':223C 'user':281C 'usual':406C 'valid':156C 'valu':172C 'variant':501C 'vector':397C 'via':239C 'walk':405C 'whose':359C 'win':258C 'window':362C 'write':319C,431C 'y':298C 'z':83C 'zephyr':1A,26B,34B,78C,369C 'zero':131C,316C,403C 'zero-initialis':130C","nicknames":[],"mitigations":[],"who_affected":"Zephyr devices that run the UpdateHub firmware-over-the-air client and poll a server for updates. The default build uses unauthenticated plain CoAP over UDP, so any network peer on the path or able to spoof DNS can trigger it. Systems that enable DTLS limit the trigger to a malicious or compromised update server, and devices without UpdateHub are not affected.","tier":"C","verified":{},"analyst_revisit_at":null,"first_public_at":"2026-10-19T21:18:01+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H","cvss_by":"vulnerabilities@zephyrproject.org","poc_count":0,"sources":[{"source":"nvd","external_id":"CVE-2026-76787","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-76787","severity":null,"published_at":"2026-10-19T21:18:01+00:00","modified_at":"2026-10-20T19:59:00+00:00","first_seen_at":"2026-10-23T21:57:19+00:00","fetched_at":"2026-10-23T22:28:57+00:00","note":null}],"documents":[],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}