A timing bug in a talking teddy bear's chat parser — annoying, not apocalyptic
CVE-2026-13489 is an improper synchronization flaw (CWE-662) in the ParseMessage function of main/mcp_server.cc inside the 78/xiaozhi-esp32 project — an open-source ESP32-based AI voice-companion firmware that speaks the Model Context Protocol (MCP) to a backend LLM. Versions 2.2.0 through 2.2.6 are affected; a fix is pending in PR #2021 but not yet merged. An authenticated remote actor who can already deliver MCP responses to the device can race the parser to corrupt a single message's state, yielding limited integrity impact (C:N/I:L/A:N).
The vendor's LOW (3.1) rating is *accurate, possibly even slightly generous*. The CVSS vector itself spells out why nobody should lose sleep: AC:H (race window must be hit), PR:L (you're already authenticated to the MCP channel), C:N / A:N (no data leak, no crash), only I:L (partial integrity). This isn't an enterprise patch-management problem — it's a hobbyist firmware bug in a microcontroller toy. If you're managing 10,000 hosts, you almost certainly own zero of these.
3 steps from start to impact.
Obtain MCP channel access to the device
- PR:L — valid MCP session credentials or paired controller token
- Network reachability to the ESP32's MCP listener (typically LAN or backend-routed)
- Devices are not designed to be internet-exposed; they call out to a backend
- No mass-scan footprint (Shodan/Censys won't enumerate these meaningfully)
Win the parser race in mcp_server.cc::ParseMessage
ParseMessage, hitting an unsynchronized shared-state window. AC:H is doing real work here — the ESP32 is single-threaded-ish with FreeRTOS tasks, and the window is narrow. Public PoC exists but reliability is poor.- Ability to send crafted, back-to-back MCP frames
- Knowledge of timing window (PoC reveals it)
- FreeRTOS scheduler jitter makes the race non-deterministic
- Single device, single session — no parallelism advantage
Corrupt a single parsed message (I:L)
A:N), no data exfiltration (C:N).- Race won
- Backend or device acts on the corrupted message
- MCP tool surface on these devices is small (TTS, LED, sensor read)
- No privilege escalation past the already-authenticated session
The supporting signals.
| In-the-wild exploitation | None observed. No KEV listing, no campaign reporting, no honeypot hits. |
|---|---|
| Proof-of-concept | Public PoC referenced by VulDB submission #838198; reliability poor due to AC:H. |
| EPSS | 0.00228 (~0.23%) — bottom-quartile exploitation likelihood. |
| CISA KEV | Not listed. |
| CVSS vector | CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:L/A:N → authenticated remote, race window, integrity-only impact. |
| Affected versions | 78/xiaozhi-esp32 2.2.0 → 2.2.6 inclusive. |
| Fixed version | Unreleased. PR #2021 pending merge as of disclosure. |
| Exposure data | Not enumerable on Shodan/Censys/GreyNoise — ESP32 hobbyist firmware, no canonical fingerprint and not designed for internet exposure. |
| Disclosed | 2026-06-28 via VulDB coordinated submission. |
| Reporter | Anonymous VulDB submitter (submission #838198). |
noisgate verdict.
The single decisive factor is role multiplier — affected component is a hobbyist ESP32 AI-companion firmware with no enterprise deployment role. The blast radius is one toy; there is no high-value role spectrum to floor the verdict above LOW.
Why this verdict
- Friction stack is brutal: PR:L (auth required) + AC:H (race window) + I:L only (no RCE, no DoS, no data leak). Each one pushes severity down independently.
- Role multiplier: Low-value role only. The component is an open-source ESP32 firmware for an AI voice-companion device — there is no Active Directory, hypervisor, IdP, PAM, CI/CD, backup, or kernel-agent role this firmware can occupy. Blast radius caps at *one device*.
- Installed-base evidence: Not present in Tenable/Qualys/Rapid7 plugin catalogs; no Shodan fingerprint; ships on maker-community ESP32 boards, not in enterprise fleets. Enterprise exposure floor is well below 1%.
- EPSS 0.23% + no KEV + no campaign telemetry confirms the math — attacker ROI is negative.
Why not higher?
No memory corruption, no RCE primitive claimed, confidentiality and availability both N, and the attacker must already hold valid MCP credentials. Even a full chain win yields one corrupted message on one device — that is the definition of LOW, not MEDIUM.
Why not lower?
A public PoC exists and the fix is not yet merged, so this is not pure backlog hygiene (IGNORE). If a defender somehow owns these devices in a sensitive context (e.g., a kid's room with a paired smart-home backend), the integrity impact is non-zero and worth tracking.
What to do — in priority order.
- Inventory before you patch — Confirm whether your environment actually runs
78/xiaozhi-esp32firmware anywhere. For 99% of enterprise readers the answer is no and this CVE closes immediately as not-applicable. No mitigation SLA applies to LOW — handle as backlog hygiene. - Segment MCP traffic to the device — If you do own affected devices, ensure the MCP listener is reachable only from the paired backend over a VLAN/VPN. Strip LAN reachability from untrusted Wi-Fi (guest, IoT-segregated SSIDs). This eliminates Step 1 of the chain entirely.
- Track PR #2021 and flash on merge — Subscribe to the upstream repo release feed. When the fix lands in a 2.2.7+ release, OTA-flash devices via the project's normal update channel within the noisgate remediation SLA (365 days for LOW).
- Rotate paired controller tokens — If you suspect a paired controller has been compromised, rotate the MCP pairing secret. Removes PR:L precondition immediately.
- Web Application Firewall — MCP is a binary/JSON protocol over WebSocket/MQTT, not HTTP request/response; a WAF in front of a backend doesn't see the device-side parser.
- EDR/AV — ESP32 is a microcontroller; no agent runs on the target.
- Network IDS signatures — no public Snort/Suricata rule exists, and the race exploit looks like normal MCP traffic.
- Patching the backend — the bug is in the on-device parser, not the cloud side.
Crowdsourced verification payload.
Run on a Linux auditor workstation that can reach the device's HTTP info endpoint, or against a firmware build directory. Invoke as ./check-cve-2026-13489.sh <device-ip-or-firmware-path>. No special privileges needed; needs curl and grep.
#!/usr/bin/env bash
# noisgate verification — CVE-2026-13489 (xiaozhi-esp32 ParseMessage race)
# Usage: ./check-cve-2026-13489.sh <device-ip|firmware-dir>
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
TARGET="${1:-}"
if [[ -z "$TARGET" ]]; then
echo "UNKNOWN: no target supplied" >&2
exit 2
fi
AFFECTED_RE='^2\.2\.[0-6]$'
get_version_from_device() {
# xiaozhi-esp32 typically exposes /api/info or /version on HTTP
for path in /api/info /version /status; do
v=$(curl -fsS --max-time 4 "http://${TARGET}${path}" 2>/dev/null \
| grep -oE '"(firmware_)?version"[[:space:]]*:[[:space:]]*"[^"]+"' \
| head -1 | sed -E 's/.*"([^"]+)"$/\1/')
[[ -n "$v" ]] && { echo "$v"; return 0; }
done
return 1
}
get_version_from_source() {
# Look for CMake/idf version pin or CHANGELOG
if [[ -d "$TARGET" ]]; then
grep -rhoE 'PROJECT_VER[[:space:]]*=?[[:space:]]*"?[0-9]+\.[0-9]+\.[0-9]+' "$TARGET" 2>/dev/null \
| head -1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' && return 0
grep -hoE '^##[[:space:]]*\[?[0-9]+\.[0-9]+\.[0-9]+\]?' "$TARGET/CHANGELOG"* 2>/dev/null \
| head -1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+'
return $?
fi
return 1
}
VER=$(get_version_from_device || get_version_from_source)
if [[ -z "${VER:-}" ]]; then
echo "UNKNOWN: could not determine xiaozhi-esp32 version for $TARGET"
exit 2
fi
if [[ "$VER" =~ $AFFECTED_RE ]]; then
echo "VULNERABLE: xiaozhi-esp32 $VER is in affected range 2.2.0-2.2.6 (CVE-2026-13489)"
exit 1
fi
echo "PATCHED: xiaozhi-esp32 $VER is outside affected range 2.2.0-2.2.6"
exit 0
If you remember one thing.
78/xiaozhi-esp32 is not on the asset register — this CVE is not-applicable. If you do operate these devices (maker labs, R&D, voice-assistant prototypes), there is no noisgate mitigation SLA for LOW — go straight to the noisgate remediation SLA of ≤ 365 days: subscribe to PR #2021, flash the fixed release when it lands, and in the meantime segment device MCP traffic to the paired backend only. Do not waste a patch window cycle on this ahead of any KEV-listed or unauthenticated-RCE work.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.