Skip to main content

Free 30-min security demo Book Now

Offensive360 Offensive360
ZeroDays CVE-2026-64624
High CVE-2026-64624 CVSS 7.8 FreeRDP C

FreeRDP CLI Option Injection

CVE-2026-64624: FreeRDP's RDP file parser exposes the full CLI surface to untrusted input, enabling RCE, cert bypass, and filesystem exfiltration.

Offensive360 Research Team
Affects: < 3.28.0
Source Code

Overview

FreeRDP, the widely deployed open-source Remote Desktop Protocol client library, contains a critical design flaw in its .rdp file parser that allows an attacker to inject arbitrary command-line options into a FreeRDP session simply by crafting a malicious RDP file. Versions prior to 3.28.0 treat any line in an RDP file that begins with a forward slash (/) as a raw CLI argument, forwarding it directly into FreeRDP’s argument parser without sanitization or allowlisting. Because RDP files are routinely distributed by enterprises, embedded in email attachments, or delivered via web links, this creates a trivially weaponizable attack path that requires no user interaction beyond opening the file.

The flaw was disclosed through the FreeRDP project’s own security advisory process and affects all consumers of the libfreerdp client stack — including standalone xfreerdp users, GUI wrappers such as Remmina when backed by FreeRDP, and any application embedding the library for RDP connectivity. The breadth of the affected surface is significant: FreeRDP is the de facto RDP implementation on Linux and is also present in macOS and Windows environments.

The vulnerability is particularly dangerous because the exploitation primitives available through FreeRDP’s own CLI are severe. An attacker does not need to exploit a memory safety bug; they simply need a user to open an RDP file, a social-engineering bar that is extremely low in enterprise environments where .rdp files are a standard IT distribution mechanism.

Technical Analysis

RDP files are INI-like configuration documents. Legitimate keys follow the format key:type:value, for example:

full address:s:192.168.1.100
username:s:jdoe

FreeRDP’s parser, however, historically accepted lines beginning with / and routed them directly into freerdp_parse_args() — the same function invoked when processing actual command-line arguments supplied by the user. The vulnerable parsing logic looks approximately like this:

/* client/common/file.c — pre-3.28.0 (simplified) */
static BOOL freerdp_client_parse_rdp_file_line(rdpFile* file,
                                                const char* line,
                                                size_t length)
{
    /* Lines starting with '/' are forwarded to the CLI parser */
    if (line[0] == '/')
    {
        /* Build a synthetic argv[] from the raw line and feed it
         * directly to the argument parser — NO validation here.   */
        char* fake_argv[] = { "xfreerdp", (char*)line, NULL };
        return freerdp_parse_args(file->context->settings,
                                  2, fake_argv,
                                  NULL, NULL, NULL, NULL) >= 0;
    }

    /* Normal key:type:value processing below */
    return freerdp_client_parse_rdp_file_option(file, line, length);
}

Because freerdp_parse_args() accepts the full CLI option set, an attacker controlling the content of an RDP file can supply any option the interactive user could have typed. Three options stand out as immediately dangerous:

/rdp2tcp:<path> — Instructs FreeRDP to spawn an external TCP proxy binary at the given path. A line such as /rdp2tcp:/tmp/backdoor causes FreeRDP to execute the binary at that path, achieving arbitrary command execution if the attacker can also stage the binary (e.g., via a world-writable temp directory or a UNC path on Windows).

/cert:ignore — Disables all TLS certificate validation for the session. An attacker distributing a malicious RDP file pointing at a server they control can silently strip TLS verification, enabling credential harvesting via a rogue RDP server without presenting any certificate warning to the user.

/drive:<name>,<path> — Redirects a local directory into the RDP session as a virtual drive shared with the remote server. If the remote server is attacker-controlled, this directly exfiltrates the contents of any locally accessible path, including /home, /etc, or C:\Users.

The root cause is an architectural conflation of trusted (interactive user) and untrusted (file content) input sources. The CLI parser was never designed to be a safe deserialization surface for external documents.

Impact

The CVSS 7.8 score reflects a local attack vector in the strictest sense — the malicious file must be opened on the victim’s machine — but in practice the delivery mechanism (email, browser download, enterprise file share) makes this functionally equivalent to a network-reachable vulnerability for most threat models.

Concrete attacker outcomes include:

  • Arbitrary command execution via /rdp2tcp when combined with a file write primitive or pre-positioned binary, achieving full user-level code execution without exploiting any memory corruption.
  • Credential theft at scale via /cert:ignore combined with a rogue RDP endpoint — every user in an organization who opens a distributed .rdp file will silently authenticate against an attacker-controlled server, handing over NTLM hashes or cleartext credentials depending on authentication configuration.
  • Sensitive data exfiltration via /drive redirection. A single RDP file can map a victim’s entire home directory to a remote server, leaking SSH keys, browser credential stores, source code, and documents.

Enterprises that deploy RDP files as part of VDI or jump-host workflows — an extremely common pattern — face a supply-chain risk: compromise of the file distribution mechanism (an internal SharePoint, an IT helpdesk portal) turns every distributed .rdp file into a weapon.

How to Fix It

Upgrade to FreeRDP ≥ 3.28.0 immediately. The fix introduces strict allowlisting of keys permitted inside RDP files, rejecting any line that begins with / rather than forwarding it to the CLI parser.

The corrected parsing logic rejects forward-slash lines outright:

/* client/common/file.c — 3.28.0+ (simplified) */
static BOOL freerdp_client_parse_rdp_file_line(rdpFile* file,
                                                const char* line,
                                                size_t length)
{
    if (line[0] == '/')
    {
        /* Reject CLI-style options embedded in RDP files.
         * These are untrusted and must never reach the arg parser. */
        WLog_WARN(TAG, "Ignoring disallowed CLI option in RDP file: %s",
                  line);
        return FALSE;
    }

    return freerdp_client_parse_rdp_file_option(file, line, length);
}

Package manager upgrade commands:

# Debian/Ubuntu — if a patched package is available in your repo
sudo apt update && sudo apt install --only-upgrade freerdp2-x11 freerdp3-x11

# Build from source (guaranteed patched)
git clone https://github.com/FreeRDP/FreeRDP.git
cd FreeRDP && git checkout 3.28.0
cmake -DCMAKE_BUILD_TYPE=Release -B build && cmake --build build
sudo cmake --install build

# Homebrew (macOS)
brew upgrade freerdp

If an immediate upgrade is not possible, mitigate by stripping or rejecting .rdp files containing /-prefixed lines at the mail gateway or web proxy layer, and audit all centrally distributed RDP files for unexpected CLI options.

Our Take

This vulnerability is a textbook example of parser conflation — the same parsing code path serving both trusted and untrusted input with no privilege boundary between them. We see this pattern repeatedly across security research: a developer adds a “convenience” feature (pass CLI flags in a config file) without recognizing that config files and interactive input have fundamentally different trust levels.

The danger is compounded by the power of FreeRDP’s CLI surface. The argument parser was designed for a human operator who has already authenticated to their workstation; it was never intended to be a deserialization endpoint for arbitrary file content. Once that conflation exists, the entire CLI becomes an attack surface — and rich CLIs like FreeRDP’s are particularly hazardous because they include options with direct OS-level side effects (/rdp2tcp, /drive).

For enterprises, the lesson is that .rdp files should be treated as executable artifacts, not passive configuration. File-opening actions that invoke complex parsers require the same scrutiny as running a script.

Detection with SAST

This vulnerability class maps to CWE-88: Improper Neutralization of Argument Delimiters in a Command and CWE-184: Incomplete List of Disallowed Inputs. In a SAST context, Offensive360’s engine flags this pattern by tracing data flow from file-read operations into argument-parsing or command-execution sinks.

Specifically, our rules look for:

  • Taint propagation from file I/O functions (fgets, getline, ReadFile) through string comparison branches that gate on a single character prefix (e.g., line[0] == '/') and then forward the raw buffer to a function whose parameter type is argv-style (char** or const char* const*).
  • Sink identification: any call to functions matching the pattern *parse_args*, *parse_cmdline*, execvp, execve, CreateProcessA/W, or equivalent where at least one argument originates from a tainted file-read source.
  • Missing allowlist check: the absence of an explicit set-membership validation between the file-read source and the sink call is flagged as a high-confidence finding under the Unsafe Deserialization / Argument Injection rule category.

In DAST, this class is detected by fuzzing RDP file content with CLI-option payloads and observing anomalous child process creation or outbound connection behavior — both observable without source code access.

References

#command-injection #rdp #file-parsing #remote-code-execution #certificate-bypass

Detect this vulnerability class in your codebase

Offensive360 SAST scans your source code for CVE-2026-64624-class vulnerabilities and thousands of other patterns — across 60+ languages.