All vulnerabilities
GHSA-9qqc-m43j-g4r2

FreeRDP: urbdrc: missing OutputBufferSize validation in urb_isoch_transfer IN path - reachable assertion DoS (CWE-617)

FreeRDP
CVSS
5.3Medium
ExploitationNo known exploitationNot in CISA KEV, which does not prove it is unexploitedCISA KEV
Exploit odds (EPSS)No scoreNo FIRST EPSS score in this snapshot yet
Fixed in3.32.1Fixed versionGitHub
Published28 Sep 2026Updated 28 Sep 2026GitHub

What fixes it

A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.

Description

Summary

urb_isoch_transfer() in channels/urbdrc/client/data_transfer.c reads OutputBufferSize from the network stream (controlled by the RDP server) but validates it only for OUT-direction transfers. For IN-direction, the value flows unchecked into libusb_udev_isoch_transfer(), where WINPR_ASSERTING_INT_CAST(int, BufferSize) fires a reachable assertion when BufferSize > INT32_MAX, terminating the FreeRDP client process. Same class as CVE-2026-91961 (control_transfer path), different function.

Details

File 1: channels/urbdrc/client/data_transfer.c ~line 994 File 2: channels/urbdrc/client/libusb/libusb_udevice.c ~line 1421 Tested on commit: 7c3b4bd CWE: CWE-617 (Reachable Assertion)

Vulnerable code — missing IN-direction check:

Stream_Read_UINT32(s, OutputBufferSize);

if (transferDir == USBD_TRANSFER_DIRECTION_OUT)
{
    if (!Stream_CheckAndLogRequiredLength(TAG, s, OutputBufferSize))
        return ERROR_INVALID_DATA;
}
// IN direction: OutputBufferSize is never range-checked before use

Assertion fires in libusb backend:

libusb_fill_iso_transfer(
    iso_transfer, pdev->libusb_handle,
    WINPR_ASSERTING_INT_CAST(uint8_t, EndpointAddress),
    Stream_Pointer(user_data->data),
    WINPR_ASSERTING_INT_CAST(int, BufferSize),      // ← assert fires if BufferSize > INT32_MAX
    WINPR_ASSERTING_INT_CAST(int, NumberOfPackets),
    func_iso_callback, user_data, Timeout);

When BufferSize = 0x80000001: cast to int flips sign positive→negative, WINPR_ASSERTING_INT_CAST sign-check assert fires → winpr_int_assert() (WINPR_NORETURN) → process terminated.

**Contrast — patched libusb_udev_control_transfer has the guard (line ~1456):**

if (*BufferSize > UINT16_MAX)   // ← explicit check present here
{
    WLog_Print(...);
    return FALSE;
}

libusb_udev_isoch_transfer has no equivalent check.

PoC

Malicious RDP server sends TS_URB_ISOCH_TRANSFER with:

  • TransferDirection = USBD_TRANSFER_DIRECTION_IN
  • NumberOfPackets = 1 (valid, passes stream length check)
  • OutputBufferSize = 0x80000001

Client reads OutputBufferSize without bounds check (IN path skips validation), passes it to libusb_udev_isoch_transfer, WINPR_ASSERTING_INT_CAST(int, 0x80000001) sign-check fails → assertion → client crashes.

Impact

A malicious or compromised RDP server can crash the FreeRDP client via the USB redirection channel (URBDRC). Denial of Service. No user interaction required beyond connecting to the server.

Proposed Fix

Add bounds check in libusb_udev_isoch_transfer before the cast:

if (BufferSize > (UINT32)INT32_MAX)
{
    WLog_Print(urbdrc->log, WLOG_ERROR,
               "BufferSize %" PRIu32 " > INT32_MAX, rejecting isoch transfer", BufferSize);
    async_transfer_user_data_free(user_data);
    return -1;
}

Text from GitHub Advisory Database

Affected versions 1

  • FreeRDP, c<= 3.32.0GitHub