srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/PLAN.md
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2026-04-13 01:37:00 +0200
committersrdusr <[email protected]>2026-04-13 01:37:00 +0200
commitcecf6f0ea3d5e4706c134f708c50b00c519d536f (patch)
tree1b167aa450e598b9f78fc4e472310ea563e15eda /PLAN.md
parent7b9bf73e46102969d5802300469862296f979ef6 (diff)
downloadmitmux-cecf6f0ea3d5e4706c134f708c50b00c519d536f.tar.gz
mitmux-cecf6f0ea3d5e4706c134f708c50b00c519d536f.zip
Fix terminal-injection and table-cursor-desync bugs found by audit
Two robustness fixes from a hands-on edge-case audit of the TUI (driving the app in tmux against a daemon fed adversarial history data, not just code review). 1. Control-character/ANSI injection from captured traffic reaches the real terminal. mitmux exists specifically to MITM hostile servers, but every rendered string (table cells, detail/repeater/comparer text, decoder output) was written straight to stdout via lipgloss with no escaping. Confirmed live before the fix: a history entry whose Host contained an OSC title-change sequence changed the actual tmux pane title; a Path containing a clear-screen CSI sequence corrupted the TUI's own rendering. Fixed with sanitizeControl (cmd/mitmux/sanitize.go): replaces ASCII control bytes with "." before display, preserving \n/\t in multi-line contexts (sanitizeBlock) and stripping everything including those in single-line contexts like table cells and titles (sanitizeLine). Display-only, same pattern as the existing CRLF-normalization and JSON-pretty-printing transforms - never touches stored bytes or what Repeater/Intruder actually send. Applied at every render boundary: history table rows, detail/repeater/comparer titles and body text, Intruder's grep-extract column (text pulled directly out of an attacker-controlled response via regex), decoder output, and status messages. The one deliberate trade-off: Repeater/Intruder's editable template buffers are seeded with sanitized text too (otherwise opening a captured request with raw escape bytes would corrupt the editor's own rendering just by being viewed) - resending it unmodified sends the sanitized text; typing the original control bytes back in still sends them verbatim, since only the seed is sanitized, not live keystrokes. Verified live: re-tested the exact repro (OSC/CSI bytes in Host/Path/response body) post-fix - renders as literal "." in place of each control byte, zero corruption, zero title change. 2. Table cursor desync when a live entry arrives on an empty list. bubbles/table's own SetRows only clamps the cursor's *upper* bound (cursor > len(rows)-1) - on an empty table the cursor sits at -1, and going from 0 rows to N rows never re-clamps that lower bound, so every "row >= 0 && row < len(...)" guard (enter/r/i/f/c) silently no-ops until the next navigation keypress happens to clamp it. Confirmed live: a live-captured entry arriving while history was still empty left every action on it inert - pressing enter did nothing - until an arrow key was pressed first, with zero error or feedback. Fixed with setTableRows (calls SetRows then SetCursor(Cursor()), the latter clamping both bounds correctly), replacing every direct .SetRows() call across all three tables (history, rules, intruder results) so the same fix covers all of them, not just the one the audit happened to catch. Verified live: fresh empty-history daemon, TUI already running, captured a request via curl, pressed enter immediately with no prior navigation - opened detail view correctly. Both found via two parallel fork audits (backend and frontend) that actually drove the daemon/TUI against adversarial input rather than reading code; a third backend-focused round of fixes follows separately. go build/vet/gofmt/test/mod tidy all clean.
Diffstat (limited to 'PLAN.md')
0 files changed, 0 insertions, 0 deletions