Introduction
On Jan. 16, 2025, Alexandra Alper of Reuters published an article titled “Chinese tech firm founded by Huawei veterans in the FBI’s crosshairs.” The piece explores an ongoing investigation by the U.S. Commerce Department and the FBI into Baicells Technologies, a company flagged for potential national security concerns.
Baicells, founded in China in 2014, has operated in the U.S. since 2015, providing telecom equipment for over 700 networks nationwide, including those used by local municipalities, healthcare facilities, and utility systems. While the company has established a significant presence in the U.S. market, its Chinese origins are drawing scrutiny from federal regulators who are increasingly wary of foreign influence in core communications infrastructure—especially given critical vulnerabilities found in their hardware.
Interestingly, Censys played a minor role in the research supporting this investigation. Our contribution was limited to providing high-level data on the public internet exposure of Baicells devices. However, generating these numbers required significant behind-the-scenes analysis and led us down a rabbit hole of discovery. This report reflects on our process and offers a technical overview of the methods we used to support Reuters’ request.
It should be noted that Censys does not have evidence that any of the allegations are true, nor are we making further accusations. We are a neutral party with no skin in the game. We saw nothing concrete to imply malicious intent from Baicells. This report comprises information pulled together using only publicly accessible data to fingerprint Baicells devices connected to the internet.
Scope & Vulnerabilities
When Reuters approached us about Baicells host counts, we didn’t have concrete numbers because it was the first time we’d heard of the vendor. However, we knew the data likely existed within our resources—we just had to find it. Our primary objective was to estimate how many internet-connected Baicells devices were vulnerable to CVE-2023-24508 and CVE-2023-0776. We aimed to achieve this without engaging in any activities that could be construed as malicious or illegal.
Overview of reviewed CVEs
- CVE-2023-24508: A pre-authentication critical-level vulnerability affecting devices such as Nova 227, Nova 233, and Nova 243 LTE TDD eNodeBs running RTS firmware.
- CVE-2023-0776: A pre-authentication critical-level vulnerability affecting devices like the Nova 436Q and Neutrino 430 LTE running QRTB firmware.
What is Baicells?

Typical LTE Network Architecture (via Fujitsu)
Baicells operates in a specialized corner of the telecom industry, focusing on hardware bridging mobile networks (e.g., LTE and 5G) and IP networks. Their eNB (eNodeB) products, for instance, connect to networks that interact with physical devices like phones while being managed through IP-based systems. Their equipment spans a wide range of use cases and price points, from rugged outdoor LTE to SOHO 5G routers.

Since Baicells devices exist within such a critical intersection of network infrastructure, the security of such a device is of the utmost importance; the possibility and probability of compromise should not be taken lightly, especially given that these devices are known to be running within the US government and military-owned properties.
While this confirmed the presence of these devices online, further investigation was needed to determine their model and firmware versions, which are two critical pieces of information we would need to determine whether these devices were vulnerable to the two CVEs in question.
We noticed that a subset of the results we found in our initial search included what looked like a model name in the HTTP response body defined in a javascript variable—for example: “moduletype=’BRU3510′;”

When we looked for some of these supposed model names in a web search, we found a handful of technical documents related to Baicells, including explicit wording related to the Baicells Nova LTE basestations.

We found that the web interfaces we had discovered with this information were all related to the Nova (RTS) brand of Baicells devices potentially vulnerable to CVE-2023-24508. Below is a table of the known Nova devices, followed by the known Censys search terms that we used to identify a subset of those. Note that any of the model names that we exclude from the searches were not found within our dataset.
 |
Nova 243 |
BRU3501,3510,3511,3528 |
 |
Nova 233 |
mBS1100,1105,11002,11003,11004,11005,11006,11007 |
 |
Nova 277 |
pBS2120,11001,11002,11003,11004,11005,11006 |
At this point, we had found evidence of hardware running the RTS line of firmware (CVE-2023-24508) but had yet to find anything related to QRTB (CVE-2023-0776) devices. But, there were still a lot of Baicells devices out there that fell outside of the above search terms.
Identifying QTRB
Since none of the model names that came back from our initial search matched any of the devices related to CVE-2023-0776, we wanted to determine if there was any mechanism available that may aid in their discovery. We began this process by downloading and unpacking the publicly available QTRB firmware from the Baicells website.
By examining the files served by the public-facing webserver, we identified unique fields within the HTML that could distinguish Baicells devices from non-QTRB-derived ones. Specifically, the file “www/pages/index.html” contained two distinctive form field identifiers: “loginRuleForm” and “loginRules”.

This allowed us to create a simple Censys search query tailored to these criteria, giving us a foundation for future queries targeting QTRB devices. At the time of our initial report to Reuters, this matched over ninety hosts.
Next, we aimed to uncover additional public endpoints on these devices that could provide specific model names and firmware versions. To do this, we performed a simple grep search for the term “version” across all publicly accessible HTTP-related files within the firmware, concentrating on the “cgi-bin” directory—a common location for dynamically generated data.

The most noteworthy file referencing a version was “www/pages/cgi-bin/overview.htm”, which extracted both “software_version” and “hardware_version” values from the underlying system and rendered them for the client. As shown in the screenshot below, this process is a series of system commands, with their output assigned to JavaScript variables.

Next, we combined the Censys CLI with the HTTP client “curl” to confirm that these endpoints do indeed render the software (firmware) version to the user. Using Censys, we identified hosts and ports matching the previously mentioned search criteria, then piped the host information to curl to request the path “/cgi-bin/overview.htm”.
censys search --pages -1 \
'services:(http.response.body:"loginRuleForm" and http.response.body: "loginRules")' | \
jq -cr '.[]|.ip as $i|.name as $n|.matched_services[]|"\(.extended_service_name|ascii_downcase)://\($i):\(.port)"' | \
while read l; do \
echo $l; \
curl -sk $l/cgi-bin/overview.htm | grep software_version; \
done
In the command above, we included a grep to filter the output, ensuring that only hosts containing the specified variable were displayed. As shown in the screenshot below, this method enabled us to extract the specific firmware version running on a substantial number of these hosts—a critical piece of information needed to assess whether these devices were vulnerable to the CVE in question.

During our analysis, we identified 28 hosts that responded with this data and were confirmed to be running a vulnerable version of the QRTB firmware. Still, there were likely more out there that did not respond at the time.
Identifying RTS Vulnerabilities
In contrast to the paths identified for the QRTB line of devices, we could not locate any specific endpoint for RTS-based devices that would reveal version or model information. However, during our analysis, we uncovered what we believe to be the vulnerability detailed in CVE-2023-24508.
We started by downloading two versions of the RTS firmware from the Baicells website: version 3.6.6, known to be vulnerable, and version 3.7.11.6, which includes a patch addressing CVE-2023-24508.
According to the CVE, this vulnerability involves a pre-authentication issue in the HTTP administrative interface. To begin with, we compared the patched firmware with the vulnerable version, focusing on changes made to the files for the web server.
One particularly noteworthy change was the addition of a single line to the file “www-nui/cgi-bin/header.htm” —a dependency for many other scripts involved in dynamically generating content for the web interface:
eval $( baicells_session_validator -c "$COOKIE_hash" -e "$COOKIE_exp" -a "$HTTP_USER_AGENT" -i "$REMOTE_ADDR" -r "login.htm" -t $(uci get baicells.global.session_timeout) -b "$COOKIE_browser_time" )
Before we can fully appreciate the critical importance of this addition, we must first understand the significance of the baicells_session_validator command. During our investigation of Baicells devices, we repeatedly encountered references to the term “Gargoyle” in multiple files. Initially, we assumed this was merely a codename for the software. However, we soon realized that the management system for these devices is primarily based on the (very old) GPLv2-licensed open-source project, the “Gargoyle Router Management Utility”.
This connection can be further substantiated by examining the disassembly of the “baicells_session_validator” binary and comparing it with the source code of Gargoyle’s “session_validator.c“. As shown below, the switch/case statement in Baicells’ “session_validator” aligns almost identically with that of Gargoyle’s implementation:
 |
 |
Baicells session_validator (Ghidra) |
Gargoyle’s session_validator (Github) |
In short, this command is used to authenticate a user via username and password or validate that the client in question has previously authenticated and now has a valid session cookie.
It’s important to note that both Gargoyle and Baicells leverage an embedded scripting language called Haserl, which is a lightweight alternative to frameworks like PHP. Haserl uses shell scripting and Lua as its backend for code execution; however, Baicells only utilizes the latter.
A critical aspect to understand is how CGI scripts utilizing Haserl handle interactions with HTTP client input. Specifically, data inputs from HTTP requests undergo a transformation into Haserl-specific variables:
- HTTP Header Transformation: Key-value pairs in HTTP headers are converted into variables prefixed by the header’s name. For example, a header like “Cookie: blah=thing; foo=bar” would become Haserl input variables “$COOKIE_blah=thing” and “$COOKIE_foo=bar”.
- Query Argument Transformation: Query arguments passed via GET or POST are similarly converted. For example, a request like “POST /data?key=val” would translate to the Haserl variable “$POST_key=val”.
All the code responsible for dynamic content generation resides in the “www-nui/cgi-bin” directory. Each file in this directory has a corresponding JavaScript counterpart located in the “www-nui/js” directory, both of which are publicly accessible paths.
The purpose of these JavaScript files is to handle the form inputs generated by the CGI scripts and perform backend AJAX calls to other subsystems. These calls are made using the “runAjax()” function, which is defined in the “www-nui/js/common.js” file.

One of the most common methods of calling this function is to initiate an AJAX call out to the file “../utility/run_commands.sh” (which is also publicly accessible since AJAX is initiated on the client side)
runAjax("POST", "../utility/run_commands.sh", param, stateChangeFunction);
The contents of the “run_commands.sh” file reveal another Haserl script with some alarming functionality:
#!/usr/bin/haserl
<%
#eval $(baicells_session_validator -c "$COOKIE_hash" -e "$COOKIE_exp" -a "$HTTP_USER_AGENT" -i "$REMOTE_ADDR" -r "login.htm" -t $(uci get baicells.global.session_timeout) -b "$COOKIE_browser_time")
mkdir /tmp/.log
log_file="/tmp/.log/run_cmd.log"
echo "FORM_commands " "$FORM_commands" > $log_file
echo "POST_hash " "$POST_hash" >> $log_file
echo "COOKIE_exp ""$COOKIE_exp" >> $log_file
echo "$HTTP_USER_AGENT" >> $log_file
echo "$REMOTE_ADDR" >> $log_file
echo "COOKIE_browser_time " $COOKIE_browser_time >> $log_file
echo "Content-type: text/plain"
echo ""
#if [ -n "$FORM_commands" ] ; then
echo "begin exec cmd" >> $log_file
tmp_file="/tmp/tmp.sh"
printf "%s" "$FORM_commands" | tr -d "\r" > $tmp_file
sh $tmp_file
echo "end exec cmd" >> $log_file
if [ -e $tmp_file ] ; then
# rm $tmp_file
fi
#fi
echo "Success"
%>
Here, the “$FORM_commands” variable, derived from an HTTP POST request, is directly written to a temporary shell script (“/tmp/tmp.sh”) and executed using the “sh” command. Notably, in the vulnerable version of this firmware, the “baicells_session_validator” command is commented out, effectively bypassing session validation. As a result, simply requesting this specific file could lead to arbitrary code execution with ease.
This firmware’s fixed implementation integrates the “baicells_session_validator” into every CGI script through a header dependency and re-enables the validation check specifically for “run_commands.sh”.
Armed with this knowledge, an attacker could theoretically exploit one of these Baicells devices by supplying all the required fields that Haserl expects as input. For example, an exploit might be as simple as the following:
curl -k \
-X POST \
--data "hash=abcde&commands=$COMMAND\n" \
http://$HOST/utility/run_commands.sh
However, we have not confirmed this as we do not own any of these devices, but comparing the vulnerable version to the fixed version, we can say that this method is close.
Odds and Ends & VPNs
These Baicells devices can also be found under different brandings and names, such as “ABIT”, “Celona”, “Lemko”, and “Sunsea”, and while Baicells has a significant presence in North America, several elements in the firmware reveal its true China-based origins. For example, we find evidence that these systems will use 114.114.114.114, a public DNS server in China, and an NTP configuration for “cn.pool.ntp.org”.
We also found that both the RTS and QTRB firmware are configured (or have the configurations ready) to establish VPN tunnels between the device and two hosts in Microsoft Azure:
The hostname “west/east EPC” may be in reference to the telecom term “Evolved Packet Core” given the fact that Baicells offers a service called “CloudEPC”, a SaaS service provided by Baicells for deploying an EPC in the cloud and using their servers for handling the various functions of an LTE network such as the routing of data between physical devices like phones, and external networks like the internet.

CloudEPC overview (Via Baicells)
We can see these configurations in the QTRB firmware in two XML files that are eventually converted to legitimate StrongSwan VPN configurations via various provisioning and init scripts.
 |
 |
Tunnel Config 1 |
Tunnel Config 2 |
We should note that there is no evidence that these configurations are enabled by default; but, it seems that everything is in place for these VPNs to be enabled, including a readily available client certificate:

However, the RTS line of firmware had a more straightforward UCI-based approach to configuration, making it easier to see what was and was not configured by default. And like the QTRB, we see those two tunnels to the Azure hosts configured, this time with more concrete evidence of it being enabled by default (“/etc/config/ipsec”):
config vpn 'strongswan'
option enabled '1'
option rightikeport '4500'
option left_interface ''
config tunnel
option enabled '1'
option name 'Tunnel1'
option gateway 'baicells-westepc-03.cloudapp.net'
option left_identifier ''
option right_identifier ''
option ike_encryption_algorithm 'aes128'
option esp_encryption_algorithm 'aes128'
option ike_authentication_algorithm 'sha1'
option esp_authentication_algorithm 'sha1'
option leftsourceip '%config'
option ike_dh_group 'modp768'
option esp_dh_group 'null'
option ikelifetime '60m'
option keylife '40m'
option rekeymargin '5m'
option keyingtries '%forever'
option dpdaction 'restart'
option dpddelay '30s'
option authby 'psk'
option pre_shared_key 'baicells.westus'
list rightsubnet '10.3.0.0/24'
config tunnel
option enabled '1'
option name 'Tunnel2'
option gateway 'baicells-eastepc04.eastus.cloudapp.azure.com'
option left_identifier ''
option right_identifier ''
option ike_encryption_algorithm 'aes128'
option esp_encryption_algorithm 'aes128'
option ike_authentication_algorithm 'sha1'
option esp_authentication_algorithm 'sha1'
option leftsourceip '%config'
option ike_dh_group 'modp768'
option esp_dh_group 'null'
option ikelifetime '60m'
option keylife '40m'
option rekeymargin '5m'
option keyingtries '%forever'
option dpdaction 'restart'
option dpddelay '30s'
option authby 'psk'
option pre_shared_key 'baicells.eastus'
list rightsubnet '10.5.0.0/24'
This configuration is seemingly loaded via an init.d script in “/etc/rc.d/S74ipsec” which is a symlink to “/etc/init.d/ipsec’. If we look at the “start()” function we see that there are several steps it goes through to eventually enable this VPN:
start() {
while [ ! -f /tmp/oam.ready ];
do
sleep 1
done
ipsec_log "Ipsec start ..."
CheckInstallation
config_load ipsec
PrepareEnvironment
ConfigVpn
/usr/sbin/ipsec start
}
Here, the “CheckInstallation” function ensures that the “/usr/sbin/ip” tool is available on the system, then “config_load ipsec” is a wrapper around “uci_load” that reads in the configuration from “/etc/config/ipsec”. Then, “PrepareEnvironment” generates a basic StrongSwan configuration file into “/var/ipsec/ipsec.conf”. Finally, the “ConfigVpn” function is called, and it is defined as follows:
While the “config_get_bool” will be true since the default configuration for “strongswan” (in “/etc/config/ipsec”) is “enabled ‘1’”. And for each configured tunnel in that configuration, “ConfigTunnel” generates a valid StrongSwan configuration. However, right before this happens, we see a call to a function named “ConfigOMC”.
This “ConfigOMC” function is odd because it statically configures another VPN tunnel to a remote endpoint with the hostname “baiomc.chinacloudapp.cn” – a host which currently resolves to the IP 42.159.86.204 – a server located in Beijing, China:

42.159.86.204 has seen its fair share of interesting services over the years, including SSH and FTP servers on very high ports and web servers that go up and down over time with Baicells certificates, which provides evidence that these hosts were actively used up to May 1st, 2024 when the host last saw a running service.

The term “OMC” is a reference to another Baicells service offering called the “CloudCore Operations Management Console” which describes itself as the following:
“Administrators use the OMC to configure or modify the eNB and UE components and interfaces, monitor the network, troubleshoot issues, and perform software or firmware upgrades.”
In other words, it is an offering that allows remote-hand management and setup of Baicells devices.
Since we do not own any of these devices, we cannot confirm whether these VPNs are enabled on a live system by default. Still, if someone were to use these CloudEPC or OMC services, it’s probably a good idea to understand that they simply create full VPN tunnels into Baicells-managed infrastructure.
Technically, this could be seen as a pinhole into a Baicells customer device, bypassing any ingress filtering; however, this does not mean Baicells has authenticated access to the actual device unless it is a version of the QRTB firmware that is described in CVE-2022-24693 that states Baicells devices shipped with hardcoded credentials.
There have even been unsubstantiated claims on an unofficial Facebook forum about Baicells that have stated they saw sudden unwanted increases of traffic going to “baiomc.chinacloudapp.cn” back in 2023. A post that can be found with a simple Google search.

We cannot imply or know intent, but the existence of these VPN configurations is a design choice that most security-focused individuals would scrutinize. Architecturally, it feels wrong, but the reality may not be as dramatic as our feelings.
Final Words
In an increasingly interconnected world where more of our hardware and software are developed and maintained outside our countries of origin, where services are continually migrated to “the cloud,” and where paranoia about trustworthiness grows, it is crucial to maintain perspective. We must remember to never attribute to malice that which can be adequately explained by inexperience or poor decisions.
But this also does not mean that these inadequacies could not be taken advantage of by our adversaries, and we should always be more vigilant in our decisions around what runs in the most critical parts of our networks.
When we understand what Baicells is, what they do, and the vulnerabilities they have had, the fact that hundreds of Baicells devices are just sitting out there on the internet is a troubling thought. Devices like these should have as little public internet presence as possible; these administration interfaces should be behind several layers of security, like firewalls and VPNs, completely disconnected from the prying eyes of would-be attackers.