Sanitize peer-supplied mDNS labels in discover CLI#911
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #911 +/- ##
==========================================
- Coverage 99.30% 99.29% -0.01%
==========================================
Files 191 191
Lines 14091 14099 +8
==========================================
+ Hits 13993 14000 +7
- Misses 98 99 +1
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
@bluetoothbot review |
There was a problem hiding this comment.
Pull request overview
This PR hardens the esphome-device-builder-discover CLI against terminal escape/control-sequence injection by sanitizing all peer-supplied mDNS labels (service instance name + TXT values) before printing them to stdout.
Changes:
- Add
_safe_labeland route all peer-supplied labels through printable-character filtering and length caps derived from_FORMATcolumn widths. - Decode TXT bytes with
utf-8usingerrors="replace"to prevent malformed payloads from raising inside the zeroconf callback. - Extend
tests/test_discover.pywith coverage for sanitization behavior (ESC/CR/LF/NUL/TAB stripping, length caps, unicode printable preservation) and format-width invariants.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
esphome_device_builder/discover.py |
Sanitizes mDNS instance/TXT labels, adds per-column caps derived from _FORMAT, and switches TXT decode to utf-8 with replacement. |
tests/test_discover.py |
Adds tests covering sanitization, decode behavior, and verifies caps match _FORMAT widths. |
…stale test docstring
PR Review — Sanitize peer-supplied mDNS labels in discover CLISolid security hardening port. The implementation routes every peer-controlled label through Checklist
SummarySolid security hardening port. The implementation routes every peer-controlled label through |
What does this implement/fix?
Ports esphome/aioesphomeapi#1689 to the dashboard's
esphome-device-builder-discoverCLI. Anything broadcasting_esphomebuilder._tcp.local.controls both the service instance name and every TXT value; the CLI was passing those bytes straight to stdout, so a hostile peer could embed ANSI escapes inserver_version/pin_sha256/ etc. and reflow the operator's terminal, or break the column-aligned table with an oversized value.Routes every peer-supplied label through
_safe_label(strip non-printables, length-cap), switches the bytes path todecode("utf-8", "replace")so a malformed payload no longer raises out of the zeroconf callback, and renames_decodeto_decode_mdns_label_or_unknown. Per-column caps are derived from_FORMATwidths via regex with a module-load assertion pinning_COLUMN_NAMESagainst the derived widths, so a future_FORMATedit cannot silently drift from the caps.Replaces and closes #897.
Related issue or feature (if applicable):
Types of changes
bugfixnew-featureenhancementbreaking-changerefactordocsmaintenancecidependenciesFrontend coordination
Checklist
ruff,codespell, yaml/json/python checks).tests/where applicable.components.jsonhas not been hand-edited (regenerate viascript/sync_components.pyif a sync is needed).docs/ARCHITECTURE.mdand/ordocs/API.md.