A newly disclosed vulnerability in FreeRDP, the widely deployed open-source RDP implementation powering servers like sfreerdp-server, freerdp-shadow-cli, and various proxy and embedded appliances allows unauthenticated attackers to write attacker-controlled data past a fixed-size heap buffer before any credentials are checked.
Tracked as GHSA-pjqx-v446-x7fc and rated High severity, the flaw lives in a function that has been scrutinized before, yet still hides a classic “check-after-write” bug.
The issue was discovered by Claude, an AI model developed by Anthropic, using autonomous agents tasked with auditing open-source security, and was validated and reported by Ada Logics. It affects all FreeRDP 3.x releases up to and including 3.27.1, with a fix landing in 3.28.0.
FreeRDP Pre-Auth Flaw
The vulnerable function, crypto_rsa_common() in libfreerdp/crypto/crypto.c, performs RSA modular exponentiation and then serializes the result into a caller-supplied buffer using OpenSSL’s BN_bn2bin().
That function writes BN_num_bytes(y) bytes, however large the resulting value is, directly into the destination buffer, with zero regard for the buffer’s actual capacity.
Only after that write does the code check output_length > out_length at line 109. It’s textbook CWE-697 (Incorrect Comparison) feeding directly into CWE-787 (Out-of-Bounds Write): the safety check exists, but it runs after the damage is already done.
On the server side, this function is reached through rdp_update_client_random() in connection.c, which allocates a hard-coded 32-byte buffer for the ClientRandom value and passes it as the decryption target regardless of the RSA key size in use.
Here’s the catch: the server publishes its own RSA public key (n, e) in the Proprietary Server Certificate during connection setup. An attacker doesn’t need to break RSA or know the private key. They simply pick an arbitrary plaintext value Y sized to the full modulus (256 bytes for RSA-2048) and compute X = Y^e mod n.
When the server decrypts X, it faithfully recovers Y and BN_bn2bin() writes all 256 bytes into that 32-byte buffer, an overflow of up to roughly 224 fully attacker-controlled bytes.
This path is reachable the moment a client negotiates RDP Standard Security (PROTOCOL_RDP) instead of TLS/NLA a choice the client makes unilaterally, before any authentication occurs.
FreeRDP watchers may recognize crypto_rsa_common() from CVE-2020-13398 (GHSL-2020-102). That earlier issue concerned input buffer handling, back when the function didn’t even have an out_length parameter.
Developers later added that parameter and the corresponding bounds check but placed it after the write instead of before, leaving a structurally different, still-exploitable defect in the same function.
The overflow’s length and content are fully attacker-controlled, and because the write is repeatable across reconnects, it opens the door to heap grooming, a technique that can shape memory layout to increase reliability of further exploitation.
Researchers confirmed the primitive using an AddressSanitizer-instrumented build, reproducing the heap-buffer-overflow deterministically in bn2binpad/BN_bn2bin inside OpenSSL’s own code.
At minimum, this guarantees a remote, pre-auth denial-of-service crash. Control-flow hijack wasn’t demonstrated in the report, which is why it’s rated High rather than Critical, but corruption of adjacent heap metadata gives it real potential as a stepping stone toward RCE.
mi
FreeRDP 3.28.0 fixes this by validating BN_num_bytes(y) against out_length before calling BN_bn2bin() the correct ordering that should have existed from the start.
Until upgrading, administrators can mitigate exposure by disabling RDP Standard Security and enforcing TLS/NLA (PROTOCOL_SSL/PROTOCOL_HYBRID), which prevents the vulnerable code path from ever executing.
Given the pre-authentication, network-reachable nature of this flaw, FreeRDP-based server deployments, particularly public-facing proxies and shadow servers, should prioritize patching immediately.