From 62dbc50cc1964bdeb5d32c4f4f8c9b6b332e2f7d Mon Sep 17 00:00:00 2001 From: OpenClaw Backup Date: Sun, 17 May 2026 00:22:30 +0100 Subject: [PATCH] fix(cli): strip leaked Device Attributes (DA) terminal responses (#14692) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When prompt_toolkit's resize handler or terminal-query logic races with the input parser under resize storms or multiplexer tab switches, the terminal's Device Attributes response (ESC[?c) can land in the input buffer as literal text — visible as the '1c' fragment in terminal startup noise like '1c/2424'. The existing _strip_leaked_terminal_responses_with_meta() sanitizer (added for issue #14692) already handled Cursor Position Report (CPR) responses (ESC[;R) and SGR mouse reports (ESC[<...M/m) but was missing DA response stripping entirely. This commit adds: - _DA_ESC_RE — matches ESC[?c (primary DA), ESC[>c (secondary DA), and bare ESC[c sequences at the byte level. - _DA_VISIBLE_RE — matches the caret-escape visible form ^[[?c that appears when the ESC byte was stripped by a prior filter. - Both regexes wired into the ESC and visible branches of the sanitizer. 7 regression tests covering primary DA, secondary DA, bare DA, visible form, combined DA+CPR (the exact '1c/2424' artifact), and a negative test ensuring Cursor Forward (ESC[2C) is not confused with DA. Closes issue #14692 (completing the coverage gap). --- cli.py | 6 ++++ .../test_cli_terminal_response_sanitizer.py | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/cli.py b/cli.py index b85ee0ee91678..429d685dc6722 100644 --- a/cli.py +++ b/cli.py @@ -1848,6 +1848,10 @@ def _strip_leaked_bracketed_paste_wrappers(text: str) -> str: # these fragments are extremely unlikely to be intentional user input, and # stripping them is better than sending corrupted prompts. _SGR_MOUSE_BARE_RE = re.compile(r"<\d+;\d+;\d+[Mm]") +# Device Attributes (DA) response: terminal identity reply to ESC[c query. +# Format: ESC[?c (primary DA), ESC[>c (secondary DA), or bare ESC[c. +_DA_ESC_RE = re.compile(r"\x1b\[\??>?[\d;]*c") +_DA_VISIBLE_RE = re.compile(r"\^\[\[\??>?[\d;]*c") _TERMINAL_INPUT_MODE_RESET_SEQ = ( "\x1b[?1006l" # disable SGR mouse "\x1b[?1003l" # disable any-motion tracking @@ -1951,11 +1955,13 @@ def _strip_leaked_terminal_responses_with_meta(text: str) -> tuple[str, bool]: text = _DSR_CPR_ESC_RE.sub("", text) text, count = _SGR_MOUSE_ESC_RE.subn("", text) had_mouse_reports = had_mouse_reports or count > 0 + text = _DA_ESC_RE.sub("", text) if has_visible: text = _DSR_CPR_VISIBLE_RE.sub("", text) text, count = _SGR_MOUSE_VISIBLE_RE.subn("", text) had_mouse_reports = had_mouse_reports or count > 0 + text = _DA_VISIBLE_RE.sub("", text) if has_bare_mouse: text, count = _SGR_MOUSE_BARE_RE.subn("", text) diff --git a/tests/cli/test_cli_terminal_response_sanitizer.py b/tests/cli/test_cli_terminal_response_sanitizer.py index 1db16df90b804..55f32ddcb8a38 100644 --- a/tests/cli/test_cli_terminal_response_sanitizer.py +++ b/tests/cli/test_cli_terminal_response_sanitizer.py @@ -79,3 +79,33 @@ def test_strips_multiple_concatenated_sgr_mouse_reports(self): def test_does_not_strip_regular_angle_bracket_text(self): text = "render
literal" assert _strip_leaked_terminal_responses(text) == text + + def test_strips_da_response_primary(self): + """ESC[?1;2c — primary Device Attributes response (terminal identity)""" + text = "prefix\x1b[?1;2csuffix" + assert _strip_leaked_terminal_responses(text) == "prefixsuffix" + + def test_strips_da_response_no_params(self): + """ESC[c — bare DA response""" + text = "before\x1b[cafter" + assert _strip_leaked_terminal_responses(text) == "beforeafter" + + def test_strips_da_response_secondary(self): + """ESC[>0;0;0c — secondary DA response""" + text = "a\x1b[>0;0;0cb" + assert _strip_leaked_terminal_responses(text) == "ab" + + def test_strips_da_response_visible_form(self): + """^[[?1;2c — visible form after ESC stripped""" + text = "x^[[?1;2cy" + assert _strip_leaked_terminal_responses(text) == "xy" + + def test_strips_combined_da_and_cpr(self): + """Combined DA + CPR payload matching the reported '1c/2424' artifact""" + text = "\x1b[?1;2c\x1b[24;24R" + assert _strip_leaked_terminal_responses(text) == "" + + def test_does_not_strip_cursor_forward(self): + """ESC[2C (upper-case C) is Cursor Forward, NOT a DA response — must not be stripped""" + text = "abc\x1b[2Cdef" + assert _strip_leaked_terminal_responses(text) == "abc\x1b[2Cdef"