Back to Blog
critical SEVERITY10 min read

Critical Heap Buffer Overflow in SSDP Control Point: How Unbounded String Operations Put Networks at Risk

A critical heap buffer overflow vulnerability was discovered and patched in the SSDP control point implementation (`ssdp_ctrlpt.c`), where multiple unbounded `strcpy` and `strcat` operations constructed HTTP request buffers without any length validation. Network-received SSDP response fields — including service type strings and location URLs — could be crafted by an attacker to exceed buffer boundaries, potentially enabling arbitrary code execution or denial of service. The fix replaces the unsa

O
By Orbis AppSec
Published May 28, 2026Reviewed June 3, 2026

Answer Summary

A heap buffer overflow vulnerability (CWE-122) existed in the SSDP control point implementation due to unbounded strcpy() and strcat() operations on user-controlled network data including service type strings and location URLs. The fix replaces these unsafe functions with length-bounded alternatives like strncpy() and strncat(), or safer APIs that validate buffer boundaries before writing data.

Vulnerability at a Glance

cweCWE-122 (Heap-based Buffer Overflow), CWE-120 (Buffer Copy without Checking Size of Input)
fixReplace strcpy()/strcat() with strncpy()/strncat() and validate all string lengths before buffer operations
riskRemote code execution or denial of service via crafted SSDP network responses
languageC
root causeNetwork-received SSDP fields copied into fixed-size buffers without length validation
vulnerabilityHeap buffer overflow via unbounded string operations in SSDP control point

Critical Heap Buffer Overflow in SSDP Control Point: How Unbounded String Operations Put Networks at Risk

Severity: Critical | CWE: CWE-120 (Buffer Copy without Checking Size of Input) | File: upnp/src/ssdp/ssdp_ctrlpt.c


Introduction

Buffer overflows are among the oldest and most dangerous vulnerability classes in systems programming — and they keep showing up in production code. This post dives into a critical heap buffer overflow discovered in the SSDP (Simple Service Discovery Protocol) control point implementation of a UPnP library, explains exactly how it could be exploited, and walks through the fix that closes the door on this attack vector.

If you write C or C++ code that processes network data, this one is for you. Even if you don't, understanding why unbounded string operations are dangerous is essential knowledge for any developer who cares about the security of the systems they build.


What Is SSDP and Why Does It Matter?

SSDP (Simple Service Discovery Protocol) is the discovery mechanism at the heart of UPnP (Universal Plug and Play). It's how your smart TV finds your router, how a media server announces itself to clients, and how IoT devices broadcast their capabilities on a local network.

The control point side of SSDP is responsible for sending M-SEARCH requests — essentially asking "who's out there?" — and processing the responses. Because SSDP operates over UDP and accepts responses from any device on the network, it is a natural target for network-based attacks. Malicious or malformed responses are trivial to craft and inject.


The Vulnerability Explained

What Went Wrong

Inside CreateClientRequestPacket(), the code was responsible for building an HTTP-style M-SEARCH request buffer (RqstBuf). The original implementation did this in several stages using a combination of strcpy, strcat, and snprintf into an intermediate TempBuf:

// VULNERABLE CODE (before the fix)
char TempBuf[COMMAND_LEN];
const char *command = "M-SEARCH * HTTP/1.1\r\n";
const char *man = "MAN: \"ssdp:discover\"\r\n";

memset(TempBuf, 0, sizeof(TempBuf));
if (RqstBufSize <= strlen(command))
    return UPNP_E_INTERNAL_ERROR;
strcpy(RqstBuf, command);          // ⚠️ No overflow check after this point

// ... snprintf into TempBuf for the HOST header ...

if (RqstBufSize <= strlen(RqstBuf) + strlen(TempBuf))
    return UPNP_E_BUFFER_TOO_SMALL;
strcat(RqstBuf, TempBuf);          // ⚠️ Race between check and use

if (RqstBufSize <= strlen(RqstBuf) + strlen(man))
    return UPNP_E_BUFFER_TOO_SMALL;
strcat(RqstBuf, man);              // ⚠️ Another unbounded append

// ... and so on for MX header, ST header, etc.

There are several compounding problems here:

  1. strcpy without bounds checking — The initial strcpy(RqstBuf, command) checks that RqstBufSize > strlen(command), but this check only validates the first write. All subsequent strcat calls append to a buffer that is being filled incrementally, with each check only loosely validating the current state.

  2. TOCTOU-style logic errors — The pattern if (RqstBufSize <= strlen(RqstBuf) + strlen(TempBuf)) return error; strcat(RqstBuf, TempBuf); is fragile. The length check and the write are not atomic, and more importantly, the check uses <= instead of <, meaning a perfectly full buffer passes the check and then overflows by one byte on the strcat.

  3. Network-controlled input flows into the buffer — Fields like service type (ST) headers and location URLs come directly from network-received SSDP responses. An attacker on the same network segment can craft a response with an oversized ST field. When this value is concatenated into RqstBuf without strict length enforcement, the buffer overflows onto the heap.

How Could This Be Exploited?

Here's a realistic attack scenario:

  1. An attacker connects to the same local network as a device running the vulnerable UPnP control point (common in home networks, hotel Wi-Fi, corporate LANs, or any shared network).
  2. The control point broadcasts an SSDP M-SEARCH request.
  3. The attacker's machine responds with a crafted SSDP response containing an oversized ST (Service Type) field — for example, a string of several kilobytes instead of the expected short identifier like upnp:rootdevice.
  4. The vulnerable code copies this attacker-controlled string into RqstBuf via strcat, writing far beyond the allocated heap buffer.
  5. The overflow corrupts adjacent heap metadata or data, potentially enabling:
    - Arbitrary code execution via heap metadata manipulation
    - Denial of service via heap corruption and crash
    - Information disclosure if heap layout can be influenced to leak adjacent memory

Because SSDP uses UDP and requires no authentication, this attack requires no credentials, no prior access, and no user interaction — just network adjacency.

CWE-120: The Classic "Dangerous Function" Problem

This vulnerability is classified under CWE-120: Buffer Copy without Checking Size of Input ('Classic Buffer Overflow'). The C standard library functions strcpy and strcat are considered dangerous precisely because they perform no bounds checking. The destination buffer's size is never consulted — they simply write until they hit a null terminator in the source string.

The CERT C Coding Standard, MISRA C, and virtually every modern secure coding guideline explicitly prohibit the use of strcpy and strcat in code that handles externally-sourced data.


The Fix

What Changed

The fix replaces the fragmented, multi-step string construction approach with a single, offset-tracked snprintf pattern. Here's the corrected code:

// FIXED CODE (after the patch)
size_t offset = 0;

switch (AddressFamily) {
case AF_INET:
    rc = snprintf(RqstBuf,
        RqstBufSize,
        "M-SEARCH * HTTP/1.1\r\n"
        "HOST: %s:%d\r\n"
        "MAN: \"ssdp:discover\"\r\n",
        SSDP_IP,
        SSDP_PORT);
    break;
case AF_INET6:
    rc = snprintf(RqstBuf,
        RqstBufSize,
        "M-SEARCH * HTTP/1.1\r\n"
        "HOST: [%s]:%d\r\n"
        "MAN: \"ssdp:discover\"\r\n",
        SSDP_IPV6_LINKLOCAL,
        SSDP_PORT);
    break;
default:
    return UPNP_E_INVALID_ARGUMENT;
}

if (rc < 0 || (size_t)rc >= RqstBufSize)
    return UPNP_E_INTERNAL_ERROR;
offset = (size_t)rc;

if (Mx > 0) {
    rc = snprintf(RqstBuf + offset,
        RqstBufSize - offset,
        "MX: %d\r\n",
        Mx);
    if (rc < 0 || (size_t)rc >= RqstBufSize - offset)
        return UPNP_E_BUFFER_TOO_SMALL;
    offset += (size_t)rc;
}

Why This Fix Works

Let's break down the security improvements:

1. snprintf Enforces Hard Limits

snprintf(dest, n, ...) will never write more than n bytes (including the null terminator) to the destination buffer. There is no scenario in which it overflows — if the formatted output would exceed the limit, it is truncated and the function returns the number of bytes that would have been written, allowing the caller to detect truncation.

2. Offset Tracking Eliminates Cumulative Errors

Instead of using strlen(RqstBuf) to find the current end of the buffer (which is O(n) and error-prone), the fix maintains an explicit offset variable. Each snprintf call writes to RqstBuf + offset with a remaining capacity of RqstBufSize - offset. This is both more efficient and more correct — there's no possibility of miscounting.

3. Truncation Is Detected and Rejected

After each snprintf, the return value rc is checked:
- rc < 0 → encoding error, return failure
- (size_t)rc >= RqstBufSize - offset → output was truncated (or would have been), return failure

This means the code fails safely rather than silently producing a malformed or truncated buffer that could cause downstream issues.

4. The Intermediate Buffer Is Eliminated

The original code used TempBuf[COMMAND_LEN] as a staging area, introducing an extra potential overflow point. The fix writes directly into RqstBuf with full size awareness, removing an entire class of intermediate buffer issues.

5. Consolidation Reduces Attack Surface

By consolidating the static header lines (M-SEARCH, HOST, MAN) into a single snprintf call, the fix reduces the number of operations that touch the buffer — fewer operations means fewer opportunities for mistakes.


Before vs. After: A Side-by-Side Comparison

Aspect Before (Vulnerable) After (Fixed)
String functions used strcpy, strcat, snprintf snprintf only
Bounds enforcement Manual, error-prone checks Enforced by snprintf
Buffer position tracking strlen(RqstBuf) (O(n), fragile) Explicit offset variable
Truncation detection Partial (only for TempBuf) Full (every write checked)
Intermediate buffers TempBuf[COMMAND_LEN] None
Network input handling Unsafe concatenation Bounded write with failure

Prevention & Best Practices

1. Never Use strcpy or strcat on Untrusted Data

These functions should be treated as deprecated in any security-sensitive context. Modern alternatives include:

  • snprintf — for formatted output with size limits
  • strlcpy / strlcat — BSD extensions that always null-terminate and respect buffer size (not available everywhere, but widely portable)
  • strncpy — use with caution; it does not guarantee null termination
  • memcpy with explicit length — when you know the exact byte count

2. Use the Offset Pattern for Buffer Construction

When building a buffer incrementally, always track the current write position explicitly:

size_t offset = 0;
size_t remaining = buf_size;

int n = snprintf(buf + offset, remaining, "part one: %s\n", val1);
if (n < 0 || (size_t)n >= remaining) return ERROR;
offset += (size_t)n;
remaining -= (size_t)n;

n = snprintf(buf + offset, remaining, "part two: %s\n", val2);
if (n < 0 || (size_t)n >= remaining) return ERROR;
offset += (size_t)n;

This pattern is clear, efficient, and safe.

3. Treat All Network Data as Hostile

Any data received from the network — regardless of the protocol — must be treated as potentially malicious. For SSDP specifically:
- Validate and cap the length of all response fields before processing
- Use strict length limits on service type strings, location URLs, and other variable-length fields
- Consider allowlisting expected field formats with regex or explicit parsing

4. Enable Compiler and Runtime Protections

While not a substitute for correct code, these defenses raise the cost of exploitation:

  • -D_FORTIFY_SOURCE=2 — GCC/Clang compile-time and runtime buffer overflow detection
  • Stack canaries (-fstack-protector-strong) — detect stack smashing
  • AddressSanitizer (-fsanitize=address) — catch buffer overflows during testing
  • Heap hardening — modern allocators (like glibc's) include metadata integrity checks

5. Static Analysis

Tools that can catch this class of vulnerability during development:

  • Coverity — industry-standard static analyzer, excellent at buffer overflow detection
  • CodeQL — GitHub's semantic code analysis, has specific queries for CWE-120
  • Clang Static Analyzer — free, built into LLVM
  • Flawfinder / rats — lightweight scanners that flag dangerous C functions

6. Follow Established Secure Coding Standards

  • CERT C Coding Standard — Rule STR31-C: "Guarantee that storage for strings has sufficient space for character data and the null terminator"
  • OWASPBuffer Overflow
  • CWE-120Buffer Copy without Checking Size of Input
  • MISRA C 2012 — Rule 21.6 prohibits use of <stdio.h> input functions without bounds; similar restrictions on string functions

Key Takeaways

  1. strcpy and strcat are dangerous — they perform no bounds checking and should never be used with data that originates from the network or user input.

  2. The "check then use" pattern is fragile — checking strlen before strcat is not sufficient. Use snprintf with explicit size limits instead.

  3. Network protocols are attack surfaces — SSDP operates without authentication on local networks. Any device on your Wi-Fi can send crafted SSDP responses. Buffer overflows in SSDP parsers are reachable with zero credentials.

  4. The fix is simple and elegant — replacing a tangle of strcpy/strcat calls with offset-tracked snprintf calls eliminates the vulnerability class entirely, not just the specific instance.

  5. Defense in depth matters — compiler hardening, runtime sanitizers, and static analysis complement correct code. Use all of them.

Buffer overflows in C have been known since the 1970s and have been responsible for some of the most devastating exploits in computing history — from the Morris Worm to countless remote code execution vulnerabilities in network daemons. The fact that they still appear in modern codebases is a reminder that secure coding requires constant vigilance, good tooling, and a healthy skepticism toward any code that touches a network socket.

Write safe code. Validate your inputs. And when in doubt, use snprintf.


This vulnerability was identified and fixed by OrbisAI Security using automated security scanning and AI-assisted code review.

Frequently Asked Questions

What is a heap buffer overflow in C?

A heap buffer overflow occurs when a program writes more data to a heap-allocated buffer than it can hold, overwriting adjacent memory and potentially corrupting program state or enabling code execution.

How do you prevent heap buffer overflow in C string operations?

Always use length-bounded string functions (strncpy, strncat, snprintf) instead of unbounded ones (strcpy, strcat, sprintf), validate input lengths before copying, and use static analysis tools to detect unsafe patterns.

What CWE is heap buffer overflow?

Heap buffer overflows are typically classified as CWE-122 (Heap-based Buffer Overflow) or CWE-120 (Buffer Copy without Checking Size of Input).

Is input validation alone enough to prevent buffer overflow?

No—input validation is important, but the root fix requires using length-bounded APIs. An attacker may find ways to bypass validation, but bounded functions provide a hard limit on how much data can be written.

Can static analysis detect heap buffer overflow in SSDP parsing?

Yes, modern static analysis tools like Clang Static Analyzer, Coverity, and Semgrep can detect unbounded strcpy/strcat calls and flag them as potential buffer overflow risks, especially when analyzing tainted data flows from network sources.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #553

Related Articles

high

How insecure string copy functions happen in C calculations.c and how to fix it

A high-severity buffer overflow vulnerability was discovered in `src/calculations.c` at line 37, where a two-step `strncpy` + manual null-termination pattern left the door open for subtle memory safety bugs when copying string data into the `entry->type` field. The fix replaces both lines with a single `snprintf` call that handles bounds and null-termination atomically, eliminating the risk entirely. This is a common C pitfall that affects production CLI tools and can be exploited when attacker-

high

How integer truncation heap overflow happens in C++ UEFI ACPI parsing and how to fix it

A high-severity integer truncation vulnerability was discovered in `Mobility.Uefi.Acpi.cpp` where heap allocation sizes were stored in a 16-bit integer (`MO_UINT16`), causing silent truncation when the computed size exceeded 65535 bytes. This led to undersized heap allocations followed by out-of-bounds writes, exploitable by an attacker who can influence ACPI SRAT table contents in virtualized environments. The fix promotes the size variable to `MO_UINTN` (platform-native width) to prevent trunc

critical

How integer overflow in buffer size calculation happens in C and how to fix it

A critical integer overflow vulnerability was discovered in the `nsh_setvar()` function in `nshlib/nsh_vars.c`, where the buffer size calculation `newsize = pstate->varsz + varlen` could wrap around, causing a heap buffer overflow. The fix adds overflow checking before the addition, preventing attackers with shell access from corrupting memory by setting variables with crafted names and values.

high

How buffer overflow via sprintf() happens in C networking code and how to fix it

A high-severity buffer overflow vulnerability was discovered in `profile.c` where `sprintf()` was used to format server addresses without any bounds checking. An attacker who could influence the `SERVER_BASE_PORT` value or trigger integer overflow in the port calculation could write beyond the `server_address` buffer. The fix replaces `sprintf()` with `snprintf()` using explicit buffer size limits at both call sites (lines 99 and 220).

critical

How integer overflow happens in C reliable.c and how to fix it

A critical integer overflow vulnerability was discovered in `reliable.c` at line 1299, where the `packet_buffer_size` calculation used signed `int` arithmetic that could wrap to a negative or undersized value when large `fragment_size` values were involved. By casting each operand to `size_t` before multiplication, the fix eliminates the overflow risk entirely and ensures the allocated buffer is always large enough to hold the reassembled packet data.

high

How insecure string copy functions happen in C (cyw43.c) and how to fix it

Three unsafe string copy calls in `src/cyw43.c` — including a bare `strcpy()` and two `strncpy()` calls — created buffer overflow risks in a CYW43 Wi-Fi driver emulation layer. The fix replaces all three with `snprintf()`, which enforces buffer size limits and guarantees null-termination in a single, consistent operation. Left unaddressed, these vulnerabilities could allow an attacker controlling input like a TAP interface name or SSID to corrupt adjacent memory and potentially execute arbitrary