fix(automation): redact masked QLineEdit values in dumpTree (#3646)#3717
Merged
NF0T merged 1 commit intoJun 21, 2026
Merged
Conversation
…r#3646) dumpTree's widgetValue() returned QLineEdit::text() for every line edit regardless of echo mode, so password fields — the SmartLink radio password (ConnectionPanel.cpp:407) and the MQTT broker password (MqttSettingsDialog.cpp:110), both QLineEdit::Password — were serialized in cleartext, including into the temp tree.json that `automation_probe.py demo` writes. The bridge is opt-in and the socket is same-user 0600 so this isn't privilege escalation, but writing live credentials into a temp artifact is an easy footgun for an agent or CI run. Redact any non-Normal echo mode (Password / NoEcho / PasswordEchoOnEdit): return "<hidden>" for a populated masked field and null (omitted) for an empty one, so the field stays assertable (present / empty / set) without exposing the value. Reported by @aethersdr-agent in review of aethersdr#3710 (post-merge). Verified live on a FLEX-8400M: a canary secret typed into the SmartLink password field serializes as "<hidden>" and is absent from both dumpTree and the tree.json artifact; a Normal QLineEdit (email) is unaffected; an emptied masked field omits its value. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
NF0T
reviewed
Jun 21, 2026
NF0T
left a comment
Collaborator
There was a problem hiding this comment.
Human-directed independent review (Claude / @NF0T)
Minimal, correctly-targeted fix for the credential-exposure finding flagged in the bot's post-merge review of #3710.
Claims independently verified against current main:
ConnectionPanel.cpp:407—m_passwordEdit->setEchoMode(QLineEdit::Password)confirmed ✓MqttSettingsDialog.cpp:110—m_passEdit->setEchoMode(QLineEdit::Password)confirmed ✓- These are the only two non-Normal echo mode fields in
src/gui/(comprehensive grep). No other masked fields are missed. ✓ widgetValue()in current main (post-#3710 merge) returnsle->text()unconditionally — the bug is live. ✓
Fix is correct: echoMode() != QLineEdit::Normal catches all three masked modes (Password, NoEcho, PasswordEchoOnEdit). Empty field → QString() (omitted from JSON), non-empty → "<hidden>" — assertability preserved, value never exposed. Normal fields unchanged. No over-redaction, no under-redaction.
Scope: +8/−1 in widgetValue() only. No side effects.
This is a single-file Tier 3 change. LGTM — approve on exit from draft.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #3710 (merged) — addresses @aethersdr-agent's post-merge review finding.
Problem
dumpTree'swidgetValue()returnedQLineEdit::text()for every line edit, with no echo-mode check. So masked credential fields were serialized in cleartext — and the bridge writesdumpTreeinto a temptree.json(automation_probe.py demo), so the secret lands in a temp-dir artifact an agent or CI run could read.Affected
QLineEdit::Passwordfields:src/gui/ConnectionPanel.cpp:407— SmartLink radio passwordsrc/gui/MqttSettingsDialog.cpp:110— MQTT broker passwordThe bridge is opt-in (
AETHER_AUTOMATION) and the socket is same-user0600, so this isn't privilege escalation — but writing live credentials to a temp file is an easy footgun, and worth closing.Fix
One spot in
widgetValue()— redact any non-Normalecho mode (Password/NoEcho/PasswordEchoOnEdit):Slightly more than the suggested one-liner: a populated masked field serializes as
"<hidden>", an empty one omitsvalueentirely — so the field stays assertable (present / empty / set) without ever exposing the secret. Normal fields are unchanged.Verification (live, FLEX-8400M)
Typed a canary secret into the SmartLink password field via
invoke, then:"value": "<hidden>"✓dumpTreeJSON ✓tree.jsonartifact written byautomation_probe.py demo✓QLineEdit(email) still serializes its value — no over-redaction ✓valueomitted ✓💻 Generated with Claude Code (Opus 4.8) with architecture by @jensenpat