Where
-Infinity
0
Severity
8.8
AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

The OSDP Control Panel reply parser cpdecoderesponse() in subsys/mgmt/osdp/src/osdpcp.c decodes replies from a Peripheral Device into a stack-allocated struct osdpevent. For the REPLYKEYPPAD and REPLYRAW reply types, the payload length is taken from the received frame and the only validation performed is that the declared length is self-consistent with the number of payload bytes present in the frame. Because the attacker controls both the length field and the frame length, that check imposes no bound, and the subsequent memcpy() writes into the fixed 64-byte data arrays of struct osdpeventkeypress / struct osdpeventcardread (OSDPEVENTMAXDATALEN). The sibling REPLYFMT handler in the same switch already carried the missing > OSDPEVENTMAXDATALEN bound.

The defect is reached from cpprocessreply(), which reads bytes from the OSDP RS-485 channel and passes them through osdpphycheckpacket() and osdpphydecodepacket() before dispatching on the reply ID. Triggering it requires CONFIGOSDP with CONFIGOSDPMODECP and an application event callback registered (the normal Control Panel integration), plus a frame carrying a correct SOM, a valid CRC-16, and a matching 2-bit sequence number — all of which are computable or observable by anyone on the bus. No check ties the reply ID to the outstanding command, so an oversized REPLYKEYPPAD or REPLYRAW is accepted as the answer to a routine CMDPOLL. A malicious or compromised card reader, or anyone with access to the RS-485 wiring, can supply such a frame; CONFIGOSDPSCENABLED only helps while a secure channel is active, and a single unauthenticated frame carrying a bad MAC causes scdeactivate(), after which plaintext replies are again accepted.

With the default CONFIGOSDPUARTBUFFERLENGTH of 256, roughly 180 bytes of fully attacker-chosen data can be written past the end of the stack-allocated event object, over saved registers and the return address on typical Cortex-M and RISC-V frame layouts (Zephyr does not enable stack canaries by default). The impact ranges from a hard crash of the access-control panel to potential control-flow hijack in the context of the OSDP receive thread. The fix adds an OSDPEVENTMAXDATALEN bound to both handlers, capping each memcpy() at the size of its destination.

First published (updated )
Severity
7.1
AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:H

ethernetrecv() in subsys/net/l2/ethernet/ethernet.c validates only that the first netbuf of a received frame holds a plain 14-byte struct netethhdr. When the ethertype is 0x8100 and VLAN is enabled on the interface, the same buffer is reinterpreted as the 18-byte struct netethvlanhdr without re-checking the length: the VLAN TCI and the inner ethertype are read from offsets 14..17, past pkt->buffer->len, and hdrlen is raised to 18 so the subsequent netbufpull() removes more bytes than the buffer holds.

A single unauthenticated frame of 14 to 17 bytes carrying the VLAN ethertype triggers this. No knowledge of the node's VLAN configuration is needed: netethgetvlaniface() returns the base interface for the priority tag 0, and a broadcast destination address satisfies the "frame is for me" test, so a 16-byte broadcast frame with ethertype 0x8100 and TCI 0x0000 reaches the pull. Nothing in the receive path enforces the 60-byte Ethernet minimum — the USB CDC ECM and CDC NCM gadget classes in particular hand host-supplied frames of any non-zero length straight to netrecvdata().

With assertions enabled, netbufsimplepull() asserts and the node panics. In a production build (assertions and CONFIGNETBUFHARDENING off) the uint16t buffer length underflows to 65534 and buf->data is advanced past the end of the fragment's storage, so every later parser reads far outside the buffer and any netbufadd() on that fragment computes tailroom from the underflowed length. The result is a reliable remote denial of service and out-of-bounds access with information-disclosure and corruption potential.

Only configurations built with CONFIGNETVLAN=y that have a VLAN enabled on the receiving Ethernet interface, and whose MAC does not strip VLAN tags in hardware (ETHERNETHWVLANTAGSTRIP), are affected. The fix rejects the frame before the tag is read, so hdrlen is thereafter either 14 or 18 with both sizes validated against pkt->buffer->len.

First published (updated )
Severity
5.9
Use After Free, Double Free
AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:H

The Bluetooth host's ATT transmit path releases a buffer it does not own when signing fails. chansend() in subsys/bluetooth/host/att.c documents (and every other error exit implements) the contract that on failure the caller retains ownership of the netbuf; the BTATTOPSIGNEDWRITECMD branch instead called netbufunref(buf) when btsmpsign() returned an error and then returned that error to the caller. The callers act on the contract: processqueue() re-queues the buffer with kqueueprepend(), btattchansendrsp() puts it back on chan->txqueue, btattchanreqsend() restores it into the request, and attreqretry() unreferences it — so the already-freed buffer was re-queued, later dereferenced, and eventually freed again.

An ATT Signed Write Command is produced when an application calls btgattwritewithoutresponsecb() with sign set on an unencrypted connection. btsmpsign() fails whenever no local CSRK exists for the peer (-ENOENT), and whether one exists is negotiated with the peer: smpdistributekeys() stores a local CSRK only when the peer's pairing key-distribution field requests the signing key and bonding was agreed. A peer can therefore pair without accepting the CSRK, pair with No Bonding, remain unpaired, or keep the link unencrypted, and the victim's next signed write takes the failing path. Because struct netbuf's node field is simultaneously the linkage word for the ATT TX FIFO, for the deferred-destroy list used by the attpool destroy callback atttxdestroy(), and for the pool free list, the mishandled buffer corrupts these lists and can be re-issued by btattcreatepdu() to a new PDU while the ATT TX path still holds it.

The same branch also saved the netbufsimplestate only after signing, so a buffer restored after a btl2capsendpdu() failure kept its 12-octet signature; a subsequent retry re-signed it and appended a second signature with netbufadd(buf, 12) to a buffer that btattcreatepdu() sized for exactly one, writing past the end of the pooled buffer in builds where the netbuf tailroom assertion is compiled out.

Impact is host-side memory corruption in the Bluetooth stack: list corruption, a pooled ATT buffer with two owners (wrong PDU contents transmitted, or a double free when the queues are drained at disconnect), and a bounded out-of-bounds write on the retry path — typically observed as a crash or assertion failure. Exposure requires the deprecated CONFIGBTSIGNING to be enabled and an application that actually issues signed writes; in that configuration the triggering condition is under the remote peer's control.

First published (updated )
Severity
7.5
Use After Free
AV:A/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H

The Bluetooth LE host queues received L2CAP connection-oriented channel (CoC) data for deferred processing through a struct kwork embedded in the channel object (lechan->rxwork, handler l2caprxprocess()) whenever the channel uses a dynamic PSM (0x0080-0x00FF). Channel teardown in l2capchandestroy() in subsys/bluetooth/host/l2cap.c cancels the retransmission-timeout work and drains the RX FIFO, but never cancels rxwork. Because that work item was submitted to the system workqueue while HCI receive processing runs on the dedicated Bluetooth RX workqueue (CONFIGBTRECVWORKQBT, the default), a queued rxwork item can outlive the channel it points into.

A remote, unauthenticated peer with an established CoC channel triggers this by sending a data K-frame immediately followed by an L2CAP Disconnect Request. The K-frame submits rxwork to the system workqueue; because both workqueue threads are cooperative and the Bluetooth RX workqueue runs at the higher priority (KPRIOCOOP(CONFIGBTRXPRIO) versus CONFIGSYSTEMWORKQUEUEPRIORITY), the pending item cannot run before the following Disconnect Request is processed in ledisconnreq() -> l2capchandel() -> l2capchandestroy(). The stack then invokes the released() callback, which the API documents as meaning the stack has dropped all references and the application may free the channel memory.

The application therefore frees or re-accepts into an object that the system workqueue still holds in its pending list. If the memory is freed and reallocated, the workqueue later dereferences a list node and a handler function pointer read from reused memory; if the object is re-used for a later connection, l2capchanadd() calls kworkinit() on a still-enqueued work item, corrupting the workqueue's pending list so that unrelated work items are dropped or the queue spins on a looped list. A related variant lets l2caprxprocess() run concurrently with teardown, racing the netbuf unref of lechan->sdu and the clearing of chan->conn.

The fix routes the channel RX work to the Bluetooth workqueue - the same context in which every teardown path runs - and adds an explicit kworkcancel() of lechan->rxwork in l2capchandestroy(), so no reference to the channel survives the released() callback. Configurations without CONFIGBTL2CAPDYNAMICCHANNEL, or that only use SIG-assigned PSMs (EATT 0x0027, OTS 0x0025) which take the inline receive path, are not affected.

First published (updated )
Severity
5.5
Null Pointer Dereference
AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

i2sesp32triggercheck() in drivers/i2s/i2sesp32.c validates the requested direction only for I2SDIRBOTH. The I2SDIRRX and I2SDIRTX branches read devcfg->rx.data->configured / devcfg->tx.data->configured without first checking the stream pointers. The device instantiation macro I2SESP32STREAMINIT() sets both .conf and .data to NULL for a direction the devicetree does not describe, so on an instance that wires only one direction — the normal shape for audio output or a worldsemi,ws2812-i2s LED strip — the other direction dereferences a NULL pointer instead of returning an error.

i2strigger() is a Zephyr syscall, and zvrfyi2strigger() in drivers/i2s/i2shandlers.c validates only the device object and the presence of the trigger API pointer; the dir argument is passed to the driver unvalidated. On a build with CONFIGUSERSPACE enabled, a user-mode thread that has been granted the I2S device can issue a single i2strigger() call naming the unwired direction and cause a load from address 0 in kernel mode. Among the Espressif parts that carry this driver, userspace is available in-tree only on RISC-V SoCs with CONFIGRISCVPMP, and v4.4.0 is the first release where that is buildable: the ESP32-C6 HPCORE selects RISCVPMP when it is not built for MCUboot. ESP32-C5 in v4.4.x carries the same PMP-region and userspace linker support but does not select RISCVPMP by default. Espressif Xtensa targets do not support Zephyr userspace, and in a non-userspace build the bad direction can only come from in-kernel application code.

The impact is limited to availability: the access is a read at offset 0 of the missing stream structure, so there is no attacker-controlled offset, no write primitive and no information disclosure. With the default fatal-error handler the resulting exception halts the system, giving an unprivileged user-mode thread a system-wide denial of service. The fix adds the same pointer check the I2SDIRBOTH branch already performed and returns -ENOSYS for a direction the instance does not implement; the driver's other entry points (i2sesp32configcheck(), i2sesp32configget(), i2sesp32read(), i2sesp32write()) already guarded the pointers, and a static audit found no equivalent unguarded path.

The driver defect is older than the affected range. The unguarded dereference is present from v4.2.0 (reached through i2sesp32triggerstream(), whose if (stream) guard tests the address of a struct member and is never false) and takes its present i2sesp32triggercheck() form in v4.3.0. No in-tree Espressif configuration before v4.4.0 can run a user-mode thread, so in v4.2.x and v4.3.x the direction argument can only come from trusted kernel code. Those releases carry the bug but are not listed as affected; the fix has also been merged to v4.3-branch as hardening.

First published (updated )
Severity
7.8
AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

The NXP MCUX TRNG entropy driver in drivers/entropy/entropymcuxtrng.c passed the caller's byte count straight to the vendor SDK routine TRNGGetRandomData(). On i.MX RT5xx and RT6xx parts the SDK compiles its TRNGSWHEALTHTESTS variant, which always copies whole 32-bit words and draws entropy rounded up to a multiple of 128 bytes. Its "caller buffer is full" guard tests dataSize == 0, so a request whose length is not a multiple of four makes dataSize underflow past zero and the SDK keeps writing into the caller's buffer for the entire extraction: a 1-byte request results in 128 bytes written, and any non-word-multiple length overflows by up to 127 bytes.

entropygetentropy() is a syscall, and its verifier in drivers/entropy/entropyhandlers.c validates only the requested length via KSYSCALLMEMORYWRITE(). With CONFIGUSERSPACE enabled, an unprivileged user-mode thread that has merely been granted the entropy device can therefore choose both the destination address and a length such as 1, and cause the kernel to write up to 127 bytes beyond the region it proved it owns. On these Cortex-M33 targets there is no MMU, so user partitions and kernel data share one SRAM and the overflow can land in adjacent kernel state. The same defect is reached from kernel mode by any caller requesting a non-word-multiple length, including getentropy() and, in builds where syscsrandget()/sysrandget() resolve to the hardware generator, sysrand8get() and sysrand16get().

Impact is memory corruption of up to 127 bytes immediately following the supplied buffer — typically the caller's stack in kernel-mode use, or memory outside the caller's partition when driven through the syscall. The overflow offset is fully determined by the requested length and is therefore deterministic, while the written content is uncontrolled TRNG output; the practical consequences range from crashes and unpredictable state corruption to opportunistic escalation when kernel bookkeeping such as object permission bitmaps is overwritten. The affected devices are those where the MCUX SDK enables TRNGSWHEALTHTESTS (MIMXRT595S, MIMXRT555S, MIMXRT533S, MIMXRT685S, MIMXRT633S), on which the TRNG is the zephyr,entropy chosen node; other SoCs using this driver take the SDK path that clamps the copy size and are unaffected.

The fix routes any unaligned prefix and any sub-word tail through a local bounce word and hands the SDK only word-multiple sizes, so the SDK's word-granular writes can no longer pass the end of the caller's buffer.

First published (updated )
Severity
8.8
AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

The Bluetooth Mesh On-Demand Private Proxy solicitation handler in subsys/bluetooth/mesh/solicitation.c copies a received Solicitation PDU into a fixed 17-byte stack buffer without bounding the source length. In solpdudecrypt(), out is allocated as NETBUFSIMPLE(17) and then filled with netbufsimpleaddmem(out, in->data, in->len); netbufsimpleadd() guards its tailroom only with ASSERTNOMSG, which is compiled out in production builds, so when in->len > 17 the underlying memcpy writes attacker-controlled bytes past the 17-byte stack buffer. The copy occurs before any decryption or authentication, so no key material is required to trigger it.

The oversized length arises because the mesh scan callback in subsys/bluetooth/mesh/adv.c calls netbufsimplerestore() before dispatching to btmeshsolrecv(), leaving buf->len covering the entire remaining advertising payload rather than just the Solicitation Service Data. After the parser locates the Service Data AD and consumes the Identification Type byte, the remaining buf->len is the 17-octet Network PDU plus any trailing advertising bytes, and prior to this fix there was no maximum-length check (only a minimum). An attacker can therefore append extra AD structures or padding after the Solicitation Service Data to make buf->len exceed 17.

btmeshscancb() is registered directly as the BLE scan callback, so buf is raw, unauthenticated advertising data received over the air. Any device in radio range can send a non-connectable advertisement carrying a crafted mesh Proxy Solicitation to a node that has CONFIGBTMESHODPRIVPROXYSRV enabled and is currently eligible to be solicited (GATT proxy disabled, On-Demand Private Proxy enabled), with no pairing, bonding, or provisioning. The result is an attacker-controlled stack overwrite — plausibly leading to remote code execution and at minimum a reliable remote denial of service. The fix trims buf->len to the spec-fixed 17 octets (dropping the PDU if fewer remain) before decryption.

First published (updated )
Severity
6.3
AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:H

ieee802154send() in subsys/net/l2/ieee802154/ieee802154.c copies the outgoing packet into a single fixed 125-byte transmit buffer (txframebufpool, sized IEEE802154MTU). In builds with CONFIGNETL2IEEE802154FRAGMENT enabled (the default whenever CONFIGNET6LO is set), the branch taken when 6LoWPAN fragmentation is not required performed an unchecked netbufaddmem(framebuf, pktbuf->data, pktbuf->len). The only guard was ASSERTNOMSG() inside netbufsimpleadd(), which is compiled out without CONFIGASSERT, so an oversized packet silently overran the frame buffer.

The defect is not reachable from the radio: for NETAFINET6 packets ieee8021546loencodepkt() compares the whole packet length against IEEE802154MTU and takes the fragmentation path when it does not fit, so every buffer copied on the unfragmented branch is within bounds. It is reachable through NETAFPACKET sockets bound to an 802.15.4 interface: for NETSOCKRAW the 6LoWPAN block is skipped entirely and for NETSOCKDGRAM it returns early on the address-family test, leaving no length validation anywhere on the transmit path (netcontextsendto() and netiftx() apply none, and pktbufferlength() does not clamp the allocation for this L2).

An application — or, in a CONFIGUSERSPACE build, an unprivileged application thread using the zsocksocket()/zsocksendto() syscalls — can therefore drive a supervisor-mode out-of-bounds write of chosen bytes past the 125-byte pool buffer. With the default CONFIGNETBUFFIXEDDATASIZE of 128 bytes the overrun is bounded to roughly llhdrlen + 3 bytes; with CONFIGNETBUFVARIABLEDATASIZE a single storage buffer can be as large as CONFIGNETPKTBUFTXDATAPOOLSIZE, making the overrun far larger. The consequence is corruption of memory adjacent to the pool, with a crash or further compromise of kernel state as the practical impact.

The fix validates llhdrlen + netpktgetlen(pkt) + authtaglen against IEEE802154MTU before any copy and adds a tailroom-checking copypkttoframe() helper that returns -EMSGSIZE instead of overrunning the buffer. The same change also linearizes the whole netbuf chain into one MAC frame, so packet storage boundaries no longer become frame boundaries on the wire.

First published (updated )
Severity
5.9
Use After Free
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

Zephyr's TLS socket layer in subsys/net/lib/sockets/socketstls.c keeps a single process-global array, clientcache, of cached client sessions that is shared by every TLS socket context. The functions that mutate and read it — tlssessionsave(), tlssessionget(), tlssessioncachereset(), and the settings restore handler — allocate, free, and dereference each entry's heap buffer (entry->session). Before the fix these accesses were serialized only by the per-socket context mutex ctx->lock (assigned per socket in ctxsetlock()), which provides no mutual exclusion between different sockets touching the shared cache.

Because CONFIGNETSOCKETSTLSMAXCLIENTSESSIONCOUNT defaults to 1, any two concurrent client sockets contend for the same slot. A thread in tlssessionget() reading entry->session inside mbedtlssslsessionload() can run concurrently with another thread in tlssessionsave() that selects the same entry for reuse and executes mbedtlsfree(entry->session) before reallocating — a use-after-free read, and a double-free when two saves evict the same entry. Both corrupt the mbedTLS heap. The cache is reached on ordinary client paths: at connect time via tlssessionstore()/tlssessionrestore(), and (on main) whenever a TLS 1.3 session ticket arrives during recv()/poll() via tlssessionstorecurrent().

Exploitation requires an application that opts into per-socket client session caching (the TLSSESSIONCACHE socket option, off by default) and runs concurrent TLS client connections on multiple threads; the timing that opens the window is influenced by the remote peer(s), so a malicious or compromised server can raise session-ticket frequency to widen it. The reliably-demonstrable impact is memory corruption leading to a crash or heap corruption (denial of service). The fix adds a dedicated sessioncachelock mutex taken across every accessor of clientcache, serializing all reads and frees and closing the race.

First published (updated )
Severity
7.5
Null Pointer Dereference
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

The MQTT-SN client keepalive handler processping() in subsys/net/lib/mqttsn/mqttsn.c removes the gateway record after PINGREQ retries are exhausted. It invoked SYSSLISTPEEKHEADCONTAINER(&client->gateways, gw, next) but discarded the result. That macro is a pure expression that does not assign to gw, so gw retained its NULL initializer regardless of the list contents.

The code then dereferences the NULL gw (gw->gwid) and passes it to mqttsngwdestroy(), reaching kmemslabfree(&gateways, NULL). With CONFIGMEMSLABPOINTERVALIDATE enabled this triggers kpanic(); in the default configuration it performs a write through the NULL pointer ((char )mem = slab->freelist;) and corrupts the slab free list. The outcome is a crash/kernel panic or, on targets where address 0 is writable, silent memory-allocator corruption.

The vulnerable branch runs whenever the connected MQTT-SN gateway fails to answer keepalive PINGREQs for the configured number of retries. This condition is controlled by the remote peer: a malicious or compromised gateway, or an on-path/adjacent attacker that advertises itself as a gateway and then stops responding (or blackholes the real gateway's PINGRESPs), forces the client into the defect. MQTT-SN runs over UDP and no authentication is required.

The impact is a remotely triggerable denial of service (availability) of the affected MQTT-SN client; there is no attacker-controlled data written. The sibling remover processadvertise() uses SYSSLISTFOREACHCONTAINERSAFE and is not affected. The fix assigns the macro's return value to gw.

First published (updated )
Severity
5.3
AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:H

The NVS backend of the Zephyr settings subsystem (subsys/settings/src/settingsnvs.c) reads stored setting-name entries into fixed 74-byte stack buffers and NUL-terminates them with buf[rc] = '\0', where rc is the return value of nvsread(). Per its contract, nvsread() returns the full stored entry length (wlkate.len), which can exceed the supplied buffer length — only MIN(len, storedlen) bytes are actually copied, but the return value may be much larger, bounded only by the NVS sector size. Three sites (settingsnvscachematch(), settingsnvsload(), and settingsnvssave()) used this value directly as the NUL index without clamping, so an oversized stored name entry causes a single \0 byte to be written past the end of the stack buffer at an attacker-influenced offset (CWE-787).

The oversized entry cannot arise through the normal settings API, where names are bounded by SETTINGSMAXNAMELEN. It requires an actor able to write the flash that backs the settings partition — a co-resident or untrusted component sharing the flash device, a malicious settings image/restore, or offline/physical flash access (a shared-flash threat model). The malformed entry is parsed when settingsload() runs at boot or subsystem init, or during settingssave().

The out-of-bounds write is a single NUL byte at an offset equal to the crafted entry length (up to the NVS sector size), so the practical impact is a crash or denial of service and limited stack corruption rather than reliable code execution. There is no confidentiality impact, and the path is not reachable from the network through the ordinary settings interface. The fix skips any entry whose nvsread() length is greater than or equal to the buffer size before performing the NUL store.

First published (updated )
Severity
6.4
Buffer Overflow
AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:H

The Sierra Wireless HL7800 cellular modem driver (drivers/modem/vendorstandalone/hl7800.c, located at drivers/modem/hl7800.c in v4.4.0 and earlier) parses AT responses with roughly twenty handlers that call netbuflinearize(value, sizeof(value), buf, 0, len) into a 128-byte stack buffer and then write value[outlen] = 0. Because netbuflinearize() (lib/netbuf/buf.c) can return a count equal to its destination-length argument, a field that exactly fills the buffer makes the terminating NUL land one byte past the end, a single-byte out-of-bounds write into adjacent stack memory.

The +KCELLMEAS cell-measurement handler oncmdatcmdinforssi() is worse: it passed the wire length len as the destination size (netbuflinearize(value, len, buf, 0, len)), so a response line longer than 128 bytes overflows the value stack buffer with attacker-influenceable content. The line length comes from netbuffindcrlf(), which accumulates bytes across the whole netbuf fragment chain and is not bounded to 128, so an over-long line reaches the defect.

The data originates from the cellular modem over UART, driven by the network: operator-scan results, +CGCONTRDP IP/DNS info, socket indications, and +KCELLMEAS neighbour-cell reports. An attacker able to shape what the modem emits — a rogue base station, a compromised modem baseband, or a remote peer feeding oversized response framing — can drive a line past 128 bytes. The handlers run in the driver's RX thread in kernel context, so the corruption is kernel-side.

The +KCELLMEAS path is a full stack buffer overflow whose worst case is code execution in kernel context and whose floor is a reliable crash; the remaining sites are single-byte NUL out-of-bounds writes. Exploitation requires the modem to emit an over-long AT response line, giving high attack complexity over an adjacent (cellular radio) vector. The fix passes sizeof(dst) - 1 (and correct explicit bounds for the IMSI and +KCELLMEAS sites) so the terminator always stays in bounds.

First published (updated )
Severity
5
AV:A/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L

The WNC-M14A2A LTE-M modem driver mishandles unsolicited %NOTIFYEV: events in oncmdsocknotifyev() (drivers/modem/vendorstandalone/wncm14a2a.c). The response line is linearized into a fixed 40-byte stack buffer via netbuflinearize(), which caps the copy at 39 bytes and returns outlen <= 39. The two quote-delimiter scanning loops, however, were bounded by len — the full CR/LF-delimited frame length returned by netbuffindcrlf() — rather than by outlen.

When a %NOTIFYEV: line longer than 39 bytes contains no " within the linearized region, the loop indices p1/p2 walk past value[39] and read adjacent stack memory until a stray quote byte is found or the index reaches len. The over-read string is then passed to strncmp()/atoi()/LOG, and if a quote byte is found out of bounds the subsequent value[p2] = '\0' performs a single-NUL out-of-bounds stack write at an attacker-influenced offset.

The %NOTIFYEV: payload carries network-derived content (LTIME network time, SIB1 base-station system information, CSPS/RRCSTATE), so a rogue cellular base station, a malicious or compromised modem module, or RF manipulation that induces an over-long notify line reaches the defect without any application interaction; the handler runs automatically on the unsolicited event in the modem RX thread.

The impact is out-of-bounds stack disclosure (into logs and parsing) and stack corruption that can crash the modem RX thread (denial of service). The write offset is only weakly controlled, so memory-safe code execution is not demonstrated. The fix bounds both scanning loops by outlen, keeping all accesses within the linearized buffer.

First published (updated )
Severity
5.9
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

The PSA Protected Storage credential backend (subsys/net/lib/tlscredentials/tlscredentialstrusted.c) declared its credential-store mutex as a plain zero-filled static struct kmutex credentiallock; and never called kmutexinit() on it. A statically zero-filled kmutex has an uninitialized wait queue (its dlist head/tail are NULL instead of the self-referential sentinels that kmutexinit/KMUTEXDEFINE install). The uncontended lock path does not touch the wait queue, so the defect is latent and serialized use behaves correctly.

When two execution contexts contend on the lock, kmutexlock() pends the blocking thread on the wait queue via zpendcurr(), which calls sysdlistappend() on the zeroed list and dereferences a NULL tail pointer (tail->next = node), faulting the kernel. The lock is held during TLS handshake credential loading and by all credential add/get/delete operations, so a deployment performing concurrent TLS handshakes (for example a server handling multiple simultaneous connections from a remote peer) or a credential-management operation concurrent with a handshake can trigger the dereference.

The impact is a denial of service: a deterministic kernel panic / device reset on the first contention. There is no memory corruption beyond the NULL dereference and no confidentiality or integrity impact; mutual exclusion on the fast path remains correct. Exposure is limited to builds with CONFIGTLSCREDENTIALSBACKENDPROTECTEDSTORAGE enabled (PSA Protected Storage / TF-M platforms); the default volatile RAM backend initializes its lock correctly and is unaffected.

The fix initializes the mutex statically with KMUTEXDEFINE(credentiallock), providing a valid wait queue so the contended path no longer touches a NULL list.

First published (updated )
Severity
7.5
Null Pointer Dereference
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

The UpdateHub firmware-update agent's probe handler (zimplupdatehubprobe() in subsys/mgmt/updatehub/updatehub.c) parses the JSON metadata returned by the update server into a fixed two-level nested-array struct. After parsing it validates only the outer array length (objectslen != 2) and then dereferences objects[1].objects[0].objects.sha256sum via strlen() without checking that the inner object array of element [1] is non-empty.

The metadata is attacker-influenceable network input: the agent fetches it over CoAP from the configured UpdateHub server during its routine OTA probe. A malicious or compromised update server (or, when DTLS is disabled, a network man-in-the-middle) can return a response whose second outer object array is empty. Because the parse target is zero-initialised, the corresponding objects[1].objects[0].objects.sha256sum pointer is NULL, and the subsequent strlen() dereferences address zero. The same defect exists in both the 'any boards' and 'some boards' metadata layouts.

The resulting CPU fault is fatal under Zephyr's default error handling, halting or resetting the device, so the flaw is a remotely triggerable denial of service. Impact is limited to availability; it is a read from NULL with no out-of-bounds write, memory corruption, or information disclosure. The fix rejects metadata whose inner object array is empty before any dereference, on both layouts.

First published (updated )
Severity
8.2
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H

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 responsejsoncb() (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 responsedata[downloadedsize] = '\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->bodyfragstart / rsp->bodyfraglen) 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 downloadedsize + bodylen, 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 ((downloadedsize + bodylen) > responsebuffersize) 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 responsedata[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.

First published (updated )
Severity
3
AV:L/AC:H/PR:H/UI:N/S:U/C:L/I:N/A:L

In subsys/debug/coredump/coredumpshell.c, printcoredumphdr() used the 16-bit tgtcode field of a stored Zephyr coredump header directly as an index into coredumptargetcode2str[], a fixed 7-element array of string pointers, with no bounds check.

A stored coredump whose tgtcode is >= 7 causes an out-of-bounds read of a char up to ~64K entries past the array; that value is passed as the %s argument to shellprint, which dereferences and walks it as a string. The result is either disclosure of device memory contents to the shell user or a crash when the out-of-bounds pointer is unmapped.

The defect is reached via the coredump print shell command (cmdcoredumpprintstoreddump -> prettyprintcoredump -> parseandprintcoredump -> printcoredumphdr). The tgtcode field is device-generated and in-range during normal crash handling, so triggering requires local shell access plus the ability to stage or corrupt the stored coredump in the flash/in-memory backend.

Introduced in v4.2.0 (commit 13abd7fe730) and present through v4.4.0; fixed by clamping out-of-range codes to the 'unknown' (index 0) entry.

First published (updated )
Severity
7.8
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:H

The userspace verifier zvrfylogfilterset() for the logfilterset syscall in subsys/logging/logmgmt.c performed a signed comparison against the int16t srcid parameter: srcid < (int16t)logsrccntget(domainid). Any negative value for srcid (e.g. -1) trivially satisfied this check and was forwarded into zimpllogfilterset, where it propagated to filterset() and ultimately to getdynamicfilter(), which uses sourceid as an unsigned index into the linker-section array &TYPESECTIONSTART(logdynamic)[sourceid].filters.

After implicit conversion through uint32t, an int16t -1 becomes 0xFFFFFFFF, indexing logdynamic far out of bounds and causing the kernel to perform an OOB read and an OOB read-modify-write (LOGFILTERSLOTGET/SET) against memory adjacent to the logdynamic section.

The written value is a constrained 3-bit log level slot within the targeted 32-bit word, but the target address is attacker-chosen (a small negative offset from logdynamic) and the write occurs in supervisor mode following a syscall from an unprivileged user thread, providing a kernel memory-corruption / privilege-escalation primitive.

The defect is reachable on any build with CONFIGUSERSPACE=y and CONFIGLOGRUNTIMEFILTERING=y. Present from Zephyr v3.3.0 through v4.4.1. The fix replaces the signed bound check with an unsigned comparison: (uint32t)srcid < logsrccntget(domainid), which correctly rejects negative inputs.

First published (updated )
Severity
7.6
CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:H

The Classic (BR/EDR) L2CAP signaling handlers l2capbrconfreq() and l2capbrconfrsp() in subsys/bluetooth/host/classic/l2capbr.c validated the minimum command size against buf->len (the bytes remaining in the whole received PDU) instead of len (the per-command data length from the L2CAP signaling header). Because multiple signaling commands can be packed into one PDU, buf->len may exceed a command's len. An attacker can send a CONFREQ command with a header length smaller than the configuration-request structure (e.g. 0), followed by another command so that buf->len still satisfies the check. The check then passes incorrectly and optlen = len - sizeof(req) underflows the uint16t to a near-0xFFFF value. The configuration-option loop, which lacks an optlen-versus-buf->len guard, then walks far past the end of the pooled ACL receive buffer using netbuf pull primitives that perform no runtime bounds check, producing an out-of-bounds read of host memory and, when the out-of-bounds option bytes encode an MTU or flush-timeout option, an out-of-bounds write. The BR/EDR signaling channel is processed before pairing/encryption and an L2CAP channel to an L0 service such as SDP can be opened without pairing, so an unauthenticated peer within radio range that can establish an ACL connection can trigger the flaw, leading to memory corruption and denial of service (host/device crash). The defect is present in released versions including v4.4.0. The fix validates against len instead of buf->len in both handlers.

First published (updated )
Severity
6.5
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:N/A:H

The CONFIGUSERSPACE syscall verifier zvrfykpoll() in kernel/poll.c allocates a kernel-side copy of the user-supplied kpollevent[] via zthreadmalloc() and then validates each event's object handle. Before this fix, validation used KOOPS(KSYSCALLOBJ(...)) inline inside the loop, which kills the calling thread without freeing eventscopy.

A user thread can pass numevents >= 1 with a forged object handle to leak the allocation; because newly spawned user threads inherit the parent's resourcepool (kernel/thread.c), an attacker spawns sacrificial threads to repeat the leak until the shared kernel heap is exhausted. Once depleted, legitimate kernel allocations from that pool (kqueue alloc nodes, kmsgq buffers, future kpoll calls, etc.) fail, causing a system-level denial of service.

The fix replaces each inline KOOPS with a conditional goto oopsfree so the buffer is freed before the thread is killed. Affects Zephyr releases from v1.12.0 (when kpoll was first exposed to user mode) through v4.4.1.

First published (updated )
Severity
6.5
CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

In Zephyr's Bluetooth Mesh PB-ADV provisioning bearer (subsys/bluetooth/mesh/pbadv.c), provmsgrecv() rescheduled the provisioning protocol watchdog timer unconditionally at the top of the function, before the FCS check and before the ADVLINKINVALID check. Once a provisioning attempt fails, provfailed() sets ADVLINKINVALID and the only recovery path is the protocol timer firing (protocoltimeout -> provlinkclose -> closelink -> resetadvlink and re-enabling of scanning and the unprovisioned device beacon).

A remote, unauthenticated attacker on the BLE advertising channel can first induce a provisioning failure (e.g. with a malformed generic-provisioning PDU) and then transmit any FCS-valid PB-ADV transaction PDU on the same link ID more often than once per protocol timeout (60 s, or 120 s for OOB input/output). Because each such packet reset the timer even on an invalidated link, protocoltimeout never fired, the dead link was never torn down, and the device remained pinned in an un-provisionable state with its unprovisioned beacon disabled and new Link Open requests rejected.

PB-ADV PDUs are processed without authentication and the FCS is a keyless CRC, so no pairing or prior trust is required and the attacker chooses the link ID itself. The impact is a persistent denial of provisioning/re-provisioning service; there is no memory-safety, confidentiality, or integrity impact.

The vulnerable code shipped in releases through v4.4.1. The fix moves the timer reschedule to after the ADVLINKINVALID check (and the FCS check before the reset) so an invalidated link can no longer be kept alive by incoming packets.

First published (updated )
Severity
5.5
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

The NXP LPUART serial driver (drivers/serial/uartmcuxlpuart.c), when CONFIGUARTUSERUNTIMECONFIGURE is enabled, called LPUARTDeinit() at the start of mcuxlpuartconfigure(), which disables the LPUART peripheral clocks. The requested configuration is validated only afterwards (in mcuxlpuartconfigurebasic), and unsupported parity/data-bit/stop-bit/flow-control values return -ENOTSUP before the clock is re-enabled.

As a result, a uartconfigure() request with an unsupported configuration left the LPUART in a clock-disabled state; any subsequent access to LPUART registers (pollout/pollin, interrupt handling, or a later reconfigure) faults on the gated peripheral and escalates to a hard fault, crashing the system.

uartconfigure() is a Zephyr syscall whose verifier (zvrfyuartconfigure) only checks that cfg is readable user memory and forwards the caller-supplied configuration unchanged, so an unprivileged userspace thread with access to an LPUART device can deterministically trigger the fault, a persistent system-wide denial of service.

Introduced in v2.5.0 and present in all subsequent releases until this fix, which removes the LPUARTDeinit() call and instead only disables the transmitter/receiver, leaving the clock running.

First published (updated )
Severity
7.8
Integer Overflow
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

On Xtensa SoCs built with CONFIGXTENSAMPU and CONFIGUSERSPACE, archbuffervalidate() in arch/xtensa/core/mpu.c — the architecture hook that verifies a user-mode-supplied buffer is accessible to the calling user thread with the requested permission — defaulted its return value to 0 (access permitted) and only set a denial result inside its per-MPU-region probe loop. When the rounded extent of the buffer wraps the 32-bit address space (size + alignment offset near SIZEMAX, or ROUNDUP(size + offset) overflowing to 0), the loop executes zero iterations and the function returns 0 = permitted without probing any MPU region.

The syscall-layer pre-checks (KSYSCALLMEMORYSIZECHECK / ZDETECTPOINTEROVERFLOW) only catch a raw addr+size wrap and do not cover the ROUNDUP-induced wrap, and the string path (archuserstringnlen -> archbuffervalidate) has no syscall-layer guard at all.

An unprivileged user-mode thread can therefore pass a crafted (addr, size) to any syscall that validates user buffers via kusermodefromcopy/tocopy or kusermodestringcopy and have validation succeed for memory it must not access; the kernel then reads from (disclosure) or, with write=1, writes to (corruption) attacker-chosen kernel or other-partition memory on the thread's behalf, enabling information disclosure, memory corruption, privilege escalation, and denial of service.

Affected from v3.7.0 (when Xtensa MPU userspace support was added) through v4.4.0. The fix changes the default to -EINVAL (deny by default), adds an explicit sizeaddoverflow check, and sets the success value only after the full range has been validated.

First published (updated )
Severity
5.3
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L

Zephyr's DNS resolver detects mDNS (.local) queries in dnsresolvenameinternal() (subsys/net/lib/dns/resolve.c) with memcmp(strrchr(query, '.'), ".local", 7), which always reads a fixed 7 bytes from the suffix pointer. When the resolved hostname's final label is shorter than 7 bytes (e.g. names ending in .org, .com, .net, .io, or a trailing dot), the comparison reads 1-2 bytes past the string's NUL terminator.

The hostname (query) is the caller-supplied name passed through the standard getaddrinfo()/dnsgetaddrinfo()/dnsresolvename() path and is influenceable by operators or remote inputs (server names from configuration, parsed URLs, or app-facing interfaces).

On a tightly-sized buffer with no slack (for example a userspace getaddrinfo call where the hostname is copied with kusermodestringalloccopy to exactly strlen+1 bytes), the over-read crosses the allocation boundary; if that boundary is unmapped (guard page, memory-domain boundary under MPU, or an address sanitizer) the over-read faults, causing a denial of service. The over-read bytes are never returned, so there is no information disclosure.

The flaw is compiled only when CONFIGMDNSRESOLVER is enabled, exists since v1.10.0, and is fixed by replacing the fixed-length memcmp with a NUL-safe strcmp(ptr, ".local").

First published (updated )
Severity
6.2
Null Pointer Dereference
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

mcumgrserialprocessfrag() in subsys/mgmt/mcumgr/transport/src/serialutil.c calls netbufreset() on the result of smppacketalloc() before checking it for NULL. smppacketalloc() uses netbufalloc(KNOWAIT) against the shared MCUmgr packet pool (CONFIGMCUMGRTRANSPORTNETBUFCOUNT, default 4), which returns NULL when the pool is exhausted. In default builds the ASSERTNOMSG in netbufreset is a no-op, so netbufsimplereset writes through the NULL pointer (buf->len = 0; buf->data = buf->buf), causing a fault/crash.

The fragment data reaches this code from attacker-controlled bytes on the MCUmgr serial/UART/shell-console transports (smpuart.c, smprawuart.c, smpshell.c), and a fresh buffer is allocated at the start of essentially every new packet. An attacker on the serial/console link can flood the transport to drive the 4-entry buffer pool to exhaustion and induce the NULL dereference, crashing the device (denial of service).

The defect was introduced after the original MCUmgr rework and shipped in Zephyr v4.4.0. The fix moves the NULL check ahead of netbufreset.

First published (updated )
Severity
5.3
CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

The USB CDC-NCM device class (subsys/usb/devicenext/class/usbdcdcncm.c) ignores the return value of usbdepenqueue() in its ethernet transmit callback cdcncmsend(). When the enqueue fails, the function still calls ksemtake(&data->syncsem, KFOREVER), blocking on a completion semaphore that is only ever signaled from the bulk-IN transfer-completion callback. Because nothing was enqueued, that callback never fires and the calling thread — a shared network traffic-class TX thread — deadlocks permanently while holding the interface TX lock, halting transmission until reboot (and leaking the transmit buffer).

The enqueue fails under conditions controlled by the attached USB host: usbdepenqueue() returns -EPERM whenever the bus is suspended (a standard, persistent host operation), and the underlying udcepenqueue() returns -EPERM/-ENODEV on disconnect, bus reset, or endpoint disable. The cdcncmsend() guard only checks the DATAIFACEENABLED and IFACEUP flags, not the suspended state, so a packet transmitted while the host holds the bus suspended reaches the failing enqueue and deadlocks the TX path.

The realistic trigger is a bus suspend that occurs while the exported network interface is active and has traffic to send — host sleep, USB selective/auto-suspend, or hub power management — after which any device-originated packet deadlocks the path, recoverable only by reboot. The impact is a persistent loss of the virtual network connection between the host's NCM interface and the Zephyr device; because the deadlocked thread is a shared traffic-class TX thread, egress on other network interfaces can stall as well. There is no memory corruption or information disclosure.

The defect was introduced with the CDC-NCM driver and shipped in releases through v4.4.0; it is fixed by checking the usbdepenqueue() return value and freeing the buffer before the blocking wait.

First published (updated )
Severity
7.1
Use After Free
CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:L

Zephyr's IPv6 Neighbor Discovery send paths (netipv6sendna, netipv6sendns, netipv6sendrs in subsys/net/ip/ipv6nbr.c) updated the per-interface ICMP-sent statistics by calling netpktiface(pkt) after netsenddata(pkt) had already returned successfully. On the success path the network stack owns and releases the packet's reference (the L2/driver send unrefs it, e.g. ethernetsend -> netpktunref), so for a freshly allocated packet with refcount 1 the netpkt slab block can be freed before the statistics line runs (synchronously when no TX queue thread is configured, or via a concurrent TX thread otherwise).

The subsequent netpktiface(pkt) reads pkt->iface from the freed slab block, and with CONFIGNETSTATISTICSPERINTERFACE enabled that loaded pointer is dereferenced to increment iface->stats.icmp.sent, a use-after-free (CWE-416). If the slab block was reallocated in the meantime the read/increment targets unrelated or attacker-influenced memory, yielding corrupted statistics, a fault/crash (denial of service), or potential limited memory corruption.

The vulnerable Neighbor Advertisement path is reachable by any unauthenticated on-link node simply by sending ICMPv6 Neighbor Solicitations to a Zephyr node with native IPv6 enabled (handlensinput -> netipv6sendna).

Affected from v3.3.0 through v4.4.0; the fix uses the already-available iface argument instead of touching the sent packet. Configurations without per-interface statistics dereference only a global counter and are not affected by the memory-safety aspect.

First published (updated )
Severity
7.5
Use After Free
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

subsys/net/ip/icmpv6.c reads the network interface from a netpkt after that packet has been handed to nettrysenddata(). In icmpv6handleechorequest() and neticmpv6senderror(), the post-send statistics update calls netpktiface(reply)/netpktiface(pkt) on the just-sent packet.

The send path (nettrysenddata -> netiftx) unreferences and may free the packet back to its memory slab before returning — synchronously in the RX thread when no TX queue is configured (CONFIGNETTCTXCOUNT == 0), and asynchronously the driver/L2 may already have freed it otherwise. netpktiface() therefore dereferences a freed (and possibly reused) netpkt; with CONFIGNETSTATISTICSPERINTERFACE the stale iface pointer is further dereferenced and written through (iface->stats.icmp.sent++), turning the use-after-free read into a write through an attacker-influenceable pointer.

The core stack already documents this hazard in netcore.c ("do not use pkt after that call") and caches iface before sending; the ICMPv6 callers did not.

An unauthenticated remote attacker triggers the flaw simply by sending an ICMPv6 Echo Request (ping) or an IPv6 packet that elicits an ICMPv6 error (unknown next header, fragment reassembly timeout, destination unreachable), leading to denial of service via crash and potential memory corruption. Affected: Zephyr networking with CONFIGNETNATIVEIPV6, roughly v4.2.0 through v4.4.0.

The fix caches the interface pointer before sending and uses it for all statistics updates; the sibling commit 86e21665d46 fixes the identical bug in ICMPv4.

First published (updated )
Severity
6.8
CVSS:3.1/AV:P/AC:H/PR:L/UI:N/S:U/C:L/I:L/A:L

Malformed ATAES132A responses with an oversized length field overflow a 52-byte stack buffer in the Zephyr crypto driver, allowing a compromised device or bus attacker to corrupt kernel memory and potentially hijack execution.

First published (updated )
Severity
4.4
XSS
AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:N

The Zephyr Project Manager plugin for WordPress is vulnerable to Stored Cross-Site Scripting via admin settings in all versions up to, and including, 3.3.202 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with administrator-level permissions and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page. This only affects multi-site installations and installations where unfilteredhtml has been disabled.

First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203