See how freerdp compares to other vendors in security performance
FreeRDP 3.31.0 (2026-08-26) fixes 5 vulnerabilities in FreeRDP's server role that Bynario reported, as well as 17 other security issues. We were able to demonstrate that 3 of the issues could be chained to achieve pre-auth remote code execution, however we believe exposure to this specific chain is limited (more detail below).
Affected projects include those that embed FreeRDP as an RDP server, including GNOME Remote Desktop and KDE krdp. These are not typically enabled by default, so affected machines are those that have been configured by an administrator to use an affected remote desktop / login service. Client-role FreeRDP is not affected by any of the 5 issues we reported.
Remediation: upgrade to FreeRDP 3.31.0. There is no 3.30.x point release, so distributions on 3.30.0 or earlier need the 3.31.0 rebase or their own backports.
The Vulnerabilities ===================
Below are summaries of the reported vulnerabilities. Note 2 through 5 require an authenticated RDP session. Typically this is post-authentication, however for remote login modes, 1 can be used to bypass authentication and setup an RDP connection (used to render the login screen prior to local user auth), making the other issues reachable.
1. Negotiation failure is not terminal (GHSA-x7v6-xfx3-52j6)
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N (9.3, Critical)
A server that rejects the client's protocol offer sends the failure PDU, does not close the socket, and then bit-tests the failure code as if it were a protocol selection. Every failure code the server can emit collides with a protocol bit, so an unauthenticated peer that ignores the rejection is dispatched into a security mechanism the server disabled and the client never requested. Which one depends on the server's policy: an NLA-only server enters RDSTLS, an RDP-enabled server enters NLA, otherwise TLS.
Impact: pre-authentication security-mechanism selection bypass.
Affected: 3.0.0-beta1 through 3.30.0.
2. RDPGFX ResetGraphics discloses uninitialised heap (GHSA-r7jx-j9h7-j4xj)
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N (6.5, Medium)
The server serialises a fixed 340-byte PDU but seeks over the trailing padding instead of writing it, and sends the whole thing from an uninitialised buffer. A one-monitor reset discloses 300 bytes of stale heap to the peer.
Impact: information disclosure. Demonstrated remote leak of heap + module pointers.
Affected: 3.x through 3.30.0.
3. Channel PDU tracker offset desync (GHSA-9jcm-x588-gh26)
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H (7.5, High)
An oversized static-virtual-channel message desynchronises the reassembler's offset; a later size calculation underflows and writes eight attacker-controlled bytes onto a live function-pointer-bearing object in the same allocation, which is then dereferenced immediately.
Impact: build-dependent. On a default upstream build the process aborts before the write occurs, so it is a remote denial of service. The write only happens on builds with NDEBUG and WITHVERBOSEWINPRASSERT=OFF; Debian, Ubuntu, Fedora and Arch all ship this config. There it is a controlled 8-byte overwrite at a fixed, immediately-used address. Requires a channel opened with CHANNELOPTIONSHOWPROTOCOL whose poll loop survives a failed poll; in the tree that is device redirection.
Affected: 3.28.0, 3.29.0 and 3.30.0 only.
4. DRDYNVC parser uses a borrowed channel pointer after free (GHSA-6mpx-c8rj-whj5)
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H (7.5, High)
The dynamic-virtual-channel lookup returns a pointer from a synchronised table but drops the lock before returning and takes no reference, so a concurrent close on the channel's own worker thread frees the object under the parser.
Impact: use-after-free. Confirmed under AddressSanitizer; the directly demonstrated impact is availability loss.
Affected: 3.x through 3.30.0.
5. Smartcard ATR lengths are not bounded to their arrays (GHSA-q65v-4w7q-hx3r)
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H (6.5, Medium)
Two server-side smartcard response decoders accept a client-supplied ATR length without checking it against the fixed 32- and 36-byte arrays that hold it, and pass it to consumers that trust it.
Impact: out-of-bounds read; potential denial of service. No information disclosure.
Affected: 3.28.0, 3.29.0 and 3.30.0.
Exposure ========
The table below shows which applications using FreeRDP's server role are affected by which issue (using the indices above). cfg means reachability depends on a specific config:
1 2 3 4 5 GNOME Remote Desktop yes yes 51.beta yes 51.beta KDE krdp yes yes no no no Weston RDP backend cfg no no no no freerdp-shadow-cli cfg yes no yes no freerdp-proxy cfg no no no no sfreerdp (sample server) cfg no no yes no
The chain we demonstrated uses issues 1, 2 and 3. Only GNOME Remote Desktop (GRD) 51 pre-release is affected by all three. More specifically GRD 51 pre-release introduces the channel required to reach issue 3's out-of-bounds write. As a result, only distributions shipping pre-release GRD (and affected FreeRDP) are confirmed to be affected by the full chain. As of writing, this includes Fedora 45 & rawhide, Arch's gnome-unstable and CentOS Stream 11.
Furthermore, issue 1's impact varies depending on GNOME Remote Desktop's mode:
- Remote Login: bypass the system-wide authentication used to setup an RDP connection (to reach the login screen). - Screen Sharing and headless: the same transition, but the authorization callback then queries an authentication context that does not exist and the daemon dies. Pre-authentication remote denial of service of the logged-in user's session daemon.
As a result, the chain we demonstrated using these issues is limited to bleeding-edge releases using GRD's Remote Login mode (I imagine this is a small pool!). However, it's only the post-authentication steps that have the GRD pre-release requirements. The authentication bypass, issue 1, which exposes the rich RDP attack surface has very wide coverage (e.g. Ubuntu 24.04 LTS onwards) and may be chained with other n-day or 0-day issues to similar effect.
References ==========
FreeRDP 3.31.0 https://github.com/FreeRDP/FreeRDP/releases/tag/3.31.0 Issue 1 https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-x7v6-xfx3-52j6 Issue 2 https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-r7jx-j9h7-j4xj Issue 3 https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-9jcm-x588-gh26 Issue 4 https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-6mpx-c8rj-whj5 Issue 5 https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-q65v-4w7q-hx3r
Note: CVE identifiers are still pending assignment.
Credit ======
I would like to shout out @akallabeth for maintaining an awesome project and handling our security reports extremely fast.
These issues were found and validated by Bynario Atlas, an AI automated pipeline, while auditing FreeRDP 3.30.0. Reports were reviewed & submitted by myself (Samuel Page / sam4k).
We'll share technical details on the RCE chain on our blog, https://bynar.io/blog , after folks have had time to patch up.
FreeRDP before 3.29.0 contains a buffer over-disclosure vulnerability in the gateway WebSocket transport (libfreerdp/core/gateway/websocket.c). The client's Pong reply reuses a fixed 1024-byte response stream whose length is not sealed to the actual received Ping payload, so a malicious gateway/WebSocket peer sending a non-empty Ping control frame causes the client to reply with an overlong Pong that discloses bytes beyond the received payload (the peer receives the masking key and can unmask the reply). A zero-length Ping reaches an assertion and terminates the client (denial of service).
FreeRDP before 3.29.0 contains a null pointer dereference vulnerability in smartcard cache request decoders that accept NULL NDR pointers for LookupName in SCARDIOCTLREADCACHEA and SCARDIOCTLWRITECACHEA operations. When smartcard emulation is enabled, attackers can send crafted smartcard cache requests with NULL lookup-name pointers to trigger strlen() on a null pointer, causing client process termination.
FreeRDP before 3.29.0 contains an out-of-bounds heap read vulnerability in the UVC H.264 extension-unit parser that fails to validate descriptor length before accessing the GUID field. A local attacker with a malicious USB video camera can trigger a heap read beyond allocated bounds during camera stream setup, causing denial of service.
FreeRDP versions 3.28.0 and earlier contain an out-of-bounds read vulnerability in the RDP6 planar RLE bitmap decoder functions planardecompressplanerle and planardecompressplanerleonly in libfreerdp/codec/planar.c. Only the 1-byte control byte is bounds-checked; the subsequent 0–15 attacker-declared raw bytes are read without validating that the source buffer contains them. A malicious or compromised RDP server can send a truncated planar-encoded bitmap or surface update (reachable via both the Bitmap Update PDU and RDPGFX Surface Command paths) that causes the client to read past the end of the source buffer. The issue is fixed in FreeRDP 3.29.0.
FreeRDP before 3.29.0 improperly validates the Extended Key Usage (EKU) purpose of the peer certificate during client-side server TLS authentication. In x509utilsverify(), when server-purpose (X509PURPOSESSLSERVER) verification fails, the code falls back to client-purpose and any-purpose verification, so a trusted, hostname-matching certificate valid only for clientAuth can be accepted as the RDP server certificate. In environments relying on EKU separation between client and server certificates, this allows a clientAuth-only certificate issued by a trusted CA to bypass server certificate purpose validation.
FreeRDP Windows client before 3.29.0 contains a heap buffer overflow vulnerability in the clipboard virtual channel when processing CLIPRDRFILECONTENTSRESPONSE PDUs without validating the server-provided size against the destination buffer. A malicious RDP server can send a response with a data payload significantly larger than requested, causing arbitrary heap memory corruption that may enable remote code execution when a user performs a paste operation.
FreeRDP before 3.29.0 contains a null pointer dereference vulnerability in smartcard device control request cleanup when reader-state decoding fails. Attackers can send malformed smartcard IRP requests with non-zero cReaders and truncated reader-state data to crash the process via null pointer access in freereaderstates functions.
FreeRDP before 3.29.0 contains client-side heap use-after-free vulnerabilities in the async update message proxy for RAIL WINDOWSTATEORDER and NOTIFYICONSTATEORDER when AsyncUpdate is enabled. When a malicious or compromised RDP server sends crafted update orders, the message proxy shallow-copies structures containing nested parser-owned pointers (e.g., titleInfo.string, windowRects, visibilityRects, icon buffers). The parser frees those nested buffers after the callback returns, so the queued async message later dispatches stale pointers, potentially causing memory corruption or a client crash.
FreeRDP before 3.29.0 fails to properly validate server-supplied RDPDR paths in drive redirection, allowing attackers to access prefix-sibling paths outside the configured shared root. A malicious RDP server can read, write, delete, and enumerate files in sibling directories by sending non-rooted paths that bypass the shared-root boundary check.
FreeRDP before 3.29.0 contains a reachable assertion (WINPRASSERT(OutputBufferLength == BytesReturned)) in serialprocessirpdevicecontrol() in channels/serial/client/serialmain.c. When serial device redirection is enabled and a server-controlled IRPMJDEVICECONTROL request specifies an unsupported IOCTL with a non-zero OutputBufferLength, CommDeviceIoControl() can fail with BytesReturned = 0, causing the mismatch to trigger the assertion and abort the client process (denial of service).
FreeRDP before 3.29.0 contains a heap out-of-bounds read vulnerability in the TSMF FFmpeg decoder when parsing AVC1 MPEG2VIDEOINFO media types with insufficient ExtraData. Attackers can send malformed media format data from a server to trigger a crash by reading fixed offsets without validating source buffer length.
FreeRDP before 3.29.0 contains out-of-bounds read vulnerabilities in the async update message proxy for the PolygonSC and PolygonCB primary drawing orders. When AsyncUpdate is enabled (e.g., xfreerdp /async-update), updatemessagePolygonSC() and updatemessagePolygonCB() allocate a fresh points array but copy point data from the address of the order structure instead of from polygonSC->points / polygonCB->points, resulting in a client-side out-of-bounds read. A malicious or compromised RDP server sending crafted PolygonSC/PolygonCB update orders can trigger memory disclosure or a client crash.
FreeRDP versions 3.28.0 and earlier contain a heap buffer overflow in the server-side RAIL channel handler (railserverhandlemessages() in channels/rail/server/railmain.c). When processing a RAIL PDU header, the code subtracts RAILPDUHEADERLENGTH from the peer-controlled orderLength field without first verifying orderLength is at least the header length. For orderLength values 0..3 this causes an unsigned integer underflow to a very large size, which bypasses the StreamEnsureRemainingCapacity() capacity check (due to pointer arithmetic wraparound) and is then passed to WTSVirtualChannelRead(), resulting in an out-of-bounds heap write. A malicious or compromised RDP client can exploit this to corrupt the heap and crash the server. Fixed in FreeRDP 3.29.0.
FreeRDP before 3.29.0 contains a denial of service vulnerability in the RDPEI server channel handler that fails to validate maximum PDU body length before stream allocation. A malicious RDP client can send a header-only RDPEI message with a large declared body length to force excessive memory allocation on the server.
FreeRDP before 3.29.0 fails to enforce the RESPONSESIZELIMIT when processing Transfer-Encoding: chunked HTTP responses in httpresponserecvbody(). Attackers controlling a malicious RD Gateway endpoint can send oversized chunked response bodies to exhaust client memory resources without triggering the configured size limit.
FreeRDP before 3.29.0 (affected versions <= 3.28.0) contains a divide-by-zero vulnerability in the rdpecam camera redirection client. ecamdevprocessstartstreamsrequest() parses a server-controlled CAMMEDIATYPEDESCRIPTION from a StartStreamsRequest PDU but validates only Format and Flags, not FrameRateDenominator. When a malicious or compromised RDP server sends a StartStreamsRequest with FrameRateDenominator set to zero, ecamencodercontextinit() (channels/rdpecam/client/encoding.c) computes FrameRateNumerator / FrameRateDenominator, causing an integer division by zero (SIGFPE) and termination of the FreeRDP client process. Camera redirection must be enabled on the client for the channel to be reachable. Fixed in FreeRDP 3.29.0.
FreeRDP before 3.29.0 (affected versions <= 3.28.0) contains a heap out-of-bounds read in updateprocessglyphfragments()/glyphcachefragmentput() in libfreerdp/cache/glyph.c. When handling a GLYPHFRAGMENTADD update, the code reads a one-byte server-controlled declared fragment size but does not verify it fits within the remaining received buffer before allocating and copying that many bytes. A malicious RDP server can send a short fragment with an oversized declared size, causing the client to read beyond the allocated buffer, resulting in an out-of-bounds read and client crash.
FreeRDP before 3.30.0 (<= 3.29.0) contains a heap-based buffer overflow in the Windows clipboard client's CliprdrStreamRead function (client/Windows/wfcliprdr.c). When an OLE paste consumer (e.g. explorer.exe) calls IStream::Read with a fixed-size buffer of cb bytes, CliprdrStreamRead requests file contents from the RDP server and then copies the response into the caller's buffer using the server-supplied length (reqfsize) instead of cb. A malicious or compromised RDP server can return an oversized CBFILECONTENTSRESPONSE, causing an out-of-bounds write of attacker-controlled data into the paste consumer's heap buffer when a user pastes server-offered clipboard file contents.
FreeRDP is a free implementation of the Remote Desktop Protocol. Prior to 3.30.0, FreeRDP server-side RDSTLS in libfreerdp/core/rdstls.c accepts an attacker-supplied RDSTLSTYPECAPABILITIES PDU while rdstlsserverauthenticate is waiting for RDSTLSTYPEAUTHREQ, leaving resultCode at RDSTLSRESULTSUCCESS and allowing a remote unauthenticated client to bypass the RedirectionGuid, username, domain, or password checks. This issue is fixed in version 3.30.0.
FreeRDP is a free implementation of the Remote Desktop Protocol. Prior to 3.28.0, rdpsndserverrecvformats in channels/rdpsnd/server/rdpsndmain.c frees context->clientformats on a malformed Client Audio Formats PDU without clearing the owning pointer or numclientformats. An authenticated RDP client can trigger an error such as a cbSize larger than the remaining record, leave the dangling pointer in the server context, and cause rdpsndservercontextfree to free the same allocation again at session teardown. This reliably terminates the server and can create allocator-dependent heap corruption. This issue is fixed in version 3.28.0.
FreeRDP is a free implementation of the Remote Desktop Protocol. Prior to 3.29.0, planardecompressplanerle and planardecompressplanerleonly in libfreerdp/codec/planar.c verify that a control byte exists but do not verify that the source buffer contains the zero to fifteen raw bytes declared by that control byte. A malicious RDP server can send a truncated planar bitmap or surface update whose final control byte claims additional raw bytes, causing the decoder to read beyond pSrcData while processing a color plane. This can crash the client and may disclose adjacent memory. This issue is fixed in version 3.29.0.
FreeRDP is a free implementation of the Remote Desktop Protocol. Prior to 3.27.0, rpcclientrecvfragment in libfreerdp/core/gateway/rpcclient.c ensures the response reassembly stream capacity using only the server-declared allochint rather than the actual StubLength about to be written. A malicious TS Gateway can send a PTYPERESPONSE with a small allochint and a much larger fraglength, causing StreamWrite to copy attacker-controlled stub data beyond the 4096-byte pdu->s buffer. This can crash the client and may permit code execution through heap corruption. This issue is fixed in version 3.27.0.
FreeRDP before 3.29.0 contains out-of-bounds read vulnerabilities in the async update message proxy for the PolygonSC and PolygonCB primary drawing orders. When AsyncUpdate is enabled (e.g., xfreerdp /async-update), updatemessagePolygonSC() and updatemessagePolygonCB() allocate a fresh points array but copy point data from the address of the order structure instead of from polygonSC->points / polygonCB->points, resulting in a client-side out-of-bounds read. A malicious or compromised RDP server sending crafted PolygonSC/PolygonCB update orders can trigger memory disclosure or a client crash.
FreeRDP before 3.29.0 (affected versions <= 3.28.0) contains a heap out-of-bounds read in updateprocessglyphfragments()/glyphcachefragmentput() in libfreerdp/cache/glyph.c. When handling a GLYPHFRAGMENTADD update, the code reads a one-byte server-controlled declared fragment size but does not verify it fits within the remaining received buffer before allocating and copying that many bytes. A malicious RDP server can send a short fragment with an oversized declared size, causing the client to read beyond the allocated buffer, resulting in an out-of-bounds read and client crash.
FreeRDP before 3.29.0 contains a null pointer dereference vulnerability in smartcard cache request decoders that accept NULL NDR pointers for LookupName in SCARDIOCTLREADCACHEA and SCARDIOCTLWRITECACHEA operations. When smartcard emulation is enabled, attackers can send crafted smartcard cache requests with NULL lookup-name pointers to trigger strlen() on a null pointer, causing client process termination.
FreeRDP before 3.29.0 contains a denial of service vulnerability in the RDPEI server channel handler that fails to validate maximum PDU body length before stream allocation. A malicious RDP client can send a header-only RDPEI message with a large declared body length to force excessive memory allocation on the server.
FreeRDP is a free implementation of the Remote Desktop Protocol. Prior to 3.28.0, freerdpdspdecodeopus in libfreerdp/codec/dsp.c calls StreamEnsureRemainingCapacity on context->common.buffer even though opusdecode writes decoded PCM into the caller-supplied out stream. A malicious RDP server that negotiates WAVEFORMATOPUS with a client built with WITHOPUS enabled and WITHDSPFFMPEG disabled can make libopus write a large decoded frame beyond the 4096-byte StreamPoolTake destination used by channels/rdpsnd/client/rdpsndmain.c. This can corrupt the client heap, crash the client, and may permit code execution. This issue is fixed in version 3.28.0.
FreeRDP is a free implementation of the Remote Desktop Protocol. Prior to 3.29.0, planardecompressplanerle and planardecompressplanerleonly in libfreerdp/codec/planar.c verify that a control byte exists but do not verify that the source buffer contains the zero to fifteen raw bytes declared by that control byte. A malicious RDP server can send a truncated planar bitmap or surface update whose final control byte claims additional raw bytes, causing the decoder to read beyond pSrcData while processing a color plane. This can crash the client and may disclose adjacent memory. This issue is fixed in version 3.29.0.
FreeRDP is a free implementation of the Remote Desktop Protocol. Prior to 3.30.0, FreeRDP server-side RDSTLS in libfreerdp/core/rdstls.c accepts an attacker-supplied RDSTLSTYPECAPABILITIES PDU while rdstlsserverauthenticate is waiting for RDSTLSTYPEAUTHREQ, leaving resultCode at RDSTLSRESULTSUCCESS and allowing a remote unauthenticated client to bypass the RedirectionGuid, username, domain, or password checks. This issue is fixed in version 3.30.0.