Summary
Current main (754d5aa) converts child stdout with BufReader::new(child_stdout).lines(). AsyncBufReadExt::lines() grows its internal Vec until newline/EOF, so one malformed or hostile ACP frame can exhaust the client process before JSON-RPC parsing or the debug callback can reject it.
Reproducer
A focused test using a 64-byte intended ceiling receives Ok(String) for a 65-byte unterminated line:
let input = futures::io::Cursor::new(vec![b\x27x\x27; 65]);
let mut lines = futures::io::BufReader::new(input).lines();
assert!(lines.next().await.unwrap().is_err()); // fails: line is accepted
Proposed fix
Give AcpAgent a finite default stdout-line limit plus an explicit builder override. Read via bounded poll_fill_buf framing so retained memory never exceeds the limit; return InvalidData on overflow and let the existing child/process-group guard tear down the adapter.
I can send the tested implementation.
Summary
Current
main(754d5aa) converts child stdout withBufReader::new(child_stdout).lines().AsyncBufReadExt::lines()grows its internalVecuntil newline/EOF, so one malformed or hostile ACP frame can exhaust the client process before JSON-RPC parsing or the debug callback can reject it.Reproducer
A focused test using a 64-byte intended ceiling receives
Ok(String)for a 65-byte unterminated line:Proposed fix
Give
AcpAgenta finite default stdout-line limit plus an explicit builder override. Read via boundedpoll_fill_bufframing so retained memory never exceeds the limit; returnInvalidDataon overflow and let the existing child/process-group guard tear down the adapter.I can send the tested implementation.