Tighten WebCRT command audit: reject device errors and stdout replay.

Only audit interactive commands from frontend audit_line with a CLI prompt prefix; skip prompt-sync Enter and device error echoes; join wrapped xterm rows for long commands.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-02 14:47:12 +08:00
parent 52424dce37
commit 302ebfac23
5 changed files with 163 additions and 27 deletions

View file

@ -385,28 +385,26 @@ class WebcrtSession:
if redacted and (buf_lines or audit_line):
self._password_mode = False
if "\r" in text or "\n" in text:
from .webcrt_channel import (
extract_last_prompt_command,
is_auditable_command_line,
normalize_audit_line,
)
from .webcrt_channel import is_auditable_command_line, normalize_audit_line
# Ground truth: xterm visible row at Enter (frontend). PTY stdout/stdin
# still carry intermediate backspaces / tab redraws — do not prefer those.
src = str(source or "stdin")
cmd: str | None = None
if audit_line and str(audit_line).strip():
if redacted and (audit_line or buf_lines):
lines = ["***"]
elif src == "prompt_sync":
lines = []
elif audit_line and str(audit_line).strip():
candidate = normalize_audit_line(audit_line)
if is_auditable_command_line(candidate):
cmd = candidate
if not cmd:
raw = extract_last_prompt_command(self._stdout_tail)
if raw and is_auditable_command_line(raw):
cmd = raw
elif buf_lines and str(buf_lines[-1]).strip():
last = str(buf_lines[-1]).strip()
if is_auditable_command_line(last):
cmd = last
lines = [cmd] if cmd else []
lines = [cmd] if cmd else []
elif src == "post_login":
if buf_lines and str(buf_lines[-1]).strip():
cmd = str(buf_lines[-1]).strip()
lines = [cmd] if cmd else []
else:
# Interactive WebCRT: only trust frontend audit_line at Enter.
lines = []
self._last_prompt_line = ""
else:
lines = []