CVE-2025-13654: Stack Buffer Overflow in Duc via Integer Underflow
- Hacking By Doing
- 4 days ago
- 2 min read
Updated: 25 minutes ago

Date: December 05, 2025
Author: HackingByDoing
Product: Duc
CVSS: High (DoS / Information Disclosure)
While auditing Duc, a popular tool available in the official Debian repositories for indexing, inspecting, and visualizing disk usage, I discovered a stack-based buffer overflow vulnerability within the libduc library.
This vulnerability, caused by a classic unsigned integer underflow, has been assigned CVE-2025-13654. Below is the technical breakdown of the discovery, the root cause analysis, and the disclosure timeline with CERT/CC.
The Vulnerability
The issue lies within the buffer_get function in src/libduc/buffer.c. This function is responsible for reading data from a buffer structure. It attempts to perform a bounds check before copying data, but the logic is flawed due to the use of size_t (an unsigned type).
Here is the vulnerable code snippet:
static int buffer_get(struct buffer *b, void *data, size_t len)
{
/* UNSAFE: size_t underflow when len > b->len */
if (b->ptr <= b->len - len) {
memcpy(data, b->data + b->ptr, len);
b->ptr += len;
return len;
}
return 0;
}
The Root Cause: Unsigned Underflow
The sanity check if (b->ptr <= b->len - len) is dangerous.
Because len and b->len are size_t (unsigned integers), if an attacker requests a read length (len) that is greater than the remaining buffer length (b->len), the subtraction b->len - len does not result in a negative number. Instead, it wraps around (underflows) to a massive positive integer.
Consequently, the check evaluates to true, bypassing the safety mechanism. The program then executes memcpy, reading adjacent memory on the stack beyond the bounds of the allocated buffer.
Exploitation & Impact
To confirm this, I wrote a small PoC harness that links against libduc. I compiled it using Clang with AddressSanitizer enabled.
The PoC sets up a tiny 3-byte buffer but requests to read 255 bytes:
/* Simplified PoC */
uint8_t raw[3] = {0xFF, 'A', 'B'};
struct buffer *b = buffer_new(raw, sizeof raw);
uint8_t *dst = malloc(255);
/* Trigger: Request 255 bytes from a 3-byte buffer */
buffer_get(b, dst, 255);
Running this resulted in an immediate ASan crash:

Impact:
Denial of Service (DoS): The out-of-bounds read can crash the application processing the malicious input.
Information Disclosure: An attacker could potentially read sensitive data from the stack adjacent to the buffer.
The Fix
The fix is straightforward. Instead of subtracting (which risks underflow), you should add the requested length to the current pointer and check if it exceeds the total buffer size.
if (b->ptr + len <= b->len) {
memcpy(data, b->data + b->ptr, len);
// ...
}
Disclosure Timeline
The vulnerability was coordinated through CERT/CC (VINCE).
2025-10-08: Vulnerability reported to CERT/CC.
2025-11-06: CERT reaches out to the vendor. The vendor responds that a patch is applied and version 1.4.6 is released.
2025-11-25: CERT/CC confirmed the fix was properly applied in the 1.4.6 release and assigned CVE-2025-13654.
2025-12-05: Public Disclosure.
Conclusion
This is a textbook example of why integer arithmetic with size_t requires extra care in C. Always validate bounds by adding and comparing against the maximum limit, rather than subtracting and hoping you don't wrap around.
Users of duc should upgrade to version 1.4.6 immediately.
Thanks to CERT/CC for handling the coordination.




