Skip to content

Commit 2c920ab

Browse files
author
Yogthos
committed
fix: prevent DoS in sanitize_output ESC sequence handling
Found during self-review of commit 3b5ba98: - CSI consumer (ESC [ / ESC ]) now capped at 256 iterations. An unterminated sequence like '\x1b[no-alpha-here' would previously consume all remaining output. Now it stops after 256 chars, preserving the rest of the content. - DCS/APC/PM/SOS consumer (ESC P/X/^+_) now capped at 4 KB. Same issue — unterminated DCS would eat all output. - main.rs --loop validation: return the sanitized 'safe' string instead of the raw 'combined' to the transcript saver, so future reads from the transcript don't expose raw controls.
1 parent 3b5ba98 commit 2c920ab

2 files changed

Lines changed: 15 additions & 4 deletions

File tree

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1060,7 +1060,7 @@ async fn run_headless_loop(
10601060
};
10611061
let safe = ansi::strip_controls(&combined, StripPolicy::KEEP_NEWLINE);
10621062
eprintln!("{safe}");
1063-
Some(combined)
1063+
Some(safe)
10641064
}
10651065
Err(e) => {
10661066
let msg = format!("error: {}", e);

src/ui/events.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,22 +225,33 @@ pub fn sanitize_output(text: &str) -> CompactString {
225225
// Single-byte: ESC + any other char (reset, etc.)
226226
match chars.next() {
227227
Some('[') | Some(']') => {
228-
// Consume until sequence terminator (alphabetic,
229-
// tilde, or BEL for OSC).
228+
// Consume until sequence terminator. Cap at 256
229+
// bytes to prevent DoS on unterminated sequences
230+
// (tool output containing "\x1b[no-alpha-here").
231+
let mut n = 0;
230232
for next in &mut chars {
231233
if next.is_ascii_alphabetic() || next == '~' || next == '\x07' {
232234
break;
233235
}
236+
n += 1;
237+
if n >= 256 {
238+
break;
239+
}
234240
}
235241
}
236-
// DCS/APC/PM/SOS — consume until ST (ESC \).
242+
// DCS/APC/PM/SOS — consume until ST (ESC \). Cap at 4 KB.
237243
Some('P') | Some('X') | Some('^') | Some('_') => {
238244
let mut prev = '\0';
245+
let mut n = 0;
239246
for next in &mut chars {
240247
if prev == '\x1b' && next == '\\' {
241248
break;
242249
}
243250
prev = next;
251+
n += 1;
252+
if n >= 4096 {
253+
break;
254+
}
244255
}
245256
}
246257
Some(_) => {} // Single-byte esc sequence — skip the second byte.

0 commit comments

Comments
 (0)