//nefariousplan

CVE-2026-7415: Yarbo's MQTT Broker Is Not Anonymous. The Password Is in the App.

patterns

cve

CVE-2026-7415 names "the MQTT broker embedded in Yarbo firmware v2.3.9" and says it allows anonymous connections with no topic-level read or write ACLs. The broker is not embedded in the firmware. It is EMQX Cloud, hosted at t9db1d91.us-east-1.emqx.cloud:15736. Connections to it are not anonymous. They require username hytech and password hy18129XXXXXX, hardcoded in five separate files on every robot's filesystem and in the public Android app com.hanyang.yarbo. The CVE describes a broker that does not exist and an authentication scheme that the broker is not running.

The CVE describes a broker that does not exist

The candidate is for a single bug class: MQTT without authentication. Reading the NVD text alone, a defender would conclude that some component in Yarbo's firmware runs a Mosquitto-style local broker open to LAN traffic. "Any host on the same network" in the NVD text reinforces that reading: a host on the same subnet as the robot, reachable across the residential router.

That broker does not exist. Andreas Makris' writeup dumps the broker configuration from the device filesystem. Yarbo robots speak MQTT to three remote brokers:

Broker Region Use
t9db1d91.us-east-1.emqx.cloud:15736 EMQX Cloud, US East Production app and robot traffic
ke5bbebb.cn-shenzhen.emqx.cloud:8883 EMQX Cloud, Shenzhen CN users
mqtt-b8rkj5da-usw-public.mqtt.tencenttdmq.com Tencent Cloud Server-flagged migration target

All three are public-internet cloud services. None are embedded in the firmware. None are anonymous. From userdata/greengrass/v2/.../device_ops_node.py lines 44 and 45, replicated in debug_control.py line 72 and debug_display.py line 39:

broker   = "t9db1d91.us-east-1.emqx.cloud"
port     = 15736
username = "hytech"
password = "hy18129XXXXXX"

The CVE's "any host on the same network" describes a LAN-level attack surface. The actual surface is global: the broker is reachable from anywhere with internet access, authentication is required, and the credentials are fleet-wide. The bug is bigger than the CVE says. It also lives somewhere the CVE does not point.

One credential, six systems

hy18129XXXXXX is not the broker's password. It is Yarbo's password, used by their engineers as a single authority token across every system the robots talk to. Makris' filesystem dump catalogs the same string in six separate roles on a single device:

System File on robot Role of the string
FRP SSH tunnel com.yarbo.frpc/1.0.17/Archive/frpc.toml auth.token (frpc to frps registration)
EMQX MQTT (device ops) yarbo/3.10.0.3/.../device_ops_node.py MQTT password, username hytech
EMQX MQTT (debug control) yarbo/3.10.0.3/.../launch/debug_control.py MQTT password
EMQX MQTT (debug display) yarbo/3.10.0.3/.../launch/debug_display.py MQTT password
Tencent TDMQ (migration) installer/.../MqttClient_v1.0.10_251014/mqtt_client.py MQTT password
OTA progress reporting ota_progress/1.2.12/ota_progress/progress.py MQTT password
Installer deploy script userdata/env_init/.env_init/deployDir/deploy.sh usrKey

The hy prefix is Hanyangtech's internal naming convention. Hanyangtech (深圳汉阳科技有限公司) is Yarbo's Chinese parent company; the @Author headers in these files name Darwin [email protected]. The same prefix appears in the root SSH password set by the credential_updater Greengrass component, hy@0886!#, applied identically on every robot in the fleet.

Six systems, one token, fleet-wide. CVE-2026-7415 covers the MQTT instances. CVE-2026-7413 covers the FRP/SSH instance. CVE-2026-7414 covers developer credentials in the APK. The three CVEs describe three appearances of one design choice.

The credential is not leaked. It is shipped.

A leaked credential is one that was supposed to be a secret. The compromised git commit, the misconfigured S3 bucket, the screenshot of a developer's terminal. The vendor's response in those cases is to rotate, revoke, and audit.

hy18129XXXXXX is not in that category. There are two retrieval paths:

  1. The robot. Pull device_ops_node.py off the device filesystem; the password is on line 45.
  2. The phone. The Yarbo Android app, com.hanyang.yarbo, is on the Play Store. Extract the APK with any APK puller. The credential is in the asset bundle.

Customers receive hy18129XXXXXX as part of the purchase. The token is the API key the application uses to reach its own backend. There is no version of "rotation" that does not break every shipped robot and every installed phone.

This is what makes "MQTT broker without ACLs" the wrong framing. ACLs assume the credentials enforcing them are scoped per-caller. Yarbo issues one credential to every caller. There is no scoping to enforce. The MQTT broker is not the unit of trust; the Yarbo organization is.

credential_updater is the patch the firmware runs

If Yarbo wanted to fix this, they would push new credentials via OTA. The mechanism is already on every robot. It is named credential_updater (v1.0.3), and Makris recovered it from userdata/greengrass/v2/packages/artifacts/credential_updater/1.0.3/x.update.credentials.sh:

function update_password() {
    local user="$1"
    local password="$2"
    echo -e "$password\n$password" | sudo passwd root
}

function main() {
  update_credentials "$1" "$2" "firefly" "/home/firefly/.aws"
  update_credentials "$1" "$2" "root"    "/root/.aws"
  update_password "root" "hy@0886!#"
}

The component is not pushing per-device credentials. It is hardcoding hy@0886!# as the root SSH password and applying it identically on every robot in the fleet. The component runs on the device, with the credential baked into its own source.

The persistence layer beneath it is stacked. The FRP client installs itself into root's crontab on first boot, from com.yarbo.frpc/1.0.17/Archive/start.sh:

(crontab -l ; echo "* * * * * bash $SCRIPT_PATH") | crontab -

Cron checks the process every minute. If frpc is not running, cron restarts it. A second Greengrass component, monitor_files (v1.0.28), uses Linux auditd to monitor critical filesystem paths and automatically restore deleted files from a backup directory. If an owner removes credential_updater or com.yarbo.frpc, monitor_files reinstates them. If an owner removes monitor_files, Greengrass redeploys it from the AWS IoT Greengrass v2 control plane.

The persistence is not a coincidence of layered safeguards. The persistence is Yarbo's design statement that the credential is not the customer's to change.

"Remote access is not a 'permanently open' feature"

Makris emailed Yarbo support before publishing. The full transcript is in the writeup. The relevant claim, quoted from Yarbo's reply:

Remote access is not a "permanently open" feature. It is a strictly controlled protocol that is only initiated in the event of a specific repair or a backend diagnostic requirement. Apart from these authorized service instances, your Yarbo remains completely secure and under your exclusive control, no third party has the ability to access or view your details.

The technical reality is on the device filesystem in frpc.toml:

serverAddr = "98.82.87.76"
serverPort = 7000
auth.method = "token"
auth.token  = "hy18129XXXXXX"
transport.tls.enable = false
transport.poolCount = 5
transport.heartbeatInterval = 30

start = ["tcpmuxhttpconnect"]

[[proxies]]
name       = "tcpmuxhttpconnect"
type       = "tcpmux"
multiplexer = "httpconnect"
localIP    = "127.0.0.1"
localPort  = 22
customDomains = ["{{ .Envs.SN}}.yb.com"]

transport.poolCount = 5 keeps five pre-established TCP connections to Yarbo's frps server at 98.82.87.76:7000 at all times. transport.heartbeatInterval = 30 is twice a minute. The cron line restarts the daemon if it dies. None of this is "initiated in the event of a specific repair." The tunnel is the operating state of the device.

"No third party has the ability to access or view your details" trades on the word third party. The frps server is run by Yarbo and routes traffic by serial number. Anyone who can reach 98.82.87.76:6000 and send an HTTP CONNECT request for <serial>.yb.com is forwarded to that robot's local port 22. Per frpc.toml, FRP's routeByHTTPUser directive (which would require HTTP Basic auth on the proxy port) is in the config file as a comment, not enabled. The HTTP CONNECT proxy accepts no credential from the caller. The third party in Yarbo's sentence is doing all the work: Yarbo is not a third party to itself, and the unauthenticated public is not a third party until they connect.

The "third party" framing fails further

Hanyangtech is not a vendor of Yarbo's. Hanyangtech is Yarbo. The Android package identifier com.hanyang.yarbo is the unhidden name; Yarbo Inc. is the US commercial subsidiary of 深圳汉阳科技有限公司, founded in Shenzhen in 2015. The engineers whose names appear in device_ops_node.py and larkbot.py are not contractors or third-party integrators. They are the company.

larkbot.py, present in three locations on the device filesystem, posts robot serial numbers and hardware telemetry directly to ByteDance's Feishu (Lark) infrastructure at https://open.feishu.cn/open-apis/bot/v2/hook/149cc773-287a-42da-a40b-88873bcae33c. The DNS resolvers Yarbo's firmware injects via com.yarbo.script include 223.5.5.5 (Alibaba DNS) and 114.114.114.114 (114DNS), both Chinese-operated. The MQTT migration the installer component currently runs moves robots from EMQX in US-East to Tencent TDMQ, by a server-side per-device flag the owner cannot see or set.

This is the context for no third party has the ability to access or view your details. The infrastructure transmitting that data is operated by Yarbo, Yarbo's Chinese parent, ByteDance, Tencent, and Alibaba. None of them are third parties under the wording of Yarbo's email. The wording is correct. The customer's reading of it is wrong, by Yarbo's own definitions. This is the denial-by-pedantry shape: a statement whose technical accuracy depends on definitions the customer is not party to.

It is also the trust-inversion shape, in the architecturally clearest form this catalog has seen. The remote-maintenance tunnel is the trusted lane. The credential-rotation script is the trusted lane. The cloud MQTT bus is the trusted lane. All three were authored by the vendor's parent company, all three carry the same token, and all three are restored if the customer touches them. The validation on the distrusted lane (an attacker on the LAN, which is what the CVE imagines) was never the relevant gate, because the trusted lane (the engineer at Hanyangtech with the master credential) was always going to authorize the action.

The disclosure is not a disclosure

Makris did not file responsible disclosure on this. The writeup's "Why I'm publishing this directly" section is explicit: the FRP tunnel is documented on Yarbo's own developer wiki at wiki.yarbo.com; Yarbo's support engineers responded that the architecture is by design and there is no off switch; going back to a company that intentionally built this in would not get it removed.

This is the same disclosure shape Makris and Kevin Finisterre used on the Unitree Go1 in 2024: a manufacturer's persistent SSH tunnel into customer-owned devices, with shared credentials, where responsible disclosure was not on the table because the mechanism was the product. The credentials in the Yarbo writeup are partially redacted (hy18129XXXXXX, [email protected], 00XXXXXX) deliberately, so the writeup does not function as a one-click weaponizer. The serial-number enumeration step, the FRP HTTP CONNECT command, the AWS endpoint that returns RTK-precision GPS by serial number alone (https://oczkojjxh5.execute-api.us-east-1.amazonaws.com/dev/?msg_type=shadow&sn=<SERIAL>), and the full request shape are present.

The result: a CVE-2026-7415 record that names a single MQTT bug, a CVE-2026-7413 record that names a single SSH bug, a CVE-2026-7414 record that names a single credentials-in-APK bug, and a writeup that explains all three are the same artifact written by the same engineers under the same prefix. The CVE catalog has the parts. The writeup has the assembly.

CVE-2026-7415 will appear in vendor coverage as Improper Authentication (CWE-306) against the MQTT broker. The broker is not the unit being authenticated.

PoC: Bin4ry/yarbo-nat-in-my-back-yard

The unit being authenticated is Yarbo, by Yarbo, to a backend Yarbo operates, with a credential Yarbo shipped to every customer's phone.