Skip to content

your PBX takes orders by text message: hunting FreeSWITCH CVE-2026-116779 before someone else does

Hunt FreeSWITCH CVE-2026-116779: SIP MESSAGE api Proto Audit Lab

your PBX takes orders by text message: hunting FreeSWITCH CVE-2026-116779 before someone else does

FreeSWITCH had a chat feature. the chat feature had a protocol selector. one of the protocols was called api, and it ran FreeSWITCH API commands. so a SIP text message to the right address was, functionally, a remote shell with a ringtone. the fix shipped in August. the advisory went public October 28. CISA put it on KEV this morning. today we audit a lab PBX the way an assessor should audit yours: version, profiles, directory, logs. no exploit, no payload, just the stuff that actually tells you whether you are in trouble.

Lab-only / defensive use. every command here runs against a lab config tree and sample logs with documentation IP addresses. the downloadable kit sends no SIP traffic, contains no exploit or payload code, and redacts command strings in its sample data. we do not link proof-of-concept code. if you are on an engagement, auditing a client PBX config with their written permission is the job. throwing MESSAGE requests at it is a different job, with a different contract.
The short version. FreeSWITCH up to and including 1.11.2 lets an inbound SIP MESSAGE select the api chat proto, which reaches switch_api_execute() and runs FreeSWITCH API commands, including OS command sinks, with the daemon’s privileges. chat is on by default in the stock internal and external profiles. any one account on the profile is enough, and stock password-less directory users can remove even that. SignalWire says exploitation has been observed in the wild. fixed in 1.11.3, released August 28, 2026. KEV due date for federal agencies: November 12, 2026.

the bug, in the maintainers’ words

from SignalWire’s advisory GHSA-mg63-h38w-8p9p: sofia_presence_handle_sip_i_message() “splits the To user of an inbound SIP MESSAGE on + and treats the left half as a chat proto name, dispatching the message to whichever registered chat interface matches.” mod_dptools registers an api chat interface “that hands its address to switch_api_execute().” therefore “a peer that can deliver a MESSAGE to a profile therefore selects which FreeSWITCH API command the server runs.”

and the part that should be on a poster in every telecom NOC: “Nothing restricts the selector, and message-delivery protos are not distinguished from command-execution protos.”

someone designed a router where one of the exits is “root.” and then forgot to put a door on that exit. for years.

what it gets an attacker

per the advisory: command execution with the privileges of the FreeSWITCH process, meaning arbitrary OS commands, disclosure of configuration and credentials, and full call control. where mod_lua is loaded, “as stock configuration does,” inline Lua with the full standard library is reachable as a second sink. so disable_system_api_commands alone does not save you. the advisory says so explicitly. we will get there.

full call control on a phone switch means toll fraud, call interception and rerouting, and a nice quiet pivot point inside a network segment that most security teams treat as “the phone people’s problem.”

who is exposed, exactly

no guessing, straight from the advisory’s “Affected configurations” and “Attack prerequisites”:

  • versions: FreeSWITCH <= 1.11.2 (the CVE record says “prior to 1.11.3”, same thing). the GitHub release list shows no 1.10.x release after 1.10.12 in August 2024, so the fix you can install is 1.11.3 or later.
  • config: any SIP profile that accepts inbound MESSAGE. chat is on unless the profile sets enable-chat=false. stock conf/vanilla leaves it on for internal and external. “No non-default setting is required.”
  • your ACL does not help: “The inbound ACL does not cover MESSAGE, so tightening it does not take a profile out of scope.”
  • authentication: where MESSAGE auth is enforced, “any one account on that profile is enough: an extension, a handset, or a trunk peer.” one compromised desk phone credential and you are in.
  • the stock gift: installs that still carry conf/vanilla/directory/default/default.xml have a user id="default" with no password and no a1-hash. per the advisory, a directory user with neither “authenticates successfully unless allow-empty-password is set to false for it.” vanilla ships two of these: default and the Skinny example.

dates and scores, with owners attached

  • August 26, 2026: fix commit 7015f6a, “[mod_sofia] Add enable-chat-api-proto to gate the api chat proto.”
  • August 28, 2026: FreeSWITCH v1.11.3 released. release notes: “an important release containing critical security fixes,” adding enable-chat-api-proto to mod_sofia and mod_verto and bounding the To-user split in the inbound MESSAGE handler.
  • October 28, 2026: GHSA-mg63-h38w-8p9p published.
  • November 5, 2026: CVE-2026-116779 published by GitHub’s CNA.
  • November 9, 2026: added to CISA KEV. due November 12. ransomware use: Unknown. forensic triage flagged.
  • CVSS 3.1 9.8 Critical (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H), assigned by GitHub as CNA. NVD showed “Undergoing Analysis” with only that score on November 9. CISA ADP SSVC: Exploitation active, Automatable yes, Technical Impact total.
  • CWEs per KEV: CWE-77, CWE-78, CWE-749.
  • credit: Örn Arnarson and Gunnlaugur, per the advisory.

yes, a CVSS of 9.8 with PR:N on a bug where the advisory says an account is sometimes needed. the stock password-less directory user is why “none” is not crazy. we report the vector as assigned. argue with GitHub, not us.

what the fix actually does

1.11.3 adds a per-profile parameter, enable-chat-api-proto, that is off unless explicitly set. a MESSAGE that selects the api proto on a profile without it is answered 403 and logged with the source and the requested command. the comparison is case-insensitive, matching the chat interface registry. messages with no proto selector, or naming another proto, route normally. the parameter ships commented out in the vanilla profiles.

two consequences for the audit:

  • if anyone sets enable-chat-api-proto=true, they reopened the hole on a patched build. config review matters even after the upgrade.
  • a patched box now writes a WARNING line every time someone tries. the fix commit’s log string reads “Profile [%s] rejected a MESSAGE from %s@%s (%s:%d) addressed to the ‘api’ chat proto [%s].” that is a free detection. use it.

step 1: version and config audit

get the version from fs_cli -x version, then point the auditor at the config tree. it parses every SIP profile for enable-chat, enable-chat-api-proto, and auth-messages, and walks the directory for users with no password and no a1-hash.

Kali terminal running fs-116779-audit.py version mode flagging FreeSWITCH 1.11.2 as vulnerable, then config mode against a lab tree with four SIP profiles: external and internal EXPOSED with default chat on, legacy VULN with enable-chat-api-proto true, trunk OK with enable-chat false, and a WEAK finding for the password-less default directory user.
Step 1: lab config. internal and external are exposed on any pre-1.11.3 binary. the legacy profile is broken even on 1.11.3 because someone set enable-chat-api-proto=true. the default user with no password or a1-hash is the stock gift the advisory warns about.

assessor’s note: in a real engagement this is the finding table. version, per-profile chat posture, and orphaned directory users. three lines in the report, one of them critical, and you did not have to send a single packet.

step 2: log and trace hunt

two signals, depending on what build you were running when it mattered:

  • on 1.11.3 or later: grep freeswitch.log for the rejection line. every hit is someone who tried. the line includes the source IP, port, and the requested command. patched does not mean uninteresting.
  • on 1.11.2 or earlier: there is no rejection line, because nothing was rejected. you need SIP traces (sofia siptrace output, SBC logs, or packet captures) showing inbound MESSAGE requests whose To user starts with api+. the advisory’s mechanism is the split on + with the left side as the proto, so that prefix is the indicator. if you have no traces from the exposure window, you have no way to rule it out from logs alone. say that in the report.
Kali terminal running fs-116779-audit.py logs against a sample freeswitch.log and SIP trace, showing two BLOCKED rejection lines from documentation address 203.0.113.45 with redacted or harmless command strings and one HIT for an inbound MESSAGE whose To user selects the api proto.
Step 2: sample lab data with documentation IPs. command strings are redacted on purpose. BLOCKED means a 1.11.3+ box refused it. a HIT on an older build means you investigate it as a possible compromise.

the advisory gives no indicators, dates, or victim counts for the in-the-wild activity. we are not going to invent any. your own logs are the IOC feed here.

step 3: interim hardening, if you cannot upgrade today

the advisory’s workaround list, ranked by how much it actually helps:

  • enable-chat=false on every profile that does not need inbound SIP chat. this “stops the message before the proto selector is parsed.” the cost: all inbound MESSAGE chat on that profile stops. most PBXs will not notice. some will, loudly.
  • auth-messages plus removing password-less directory users. on by default from 1.10.7 onward. combined with deleting default and the Skinny example (or setting allow-empty-password to false), it “reduces this to authenticated command execution, but does not close the path.” authenticated RCE is still RCE.
  • disable_system_api_commands=true. removes the system API “but not the route, which still reaches every other registered API, including module loading and call origination.” worth setting. not a fix. and remember the Lua sink.
Kali terminal running fs-116779-mitigate.sh in dry-run mode against the lab config, proposing enable-chat false for external, internal and legacy profiles, telling the operator to remove enable-chat-api-proto true from legacy, confirming trunk already has enable-chat false, and listing the password-less default directory user file.
Step 3: dry run only. –apply edits with backups and then you restart each sofia profile. the script also lists the password-less directory user file to remove.

after the patch, the boring part that matters

  • rotate. the advisory lists configuration and credential disclosure. if a pre-1.11.3 profile accepted MESSAGE from the internet, rotate SIP account passwords, trunk credentials, and anything else stored in the config tree.
  • check call records for origination you did not authorize. call control was in scope. toll fraud shows up on the carrier bill before it shows up in your SIEM.
  • check the host for processes and files owned by the FreeSWITCH user that nobody can explain. commands ran with the daemon’s privileges.
  • leave enable-chat-api-proto unset. if a vendor integration “needs” it, ask the vendor why their product needs remote API execution over chat. enjoy the silence.

download the Kali defensive kit

freeswitch-116779-defensive-kit.zip contains fs-116779-audit.py (version, config, and log modes), fs-116779-mitigate.sh (dry run by default, backups before edits), a README, and the lab config and sample logs used above. fixed version called out everywhere: FreeSWITCH 1.11.3, with enable-chat-api-proto left off. it sends no SIP and contains no exploit code.

sources