CVE-2026-49843
Description
FreeSWITCH mod_verto allows unauthenticated attackers to evict legitimate users by exploiting a pre-authentication session ID binding vulnerability.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
FreeSWITCH mod_verto allows unauthenticated attackers to evict legitimate users by exploiting a pre-authentication session ID binding vulnerability.
Vulnerability
In FreeSWITCH versions prior to 1.11.1, the mod_verto module's JSON-RPC handler binds a connection to a client-supplied session ID (sessid) on the first frame, before authentication is performed. This binding inserts the connection into a global session hash table. If a collision occurs, the existing session occupying that slot is evicted, its calls are detached, and its WebSocket connection is closed. This vulnerability affects any FreeSWITCH deployment with a reachable mod_verto WebSocket listener, regardless of the authentication backend or HTTP vhost configuration [1].
Exploitation
An unauthenticated network attacker can exploit this vulnerability by knowing the target session UUID. The attacker sends a crafted first frame to the mod_verto WebSocket listener, providing a sessid that matches an existing legitimate session. This causes the legitimate session to be evicted before any authentication checks are completed. While the attacker's connection occupies the session UUID slot, they cannot invoke authenticated methods without valid credentials. Practical attacks require obtaining the target session UUID through a side channel, as blind enumeration is infeasible [1].
Impact
Successful exploitation results in a targeted denial of service against a specific verto session. The legitimate user's connection is terminated, their calls are detached, and their WebSocket is closed. The attacker gains control of the session UUID slot but cannot take over the victim's session or bypass authentication. The impact is limited to evicting the existing connection [1].
Mitigation
This vulnerability has been fixed in FreeSWITCH version 1.11.1, released on 2024-01-15 [2]. The fix involves deferring the sessid to connection bind operation until after the authentication gate in the JSON-RPC handler. As a workaround, administrators can restrict the mod_verto WebSocket listener to trusted networks using firewall rules or bind addresses, or disable mod_verto entirely if it is not in use [1].
AI Insight generated on Jun 9, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
3(expand)+ 1 more
- (no CPE)
- (no CPE)range: <1.11.1
- Range: <1.11.1
Patches
1693f7dc6aad2Merge commit from fork
1 file changed · +27 −11
src/mod/endpoints/mod_verto/mod_verto.c+27 −11 modified@@ -1272,10 +1272,11 @@ static jsock_t *get_jsock(const char *uuid) static void tech_reattach(verto_pvt_t *tech_pvt, jsock_t *jsock); -static void attach_jsock(jsock_t *jsock) +static switch_bool_t attach_jsock(jsock_t *jsock) { jsock_t *jp; int proceed = 1; + switch_bool_t result = SWITCH_TRUE; switch_mutex_lock(verto_globals.jsock_mutex); @@ -1284,6 +1285,17 @@ static void attach_jsock(jsock_t *jsock) if ((jp = switch_core_hash_find(verto_globals.jsock_hash, jsock->uuid_str))) { if (jp == jsock) { proceed = 0; + } else if (!zstr(jp->uid) && !zstr(jsock->uid) && strcmp(jp->uid, jsock->uid)) { + /* Refuse cross-identity takeover when both jsocks are authenticated under different uids. + * Clear uuid_str and set nodelete to prevent any uuid_str-keyed teardown + * (detach_jsock, del_jsock, detach_calls) from touching jp. */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "User %s blocked from taking over session %s owned by %s\n", + jsock->uid, jsock->uuid_str, jp->uid); + jsock->nodelete = 1; + jsock->uuid_str[0] = '\0'; + proceed = 0; + result = SWITCH_FALSE; } else { cJSON *params = NULL; cJSON *msg = NULL; @@ -1304,6 +1316,7 @@ static void attach_jsock(jsock_t *jsock) } switch_mutex_unlock(verto_globals.jsock_mutex); + return result; } static void detach_jsock(jsock_t *jsock) @@ -1482,10 +1495,8 @@ static void process_jrpc_response(jsock_t *jsock, cJSON *json) { } -static void set_session_id(jsock_t *jsock, const char *uuid) +static switch_bool_t set_session_id(jsock_t *jsock, const char *uuid) { - //cJSON *params, *msg = jrpc_new(0); - if (!zstr(uuid)) { switch_set_string(jsock->uuid_str, uuid); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s re-connecting session %s\n", jsock->name, jsock->uuid_str); @@ -1494,8 +1505,7 @@ static void set_session_id(jsock_t *jsock, const char *uuid) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s new RPC session %s\n", jsock->name, jsock->uuid_str); } - attach_jsock(jsock); - + return attach_jsock(jsock); } static cJSON *process_jrpc(jsock_t *jsock, cJSON *json) @@ -1515,11 +1525,6 @@ static cJSON *process_jrpc(jsock_t *jsock, cJSON *json) sessid = cJSON_GetObjectCstr(params, "sessid"); } - if (!switch_test_flag(jsock, JPFLAG_INIT)) { - set_session_id(jsock, sessid); - switch_set_flag(jsock, JPFLAG_INIT); - } - if (zstr(version) || strcmp(version, "2.0")) { reply = jrpc_new(0); jrpc_add_error(reply, CODE_INVALID, "Invalid message", id); @@ -1546,6 +1551,17 @@ static cJSON *process_jrpc(jsock_t *jsock, cJSON *json) switch_set_flag(jsock, JPFLAG_AUTHED); } + /* Bind only after the auth gate — attach_jsock()'s eviction + * must not be reachable pre-auth. */ + if (!switch_test_flag(jsock, JPFLAG_INIT)) { + if (!set_session_id(jsock, sessid)) { + jrpc_add_error(reply, CODE_AUTH_FAILED, "Session in use", id); + jsock->drop = 1; + goto end; + } + switch_set_flag(jsock, JPFLAG_INIT); + } + if (!method || !(func = jrpc_get_func(jsock, method))) { jrpc_add_error(reply, -32601, "Invalid Method, Missing Method or Permission Denied", id); } else {
Vulnerability mechanics
Synthesis attempt was rejected by the grounding validator. Re-run pending.
References
2News mentions
0No linked articles in our index yet.