# FreeRDP client-side RCE chain (CVE-2026-91964 heap overflow + CVE-2026-91963 USB redirection heap disclosure) found via AI-agent vulnerability research workflow

> Quarkslab used an agentic vulnerability-research harness against FreeRDP and chained two flaws, a RoutingToken heap overflow (CVE-2026-91964) and a urbdrc USB-redirection uninitialised heap disclosure (CVE-2026-91963), into a lab client-side RCE against a client connecting to a hostile RDP server. Both are fixed in FreeRDP 3.31.0; no in-the-wild exploitation is reported.

- **Published:** 2026-11-14T16:36:53Z
- **Last reviewed:** 2026-11-14T16:36:53Z
- **Canonical:** https://intel.threadlinqs.com/threat/TL-2026-6098
- **Card image:** https://intel.threadlinqs.com/og/threat/TL-2026-6098.png
- **ID:** TL-2026-6098
- **Severity:** HIGH (CVSS 8.8)
- **Category:** VULNERABILITY
- **Status:** PATCHED
- **Detections:** 9 (1 shown free below) · **IOCs:** 10
- **CVEs:** CVE-2026-91964, CVE-2026-91963

## Description

On 2026-09-29 Quarkslab (Julien Lair) published an eight-stage agentic vulnerability-research workflow (graph, recon, slicing, analysis, triage, poc, chain, exploit) built from a deterministic static-taint core plus an agent layer. Applied to FreeRDP at commit 993499447, it indexed 13,506 functions, 3,105 types and 31,705 call edges, produced 130 findings in two slices, clustered them into 36, of which 20 were real and reachable, 3 latent, 3 mixed and 10 false positives. Four days elapsed from git clone to the maintainer report.

CVE-2026-91964 (GHSA-2vf2-grvj-6g8x, CWE-122/CWE-787, CVSS 3.1 8.8 per the GitHub advisory) is a heap buffer overflow in nego_send_negotiation_request in libfreerdp/core/nego.c. A malicious RDP server sends LoadBalanceInfo (LB_LOAD_BALANCE_INFO) in a Server Redirection PDU; the client stores it without length validation and on reconnect copies it as the RoutingToken into a fixed 512-byte stream buffer with no capacity check. In Quarkslab's reproduction a 600-byte LoadBalanceInfo became a 615-byte token written into a 512-byte allocation (nego.c:1083, write at nego.c:1098), reached via rdp_client_redirect (connection.c:715). The protocol-bounded routing-token path is safe; the redirection path lacks the same restriction. The overflow is reached when FreeRDP is built with WITH_VERBOSE_WINPR_ASSERT=OFF (the Debian/Ubuntu configuration); with it ON an assertion aborts before the memcpy. The primitive is a blind, attacker-controlled heap write; alone it yields a client crash (DoS).

CVE-2026-91963 (GHSA-hw7p-5h2r-83gq, CWE-457, CVSS 3.1 6.5 per VulnCheck; Red Hat lists a draft 8.8) is an uninitialised heap memory disclosure in the urbdrc USB redirection channel (channels/urbdrc/client/data_transfer). On an error in the completion path, an attacker-supplied OutputBufferSize stays set although no data was written, so the client's response PDU exposes uninitialised heap bytes. Quarkslab validated this with ASan heap fill of 0xcd, seen in 64 of 64 bytes in range [36..100) of the emitted PDU.

The chain: the leak runs after session setup, then a server redirection forces a reconnect that triggers the write. In a lab with a client VM and a hostile server, Quarkslab demonstrated control-flow hijack, libc base recovery, ASLR defeat and a final payload writing /tmp/pwned. Two researcher interventions were needed (libc base derivation, payload). No payload or heap-layout detail or PoC code is published. Affected: FreeRDP 2.0.0 through 3.30.0; fixed in 3.31.0. Exploitation requires the victim to connect to an attacker-controlled (or man-in-the-middle) RDP server. Severity HIGH is an analyst estimate for the chain; the GitHub advisory rates the overflow High.

## MITRE ATT&CK

- T1587.004 Develop Capabilities: Exploits
- T1588.006 Obtain Capabilities: Vulnerabilities
- T1203 Exploitation for Client Execution
- T1021.001 Remote Services: Remote Desktop Protocol
- T1499.004 Endpoint Denial of Service: Application or System Exploitation
- T1583.004 Acquire Infrastructure: Server
- T1557 Adversary-in-the-Middle

## Free detection (Splunk SPL, Microsoft KQL, Sigma)

**FreeRDP Client Spawning Shell or Interpreter (Client-Side RCE, CVE-2026-91964)** (`TL-2026-6098-SPL-002`)

Detects xfreerdp, wlfreerdp, sdl-freerdp or Remmina spawning a shell or script interpreter (sh, bash, dash, zsh, python3, perl). A FreeRDP client has no normal reason to start a shell; this is the post-exploitation signal of control-flow hijack after chaining CVE-2026-91963 (heap leak, ASLR bypass) with CVE-2026-91964 (RoutingToken heap overflow). The Quarkslab lab payload wrote /tmp/pwned.

- **Languages:** Splunk SPL, Microsoft KQL, Sigma
- **ATT&CK:** T1203, T1059.004
- **Data sources:** sysmon_for_linux, defender_for_endpoint_linux, linux_auditd
- **Severity:** high
- **Confidence:** high

### Splunk SPL

```spl
index=sysmon_linux sourcetype=sysmon:linux EventID=1 earliest=-24h (ParentImage="*/xfreerdp*" OR ParentImage="*/wlfreerdp*" OR ParentImage="*/sdl-freerdp*" OR ParentImage="*/remmina") (Image="*/sh" OR Image="*/bash" OR Image="*/dash" OR Image="*/zsh" OR Image="*/python3" OR Image="*/perl") NOT CommandLine="*xdg-open*" | stats count min(_time) as first_seen values(CommandLine) as child_cmdlines by host User ParentImage Image | eval first_seen=strftime(first_seen,"%F %T") | table first_seen host User ParentImage Image child_cmdlines count
```

### Microsoft KQL

```kql
DeviceProcessEvents
| where Timestamp > ago(24h)
| where InitiatingProcessFileName has_any ('xfreerdp', 'wlfreerdp', 'sdl-freerdp', 'remmina')
| where FileName in~ ('sh', 'bash', 'dash', 'zsh', 'python3', 'perl')
| where ProcessCommandLine !contains 'xdg-open'
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine
```

### Sigma

```yaml
title: FreeRDP Client Spawning Shell or Interpreter
id: 2d9f84b6-1c3a-4e57-8b20-5f7a9c3e4b02
status: experimental
description: 'Detects xfreerdp, wlfreerdp, sdl-freerdp or Remmina spawning a shell or script interpreter. A FreeRDP client has no normal reason to start a shell; this is the post-exploitation signal of control-flow hijack after chaining CVE-2026-91963 with CVE-2026-91964.'
references:
  - https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-2vf2-grvj-6g8x
  - https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-hw7p-5h2r-83gq
author: Threadlinqs Team
date: 2026/11/14
tags:
  - attack.execution
  - attack.t1203
  - attack.t1059.004
  - cve.2026.91964
  - cve.2026.91963
logsource:
    category: process_creation
    product: linux
detection:
    selection_parent:
        ParentImage|endswith:
            - '/xfreerdp'
            - '/xfreerdp3'
            - '/wlfreerdp'
            - '/wlfreerdp3'
            - '/sdl-freerdp'
            - '/sdl-freerdp3'
            - '/remmina'
    selection_child:
        Image|endswith:
            - '/sh'
            - '/bash'
            - '/dash'
            - '/zsh'
            - '/python3'
            - '/perl'
    filter_xdg:
        CommandLine|contains: 'xdg-open'
    condition: selection_parent and selection_child and not filter_xdg
falsepositives:
  - xdg-open or helper scripts launched for clipboard or URL handling
  - Custom wrapper scripts around xfreerdp
level: high

```

**Known false positives:**

- xdg-open or desktop helper scripts launched by the client for URL or clipboard handling
- Wrapper scripts that start xfreerdp and are recorded as its parent or child

**Tuning notes:** Add exclusions for sanctioned launcher scripts by full CommandLine. Treat any hit where the child has a network connection or a command line with -c, /dev/tcp or base64 as critical. If only auditd is available, join execve records to ppid and the parent exe.

### 8 more detection rules (Splunk SPL, Microsoft KQL, Sigma), unlock with TL Creds

- [indicator] Client with USB Redirection to External RDP Server (CVE-2026-91963) (locked: unlock with TL Creds)
- [indicator] Client Writing [indicator] or Staging Files After Exploitation (locked: unlock with TL Creds)
- [indicator] Client Connecting to First-Seen External RDP Server (locked: unlock with TL Creds)
- [indicator] RoutingToken Overflow or urbdrc Leak Markers in Crash and ASan Logs (locked: unlock with TL Creds)
- [indicator] Client Parent of Downloader or Reverse Shell Tooling (locked: unlock with TL Creds)
- [indicator] Client Outbound RDP to Public Address (Hostile Server Exposure) (locked: unlock with TL Creds)
- [indicator] Client Crash in libfreerdp After Server Redirection (CVE-2026-91964 / CVE-2026-91963) (locked: unlock with TL Creds)
- [indicator] Client Reconnect Burst to External RDP Server (Server Redirection Chain) (locked: unlock with TL Creds)

Sign up free to unlock the detection rules: https://threadlinqs.com/?modal=signup

## Sources

- [From AI Agents to RCE - Building a Vulnerability Research Workflow (Quarkslab, Julien Lair)](http://blog.quarkslab.com/from-ai-agents-to-rce-building-a-vulnerability-research-workflow.html)
- [GHSA-2vf2-grvj-6g8x: Heap buffer overflow in nego_send_negotiation_request when writing the RoutingToken](https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-2vf2-grvj-6g8x)
- [GHSA-hw7p-5h2r-83gq: FreeRDP urbdrc uninitialized heap memory disclosure](https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-hw7p-5h2r-83gq)
- [OpenCVE: CVE-2026-91963](https://app.opencve.io/cve/CVE-2026-91963)
- [VulnCheck: FreeRDP 2.0.0 through 3.30.0 uninitialized heap memory disclosure via urbdrc](https://www.vulncheck.com/advisories/freerdp-2.0.0-through-3.30.0-uninitialized-heap-memory-disclosure-via-urbdrc)
- [VulnCheck: FreeRDP 2.0.0 through 3.30.0 heap buffer overflow via routingtoken](https://www.vulncheck.com/advisories/freerdp-2.0.0-through-3.30.0-heap-buffer-overflow-via-routingtoken)
- [Red Hat CVE-2026-91963](https://access.redhat.com/security/cve/CVE-2026-91963)
- [NVD: CVE-2026-91963](https://nvd.nist.gov/vuln/detail/CVE-2026-91963)
- [Debian Security Tracker: CVE-2026-91964](https://security-tracker.debian.org/tracker/CVE-2026-91964)
- [FreeRDP source repository](https://github.com/FreeRDP/FreeRDP)

## Full data

The other 8 detection rules (Splunk SPL / Microsoft KQL / Sigma) unlock with TL Creds; a free account includes daily creds: https://threadlinqs.com/?modal=signup
Indicator values unlock with TL Creds, at a lower price on Red and Purple; AI agents can query rules and IOCs through the Threadlinqs MCP server (Purple): https://intel.threadlinqs.com/mcp

Canonical: https://intel.threadlinqs.com/threat/TL-2026-6098
