← Back to Feed CACHED · 2026-06-30 00:17:25 · CACHE_KEY CVE-2026-13489
CVE-2026-13489 · CWE-662 · Disclosed 2026-06-28

A weakness has been identified in 78 xiaozhi-esp32 up to 2

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

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.

"Race condition in a hobbyist AI-companion ESP32 firmware. Authenticated, high-complexity, integrity-only — vendor's LOW rating is generous, not harsh."
02 · The Attack Path

3 steps from start to impact.

STEP 01

Obtain MCP channel access to the device

The attacker must speak the Model Context Protocol to the xiaozhi-esp32 device — that means they have valid credentials or have already compromised the LAN segment the device sits on and can MITM the WebSocket/MQTT transport. The MCP server on the ESP32 only accepts messages from a paired controller.
Conditions required:
  • PR:L — valid MCP session credentials or paired controller token
  • Network reachability to the ESP32's MCP listener (typically LAN or backend-routed)
Where this breaks in practice:
  • 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)
Detection/coverage: None at scanner level — this is consumer/maker IoT, not in Tenable/Qualys/Rapid7 plugin sets
STEP 02

Win the parser race in mcp_server.cc::ParseMessage

The attacker sends two MCP response frames timed to interleave inside 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.
Conditions required:
  • Ability to send crafted, back-to-back MCP frames
  • Knowledge of timing window (PoC reveals it)
Where this breaks in practice:
  • FreeRTOS scheduler jitter makes the race non-deterministic
  • Single device, single session — no parallelism advantage
Detection/coverage: No public detection signature; behavior is indistinguishable from a malformed-message replay
STEP 03

Corrupt a single parsed message (I:L)

Successful race yields partial integrity corruption of one MCP message — fields may be swapped, truncated, or attributed to the wrong tool call. The device may execute an MCP tool invocation with attacker-influenced arguments. There is no path to code execution, no memory corruption claimed, no DoS (A:N), no data exfiltration (C:N).
Conditions required:
  • Race won
  • Backend or device acts on the corrupted message
Where this breaks in practice:
  • MCP tool surface on these devices is small (TTS, LED, sensor read)
  • No privilege escalation past the already-authenticated session
Detection/coverage: Behavioral anomaly only — out-of-band tool calls in backend logs
03 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNone observed. No KEV listing, no campaign reporting, no honeypot hits.
Proof-of-conceptPublic PoC referenced by VulDB submission #838198; reliability poor due to AC:H.
EPSS0.00228 (~0.23%) — bottom-quartile exploitation likelihood.
CISA KEVNot listed.
CVSS vectorCVSS: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 versions78/xiaozhi-esp32 2.2.0 → 2.2.6 inclusive.
Fixed versionUnreleased. PR #2021 pending merge as of disclosure.
Exposure dataNot enumerable on Shodan/Censys/GreyNoise — ESP32 hobbyist firmware, no canonical fingerprint and not designed for internet exposure.
Disclosed2026-06-28 via VulDB coordinated submission.
ReporterAnonymous VulDB submitter (submission #838198).
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to LOW (2.5/10)

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.

HIGH verdict (LOW)
HIGH affected version range
MEDIUM installed-base in enterprise (assumed ~zero)

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.

05 · Compensating Control

What to do — in priority order.

  1. Inventory before you patch — Confirm whether your environment actually runs 78/xiaozhi-esp32 firmware 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.
  2. 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.
  3. 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).
  4. Rotate paired controller tokens — If you suspect a paired controller has been compromised, rotate the MCP pairing secret. Removes PR:L precondition immediately.
What doesn't work
  • 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.
06 · Verification

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.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/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
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning: confirm you don't own this firmware and close the ticket. For the overwhelming majority of enterprise defenders, 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

  1. VulDB entry — CVE-2026-13489
  2. VulDB technical detail #374486
  3. CIRCL Vulnerability Lookup — CVE-2026-13489
  4. GHSA-2vm4-w283-mr2p
  5. Upstream issue / pending fix (PR #2021 referenced)
  6. 78/xiaozhi-esp32 releases
  7. CWE-662: Improper Synchronization
  8. FIRST EPSS model
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.