ANT-2026-D5W3VWPN · freerdp/freerdp

heap-buffer-overflow high

CVE-2026-68579 GHSA-m37j-jcr2-8gcc

Severity Claude high · Security research firm high · Maintainer -

Discovered by Claude Mythos Preview

REPORT

Anthropic's analysis, sealed at approval. Disclosure to the maintainer was performed by Ada Logics.

ANT-2026-D5W3VWPN: Windows clipboard stream read ignores caller buffer size

The Windows FreeRDP client's IStream::Read implementation for remote clipboard files (CliprdrStream_Read, wf_cliprdr.c:249) calls CopyMemory(pv, clipboard->req_fdata, clipboard->req_fsize) where req_fsize is taken directly from the server's CLIPRDR_FILE_CONTENTS_RESPONSE (wf_cliprdr.c:2449, cliprdr_common.c:377) and never compared to the caller's buffer size cb before the copy. The resulting IStream is handed to arbitrary paste consumers (e.g., explorer.exe) via OleSetClipboard and IDataObject::GetData. A malicious RDP server can answer a small FILECONTENTS_RANGE read with an arbitrarily large payload, and the client memcpy()s the entire attacker-controlled payload into the consumer's fixed-size buffer. This yields a scope-changing heap overflow with attacker-controlled content in a process outside the RDP client, enabling code execution.

Target

Project: freerdp/freerdp
Location: client/Windows/wf_cliprdr.c:249
Discovery: static analysis — not yet dynamically reproduced

Technical Details

req_fsize is assigned directly from fileContentsResponse->cbRequested, which is derived from the server-sent PDU dataLen (response->cbRequested = response->common.dataLen - 4) with no validation or correlation to the original requested size. The only size comparison (req_fsize < cb at wf_cliprdr.c:256) runs after the CopyMemory and only handles short reads, so an oversized server response is copied in full before any check occurs.

Reproduction

  1. Attacker's RDP server advertises CFSTR_FILEDESCRIPTORW / CFSTR_FILECONTENTS on the shared clipboard
  2. Victim presses Ctrl+V in Explorer; Explorer obtains the IStream from FreeRDP's IDataObject and calls IStream::Read(pv, 0x1000, &read)
  3. FreeRDP sends a FILECONTENTS_RANGE request for 0x1000 bytes
  4. Server replies with a CB_FILECONTENTS_RESPONSE carrying ~0x100000 bytes of attacker data
  5. wf_cliprdr_server_file_contents_response() sets req_fsize=0x100000; CliprdrStream_Read() CopyMemory()s 1 MiB into Explorer's 4 KiB buffer

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

Suggested Fix

Clamp the bytes copied and reported in CliprdrStream_Read to min(cb, server-returned size), and treat server responses larger than the requested range as a protocol error; retain the requested size from cliprdr_send_request_filecontents() so it can be validated against the response.

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-D5W3VWPN.


Reference: ANT-2026-D5W3VWPN
Anthropic CVD Policy: https://www.anthropic.com/coordinated-vulnerability-disclosure

SECURITY RESEARCH FIRM ANALYSIS

Triage and disclosure were performed by Ada Logics. The writeup below is the document the firm sent to the maintainer.

Verdict
true positive
Severity
high

This issue was found using AI and agents, and has been reviewed manually.

This is a Windows-only issues, but I don't have access to a Window machine so did not create an end-to-end windows reproducer. I left out a harness-based Linux reproducer to as I think auditing the code should be sufficient to identify the vulnerability. Let me know if you need more information from me and I will see if I can extract it.

Summary

FreeRDP's Windows client exposes clipboard file contents to OLE paste consumers (e.g. explorer.exe) through a COM IStream. When the consumer calls IStream::Read(pv, cb, …) — pv is its own fixed-size buffer of cb bytes — CliprdrStream_Read() asks the RDP server for the data via a CB_FILECONTENTS_RANGE request, then copies the server's response into pv using the server-supplied length (req_fsize), not cb:

CopyMemory(pv, clipboard->req_fdata, clipboard->req_fsize);   // length is server-controlled

A malicious or compromised RDP server answers the bounded request with an arbitrarily large CB_FILECONTENTS_RESPONSE; req_fsize becomes the attacker's chosen size and the copy overflows the consumer's buffer with attacker-controlled content.

Affected versions

Details

All line numbers at master HEAD 5e8e987b, client/Windows/wf_cliprdr.c.

// CliprdrStream_Read() :225
static HRESULT STDMETHODCALLTYPE CliprdrStream_Read(IStream* This, void* pv, ULONG cb,
                                                    ULONG* pcbRead)
{
    ...
    /* Ask the server for the file contents (bounded request of cb bytes). */
    ret = cliprdr_send_request_filecontents(clipboard, (void*)This, instance->m_lIndex,
                                            FILECONTENTS_RANGE, instance->m_lOffset.QuadPart, cb);
    if (ret < 0)
        return E_FAIL;

    if (clipboard->req_fdata)
    {
        CopyMemory(pv, clipboard->req_fdata, clipboard->req_fsize);   // :249  cb is IGNORED
        free(clipboard->req_fdata);
    }
    ...
}

req_fsize / req_fdata are set by the channel callback wf_cliprdr_server_file_contents_response() directly from the server's CB_FILECONTENTS_RESPONSE PDU (the CopyMemory of the server payload is around :2455). Nothing constrains req_fsize to the cb the consumer passed, so the copy at :249 writes req_fsize bytes into a cb-byte buffer. cb is the size the paste consumer requested (commonly a small, fixed value); req_fsize is whatever the server put in the response.

Reach: OLE paste consumer → IStream::Read → CliprdrStream_Read → cliprdr_send_request_filecontents (server round-trip) → CopyMemory overflow.

Impact

A malicious/compromised RDP server overflows a fixed-size heap buffer in the OLE paste consumer (e.g. explorer.exe) with attacker-controlled bytes when a user pastes server-offered clipboard file contents — a classic attacker-content heap overflow, in a process outside the RDP client.

Suggested fix

Clamp the copy to the caller's buffer size, and report only what fits:

     if (clipboard->req_fdata)
     {
-        CopyMemory(pv, clipboard->req_fdata, clipboard->req_fsize);
+        ULONG n = (clipboard->req_fsize < cb) ? clipboard->req_fsize : cb;
+        CopyMemory(pv, clipboard->req_fdata, n);
         free(clipboard->req_fdata);
     }
-    *pcbRead = clipboard->req_fsize;
-    instance->m_lOffset.QuadPart += clipboard->req_fsize;
+    *pcbRead = n;
+    instance->m_lOffset.QuadPart += n;

(An IStream::Read must never write more than cb bytes into pv; a server returning more than requested should be treated as a short read or an error.)

References

Attribution

This issue was found using AI and agents, and has been reviewed manually. Please credit Claude and Ada Logics — found by Anthropic using agents to study the security of open-source projects, with Ada Logics validating and reporting. Let us know if you need any more information.

Disclosure

We follow coordinated disclosure policy here: https://www.anthropic.com/coordinated-vulnerability-disclosure (90 day deadline).

UPSTREAM FIX

The change that resolved this finding.

diff --git a/client/Windows/wf_cliprdr.c b/client/Windows/wf_cliprdr.c
index 70895ba3999c..c0a6feea6f3d 100644
--- a/client/Windows/wf_cliprdr.c
+++ b/client/Windows/wf_cliprdr.c
@@ -225,25 +225,27 @@ static ULONG STDMETHODCALLTYPE CliprdrStream_Release(IStream* This)
 static HRESULT STDMETHODCALLTYPE CliprdrStream_Read(IStream* This, void* pv, ULONG cb,
                                                     ULONG* pcbRead)
 {
-	int ret;
 	CliprdrStream* instance = (CliprdrStream*)This;
-	wfClipboard* clipboard;
 
 	if (!pv || !pcbRead || !instance)
 		return E_INVALIDARG;
 
-	clipboard = (wfClipboard*)instance->m_pData;
+	wfClipboard* clipboard = (wfClipboard*)instance->m_pData;
 	*pcbRead = 0;
 
 	if (instance->m_lOffset.QuadPart >= instance->m_lSize.QuadPart)
 		return S_FALSE;
 
-	ret = cliprdr_send_request_filecontents(clipboard, (void*)This, instance->m_lIndex,
-	                                        FILECONTENTS_RANGE, instance->m_lOffset.QuadPart, cb);
+	const int ret =
+	    cliprdr_send_request_filecontents(clipboard, (void*)This, instance->m_lIndex,
+	                                      FILECONTENTS_RANGE, instance->m_lOffset.QuadPart, cb);
 
 	if (ret < 0)
 		return E_FAIL;
 
+	if (clipboard->req_fsize > cb)
+		return E_FAIL;
+
 	if (clipboard->req_fdata)
 	{
 		CopyMemory(pv, clipboard->req_fdata, clipboard->req_fsize);

https://github.com/FreeRDP/FreeRDP/commit/680426e58a986b6fd0f1c352624f813708fc3432

TIMELINE

Recorded dates, in order.

  1. 2026-04-02 Discovered or logged
  2. 2026-07-16 Patch released
  3. 2026-07-22 Sent to maintainer
  4. 2026-07-22 Maintainer acknowledged
  5. 2026-09-28 Publicly revealed
PROVENANCE

SHA-3-512 hash:

94f4c703ec61699c8fd0ad4be74e234d085309ee2bb5837ca53b81cda8e86e1c3929d5ff789e4decaa75dca0af0433f6ba2a82a3f0d4299ddb8fd529d6f8a703

Committed 2026-07-22 07:29 UTC

Revealed 2026-09-28 21:38 UTC

Verify (download preimage.json)

Show preimage JSON
{
  "ant_id": "ANT-2026-D5W3VWPN",
  "bug_class": "Heap Buffer Overflow",
  "claude_severity": "high",
  "commit_sha": null,
  "created_at": "2026-04-16T01:52:39+00:00",
  "description": "The Windows FreeRDP client's IStream::Read implementation for remote clipboard files (CliprdrStream_Read, wf_cliprdr.c:249) calls CopyMemory(pv, clipboard->req_fdata, clipboard->req_fsize) where req_fsize is taken directly from the server's CLIPRDR_FILE_CONTENTS_RESPONSE (wf_cliprdr.c:2449, cliprdr_common.c:377) and never compared to the caller's buffer size cb before the copy. The resulting IStream is handed to arbitrary paste consumers (e.g., explorer.exe) via OleSetClipboard and IDataObject::GetData. A malicious RDP server can answer a small FILECONTENTS_RANGE read with an arbitrarily large payload, and the client memcpy()s the entire attacker-controlled payload into the consumer's fixed-size buffer. This yields a scope-changing heap overflow with attacker-controlled content in a process outside the RDP client, enabling code execution.",
  "discovered_at": "2026-04-02T00:00:00+00:00",
  "location": "client/Windows/wf_cliprdr.c:249",
  "poc_sha256": null,
  "preimage_version": 1,
  "project": "freerdp/freerdp",
  "reproduction": [
    "1. Attacker's RDP server advertises CFSTR_FILEDESCRIPTORW / CFSTR_FILECONTENTS on the shared clipboard",
    "2. Victim presses Ctrl+V in Explorer; Explorer obtains the IStream from FreeRDP's IDataObject and calls IStream::Read(pv, 0x1000, &read)",
    "3. FreeRDP sends a FILECONTENTS_RANGE request for 0x1000 bytes",
    "4. Server replies with a CB_FILECONTENTS_RESPONSE carrying ~0x100000 bytes of attacker data",
    "5. wf_cliprdr_server_file_contents_response() sets req_fsize=0x100000; CliprdrStream_Read() CopyMemory()s 1 MiB into Explorer's 4 KiB buffer"
  ],
  "technical_details": "req_fsize is assigned directly from fileContentsResponse->cbRequested, which is derived from the server-sent PDU dataLen (response->cbRequested = response->common.dataLen - 4) with no validation or correlation to the original requested size. The only size comparison (req_fsize < cb at wf_cliprdr.c:256) runs after the CopyMemory and only handles short reads, so an oversized server response is copied in full before any check occurs.",
  "title": "Windows clipboard stream read ignores caller buffer size",
  "vendor_severity": "high"
}