Location: src/perplexity_agent/tui/app.py:127
_refresh_tabbar interpolates the fetched page <title> into Static.update(f"...{t.title[:22]}..."). Static defaults to markup=True, so the title is parsed as Rich console markup.
Failure scenario: /open a page titled [2026] Best GPU deals (or any title whose bracket pair the [:22] truncation splits) — Text.from_markup raises MarkupError, aborting the handler and breaking every subsequent tab-bar refresh while the tab stays open. Attacker-controlled titles can also inject tags like [blink] into the UI.
Suggested fix: escape with rich.markup.escape() (or construct the bar with markup=False / Text objects).
Found by /code-review (high effort).
Location:
src/perplexity_agent/tui/app.py:127_refresh_tabbarinterpolates the fetched page<title>intoStatic.update(f"...{t.title[:22]}...").Staticdefaults tomarkup=True, so the title is parsed as Rich console markup.Failure scenario:
/opena page titled[2026] Best GPU deals(or any title whose bracket pair the[:22]truncation splits) —Text.from_markupraises MarkupError, aborting the handler and breaking every subsequent tab-bar refresh while the tab stays open. Attacker-controlled titles can also inject tags like[blink]into the UI.Suggested fix: escape with
rich.markup.escape()(or construct the bar withmarkup=False/Textobjects).Found by /code-review (high effort).