How SecMate Discovered Vulnerabilities in libcoap

We discovered two memory-safety issues in libcoap, a widely deployed IoT library. The first is an out-of-bounds write in a fixed buffer reachable via proxy requests that can crash servers with a single UDP packet. The second is an out-of-bounds read in OSCORE configuration parsing that can crash the parser on malformed input. Both vulnerabilities have amplified impact on the constrained embedded devices the library was built for.

About SecMate

SecMate combines static analysis with AI to find security vulnerabilities in source code, specifically in embedded devices and low-level code.

So far, we have reported more than 60 vulnerabilities across embedded and systems projects, most still under coordinated disclosure.

Today, we are sharing two of our findings in libcoap (the first two CVEs uncovered with SecMate), a widely-used CoAP implementation for IoT devices.

What is libcoap?

libcoap [1] is a C implementation of the Constrained Application Protocol (CoAP), standardized as RFC 7252 [2]. Think of CoAP as “HTTP for IoT”: a lightweight protocol for devices that can’t afford the overhead of full HTTP/TCP stacks.

The library is mature and widely deployed:

  • Supports multiple TLS backends (OpenSSL, GnuTLS, Mbed TLS, wolfSSL)
  • Runs on everything from Linux servers to ESP32 microcontrollers
  • Used in smart home devices, industrial sensors, and critical infrastructure

Here is the catch: the devices running libcoap are often constrained. Limited memory, no MMU, no ASLR, no stack canaries. When you find a memory-safety issue in this context, the impact is amplified.

Vulnerability #1: Static Buffer Overflow in Address Resolution (CVE-2025-34468 [3])

Location: coap_resolve_address_info() in src/coap_address.c

The Bug

This vulnerability affects libcoap servers running in proxy mode. The vulnerable function resolves hostnames for CoAP proxy requests, copying the hostname into a fixed 256-byte static buffer without checking the length:

1static char addrstr[256];  // Fixed-size static buffer
2memset(addrstr, 0, sizeof(addrstr));
3if (address && address->length)
4    memcpy(addrstr, address->s, address->length);  // No bounds check!
5else
6    memcpy(addrstr, "localhost", 9);
7getaddrinfo(addrstr, NULL, &hints, &res);

The address->length field comes directly from parsing CoAP options. An attacker controls this value.

The Attack

When a CoAP server runs in proxy mode, it accepts Proxy-Uri options that specify where to forward requests. The hostname from this URI flows directly into the vulnerable memcpy():

  1. A CoAP request arrives with a Proxy-Uri option containing an oversized hostname (>256 bytes)
  2. The proxy extracts the hostname and passes it to coap_resolve_address_info()
  3. The function calls memcpy(addrstr, address->s, address->length) without bounds checking
  4. The fixed-size buffer overflows, corrupting adjacent memory
  5. The server crashes or misbehaves; the exact impact depends on layout and mitigations

Impact

On a standard Linux system, this bug is likely to crash the server (Denial of Service). On embedded devices without memory protection, memory corruption can have broader consequences, but practical exploitation depends on layout and mitigations. One UDP packet, no authentication required when proxy mode is enabled.

Vulnerability #2: Out-of-Bounds Read in OSCORE Parsing (CVE-2025-59391 [4])

Location: get_split_entry() in src/coap_oscore.c

The Bug

OSCORE (Object Security for Constrained RESTful Environments) is a security layer for CoAP. libcoap parses OSCORE configuration files that include boolean fields. The parsing code uses memcmp() with a user-controlled length:

1case COAP_ENC_BOOL:
2    if (memcmp("true", begin, end - begin) == 0)
3        value->u.value_int = 1;
4    else if (memcmp("false", begin, end - begin) == 0)
5        value->u.value_int = 0;

The problem: end - begin comes from the configuration file. If an attacker provides a value like trueAAAAAAAA... (thousands of characters), the memcmp() reads past the static string "true" into adjacent memory.

Impact

This issue requires the ability to provide malicious OSCORE configuration input, which is typically a local or trusted provisioning path rather than a network-facing vector. The realistic outcome is a crash or parse failure on malformed configs.

Theoretical Oracle Attack

In theory, if a local attacker could repeatedly provide different config files and observe success/failure signals from the parser, they could use this as an oracle to infer adjacent .rodata bytes one at a time. The diagram below illustrates what such an attack would look like:

memory layouttrue\0?f?a???true\0...Y ✗f ✓fK ✗fa ✓fa

However, this attack is impractical: OSCORE configuration is loaded from local files, so an attacker would need repeated local access to provide different config files and observe results. At that point, they likely have access that makes this leak scenario moot.

Why This Bug is Easy to Miss

This vulnerability is subtle: the out-of-bounds read in memcmp() may not crash or produce obvious symptoms during normal operation. Spotting it requires reasoning about how data flows through multiple operations, something traditional static analysis tools typically miss.

The Embedded Security Challenge

Both vulnerabilities share a common theme: they are worse on the devices libcoap is designed for.

Desktop and server systems have decades of hardening:

  • ASLR randomizes memory layout
  • Stack canaries detect buffer overflows
  • DEP/NX prevents code execution from data segments
  • Sandboxing limits blast radius

Constrained embedded devices often have none of these. A microcontroller running FreeRTOS or bare metal has:

  • Flat, predictable memory layout
  • No memory protection unit (MPU) or it is disabled for performance
  • No operating system to enforce isolation
  • Direct hardware access for any code that runs

This isn’t a criticism of libcoap. It is the reality of their target environment. But it means bugs like these deserve extra scrutiny.

Key Insight

When auditing code for constrained devices, assume the worst-case exploitation scenario. Mitigations you take for granted on desktop systems simply don't exist.

Disclosure and Fix

We reported both vulnerabilities to the libcoap maintainers through coordinated disclosure. The team responded quickly and professionally, and fixes are now available in version 4.3.5a.

Disclosure Timeline

Sep 3, 2025
SecMate reported OSCORE out-of-bounds read to libcoap security team
Sep 3, 2025
Maintainer acknowledged and confirmed the issue is reproducible
Sep 10, 2025
SecMate reported static buffer overflow to libcoap security team
Sep 10, 2025
Maintainer acknowledged the second vulnerability
Sep 15, 2025
Fix for OSCORE issue merged (PR #1730)
Sep 15, 2025
Fix for static buffer overflow merged (PR #1737)
Sep 15, 2025
CVE requests submitted to MITRE for both issues
Nov 27, 2025
libcoap v4.3.5a released with patches for both vulnerabilities
Dec 8, 2025
CVE-2025-59391 assigned by MITRE (85 days after request)
Dec 31, 2025
CVE-2025-34468 assigned by VulnCheck (same day, MITRE never responded)

We want to thank the libcoap team, particularly Jon Shallow, for their responsiveness in addressing these issues. The maintainer responded on the same day for both reports. Maintaining open-source security infrastructure is often thankless work, and their quick turnaround made the ecosystem safer.

What’s Next

These two CVEs are just a sample of what SecMate has found. We’re continuing to analyze embedded codebases and report vulnerabilities through coordinated disclosure.

If you’re curious about our other findings, check out our disclosure page. And if you’re building embedded systems and want to find vulnerabilities before attackers do, reach out.

References

  • [1] libcoap. “libcoap - C-Implementation of CoAP” GitHub. Repository

  • [2] IETF. “RFC 7252 - The Constrained Application Protocol (CoAP)” IETF Datatracker, June 2014. RFC

  • [3] NVD. “CVE-2025-34468 - Static Buffer Overflow in libcoap” National Vulnerability Database. CVE

  • [4] NVD. “CVE-2025-59391 - Out-of-Bounds Read in libcoap” National Vulnerability Database. CVE


The SecMate Team