FreeSWITCH SIP MESSAGE RCE, Exploited in the Wild (CVE-2026-116779)
A SIP MESSAGE to a stock FreeSWITCH profile can run FreeSWITCH API and OS commands; fixed in 1.11.3 and exploited in the wild.
TL;DR
- A crafted SIP MESSAGE to a FreeSWITCH profile can select the
apichat protocol and run FreeSWITCH API commands, including operating-system commands, as the FreeSWITCH process. SignalWire published CVE-2026-116779 on 2026-11-05. - Every release up to 1.11.2 is affected. Stock internal and external profiles accept inbound MESSAGE by default, and a stock
defaultdirectory user with no password can make the attack unauthenticated. - The advisory scores it CVSS v3.1 9.8 Critical and states that exploitation of this path has been observed in the wild. The CVE is not in CISA KEV as of 2026-11-06.
- Upgrade to FreeSWITCH 1.11.3 or later. If you cannot, set
enable-chat=falseon profiles that do not need SIP chat; see "How do I fix it?".
Am I affected?
You are exposed only when all of these hold:
- The host runs FreeSWITCH 1.11.2 or earlier.
- At least one SIP profile accepts inbound MESSAGE. Chat handling is on unless the profile sets
enable-chat=false, and the stockconf/vanillainternal and external profiles leave it on. - The attacker can reach that profile over SIP, or can deliver a MESSAGE through a trunk or peer that can.
- The profile does not already reject the
apichat protocol. Releases before 1.11.3 have noenable-chat-api-protosetting, so the route is available on every profile that accepts MESSAGE.
MESSAGE authentication changes who can reach the route but does not remove it. Since FreeSWITCH 1.10.7, auth-messages is on by default, so any account on the profile is enough: an extension, a handset, or a trunk peer that can register. The stock conf/vanilla/directory/default/default.xml defines a default user with no password and no a1-hash; a directory user with neither authenticates unless allow-empty-password is false for it. That makes the stock configuration unauthenticated.
The inbound ACL does not cover MESSAGE, so tightening the ACL does not take a profile out of scope. A profile with enable-chat=false does not reach the vulnerable handler.
| Branch | Affected versions | Fixed version |
|---|---|---|
| FreeSWITCH 1.11 | 1.11.0 to 1.11.2 | 1.11.3 (released 2026-08-28) |
| FreeSWITCH 1.10 and earlier | every release before 1.11.3 | 1.11.3 |
Check what the host runs and which profiles accept chat:
# FreeSWITCH version
fs_cli -x "version"
# If fs_cli is unavailable, run the binary directly
freeswitch -version
# Profiles and whether inbound chat is disabled
grep -R "enable-chat" /etc/freeswitch/sip_profiles/ 2>/dev/null
# Directory users with no password or a1-hash
grep -R -E "<user id=|<param name=\"(password|a1-hash)\"" /etc/freeswitch/directory/ 2>/dev/null
A profile with no enable-chat=false line is in scope. The default user is the one to look for first: if it has neither password nor a1-hash, a MESSAGE can reach the route without an account.
How do I fix it?
- Upgrade to FreeSWITCH 1.11.3 or later. Use the SignalWire package repository or rebuild from the v1.11.3 tag, then restart FreeSWITCH. The release notes list the new
enable-chat-api-protoparameter and the bound on the To-user split. - If you build your own packages, rebuild every node that runs
mod_sofiaandmod_dptools; the fix is in both modules and in the vanilla profile samples. - If you cannot upgrade, disable inbound chat on every profile that does not need it:
<param name="enable-chat" value="false"/>Add the line to each profile in/etc/freeswitch/sip_profiles/, then reload the profile or restart FreeSWITCH. This closes the route because the handler returns before it parses the protocol selector. The cost is that the profile stops delivering all inbound SIP MESSAGE chat, not only theapiprotocol. - If you need chat and cannot upgrade, remove every directory user that has no
passwordora1-hash, and setallow-empty-passwordto false for the rest. Combined withauth-messages, this reduces the attack to an authenticated user; it does not close the route, because any account can still selectapi. disable_system_api_commands=trueremoves thesystemAPI but not the route. The attacker can still reach every other registered API, including module loading and call origination. Treat it as a narrowing measure, not a fix.
What is the root cause?
The SIP MESSAGE handler treats the left side of the To user as a chat protocol name and the right side as the address, and the api chat protocol executes its address as a FreeSWITCH API command. In src/mod/endpoints/mod_sofia/sofia_presence.c, sofia_presence_handle_sip_i_message() does this:
if ((p = strchr(to_user, '+')) && p != to_user) {
switch_copy_string(proto, to_user, sizeof(proto));
p = strchr(proto, '+');
*p++ = '\0';
if ((to_addr = strdup(p))) {
if ((p = strchr(to_addr, '+'))) {
*p = '@';
}
}
} else {
to_addr = switch_mprintf("%s@%s", to_user, to_host);
}
It then puts proto in the to_proto header and to_addr in the to header of a SWITCH_EVENT_MESSAGE. Nothing restricts which protocol name the sender may choose. mod_dptools registers the api chat interface next to the event one:
SWITCH_ADD_CHAT(chat_interface, "event", event_chat_send);
SWITCH_ADD_CHAT(chat_interface, "api", api_chat_send);
api_chat_send() takes the to header, URL-decodes it, splits it at the first space, and passes the two parts to switch_api_execute():
if (to) {
char *v = NULL;
switch_stream_handle_t stream = { 0 };
char *cmd = NULL, *arg;
if (!(v = switch_core_get_variable_dup(to))) {
v = strdup(to);
}
cmd = v;
switch_assert(cmd);
switch_url_decode(cmd);
if ((arg = strchr(cmd, ' '))) {
*arg++ = '\0';
}
SWITCH_STANDARD_STREAM(stream);
switch_api_execute(cmd, arg, NULL, &stream);
A MESSAGE to sip:api+system%20id@example.com sets proto to api and to_addr to system%20id. api_chat_send() decodes the address to system id, splits it into the command system and the argument id, and runs it. The output is sent back as the chat reply.
How is it exploited?
- The attacker sends a SIP MESSAGE to a profile that accepts inbound chat, addressed to
sip:api+system%20id@targetor to another API command encoded the same way. - If the profile enforces MESSAGE authentication, the attacker uses any account on the profile, or the stock
defaultuser that has no password and noa1-hash. sofia_presence_handle_sip_i_message()splits the To user at the first+: the left side becomesto_proto=api, the right side becomesto=system%20id.- The chat layer dispatches the message to the
apiinterface registered bymod_dptools. api_chat_send()URL-decodessystem%20id, splits it intosystemandid, and callsswitch_api_execute("system", "id").- The command runs with the FreeSWITCH process's privileges. The attacker can run other
systemcommands, load modules, originate calls, or read configuration and credentials; wheremod_luais loaded, inline Lua with the full standard library is a second sink.
The advisory states that exploitation of this path has been observed in the wild. It gives no date, victim count, command sequence or indicators, and no public proof-of-concept code is listed.
How does the attack flow?
A SIP MESSAGE whose To user starts with api+ selects the command-execution chat protocol, and the address after the plus is run as a FreeSWITCH API command.
What can an attacker do?
An attacker who can deliver one accepted MESSAGE to an affected profile can run FreeSWITCH API commands with the privileges of the FreeSWITCH process. That includes:
- Operating-system commands through the
systemAPI, which runs them as the FreeSWITCH user. - Configuration and credential disclosure, including SIP account and trunk credentials the process can read.
- Full call control: originating, bridging, eavesdropping and tearing down calls.
- Module loading and other registered APIs, which can extend the attacker's reach beyond the
systemcommand. - Inline Lua execution where
mod_luais loaded, as stock configuration does, with the full Lua standard library.
The conditions are listed in full: a reachable SIP profile that accepts MESSAGE, enable-chat not false, and either MESSAGE authentication satisfied by any account or a stock directory user with no password and no a1-hash. The process usually runs as an unprivileged freeswitch user; the advisory does not claim root. The impact is still full control of the telephony service and the data it can read.
Why does the fix work?
The fix adds a per-profile flag that is off by default and rejects the api protocol before the message is dispatched:
+ if (!strcasecmp(proto, "api") && !sofia_test_pflag(profile, PFLAG_ENABLE_CHAT_API_PROTO)) {
+ /* p is the rest of the To user, still percent-encoded and bounded by the proto buffer. */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+ "Profile [%s] rejected a MESSAGE from %s@%s (%s:%d) addressed to the 'api' chat proto [%s]. "
+ "Set enable-chat-api-proto=true on the profile to permit it.\n",
+ profile->name, switch_str_nil(from_user), switch_str_nil(from_host), network_ip, network_port, p);
+
+ nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
+
+ if (full_from) {
+ su_free(nua_handle_get_home(nh), full_from);
+ }
+
+ return;
+ }
The comparison is case-insensitive to match the chat registry, which is created case-insensitively. A MESSAGE that selects api on a profile without the flag is answered 403 and logged with the source and the requested command. Messages with no protocol selector, or with another chat protocol, route unchanged. The flag ships commented out in the four vanilla profiles and the mod_sofia sample, so the default is closed. The fix is complete for this route; it does not remove the api chat interface, but it gates it behind an explicit opt-in.
How do I check if I was compromised?
No indicators of compromise are published. The checks in this section find the request pattern and the configuration that made it reachable, not a confirmed compromise:
# MESSAGE requests whose To user selects the api protocol
sudo grep -iE "MESSAGE.*api\+" /var/log/freeswitch/freeswitch.log
# On 1.11.3 and later, rejected attempts are logged with this text
sudo grep -i "addressed to the 'api' chat proto" /var/log/freeswitch/freeswitch.log
# Whether mod_lua is loaded, which adds the inline-Lua sink
fs_cli -x "module_exists mod_lua"
Before 1.11.3, a successful request may leave no warning, and the log may record only a normal MESSAGE. Check for unexpected outbound calls, new files in the FreeSWITCH spool or script directories, changed dialplans, new SIP registrations and any command output the attacker could have received. If you cannot rule out a successful request, treat the host as compromised, rebuild it, rotate the SIP and trunk credentials, and review the call detail records.
Timeline
- 2026-08-26: the fix is committed as PR #3135, adding
enable-chat-api-protoand the 403 response. - 2026-08-28: FreeSWITCH 1.11.3 is released with the fix.
- 2026-10-28: the GitHub security advisory is published and states that exploitation of this path has been observed in the wild.
- 2026-11-05: CVE-2026-116779 is published with CVSS v3.1 9.8.
- 2026-11-06: the CVE is not in CISA KEV; no indicators or victim details are public.
FAQ
Is my FreeSWITCH exposed if I only use SIP trunks?
Yes, if a trunk can deliver a MESSAGE to a profile that accepts chat. An authenticated trunk account is enough, and the stock default user can remove the authentication step entirely. Set enable-chat=false on profiles that do not need chat, or upgrade.
Does this affect hosted PBX and contact-center providers?
Any provider that runs FreeSWITCH 1.11.2 or earlier with inbound chat enabled is exposed. The fix is in the engine, so the provider must upgrade or disable chat on the profiles it exposes. Ask your provider which release it runs.
Is the attack unauthenticated?
In the stock conf/vanilla configuration, yes, because the default directory user has no password and no a1-hash. If that user is removed and allow-empty-password is false, the attacker needs one account on the profile, such as an extension or a trunk peer. That is still a low bar.
Was it exploited in the wild?
The advisory states that exploitation of this path has been observed. It does not give a date, a victim count or indicators. The CVE is not in CISA KEV as of 2026-11-06.
Does disable_system_api_commands=true fix it?
No. It removes the system API, but the route still reaches every other registered API, including module loading and call origination. Use it only as an additional narrowing measure, not as a replacement for the upgrade.
Does the fix break normal SIP chat?
No. It blocks only the api protocol unless the profile sets enable-chat-api-proto=true. Messages with no protocol selector, or with another chat protocol, route as before.
Find exposed SIP services with Ostorlab
Ostorlab's attack surface discovery inventories your internet-facing hosts and the services they expose. Use it to list the systems that answer on SIP ports, then check their FreeSWITCH release and profile configuration first.
References
- FreeSWITCH security advisory GHSA-mg63-h38w-8p9p, published 2026-10-28, the root cause, affected configurations, workarounds and the exploitation statement: https://github.com/signalwire/freeswitch/security/advisories/GHSA-mg63-h38w-8p9p (checked November 6, 2026)
- CVE-2026-116779 record, published 2026-11-05, CVSS v3.1 9.8 and the affected range: https://www.cve.org/CVERecord?id=CVE-2026-116779 (checked November 6, 2026)
- FreeSWITCH commit 7015f6a73ab3d67fed5fbfc277ecfb88a74c2a86, "Add enable-chat-api-proto to gate the api chat proto", 2026-08-26: https://github.com/signalwire/freeswitch/commit/7015f6a73ab3d67fed5fbfc277ecfb88a74c2a86 (checked November 6, 2026)
- FreeSWITCH pull request #3135, the fix and the vanilla profile changes: https://github.com/signalwire/freeswitch/pull/3135 (checked November 6, 2026)
- FreeSWITCH v1.11.3 release notes, 2026-08-28, the new parameter and the To-user bound: https://github.com/signalwire/freeswitch/releases/tag/v1.11.3 (checked November 6, 2026)
- FreeSWITCH
sofia_presence.cat v1.11.2, the vulnerable To-user split: https://github.com/signalwire/freeswitch/blob/v1.11.2/src/mod/endpoints/mod_sofia/sofia_presence.c (checked November 6, 2026) - FreeSWITCH
mod_dptools.cat v1.11.2, theapichat interface andapi_chat_send(): https://github.com/signalwire/freeswitch/blob/v1.11.2/src/mod/applications/mod_dptools/mod_dptools.c (checked November 6, 2026) - FreeSWITCH project page, the statement that it powers carriers and contact centers: https://freeswitch.com/ (checked November 6, 2026)
- Docker Hub,
safarov/freeswitch, 1,366,696 pulls, a community image reach figure: https://hub.docker.com/r/safarov/freeswitch (checked November 6, 2026) - GitHub,
signalwire/freeswitch, 5,283 stars, a repository reach figure: https://github.com/signalwire/freeswitch (checked November 6, 2026) - CISA Known Exploited Vulnerabilities catalog JSON feed, checked for CVE-2026-116779 on November 6, 2026 (not listed): https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json (checked November 6, 2026)