footprintai/containarium은 SSH 네이티브 격리, eBPF egress 정책, Kubernetes와 LXC 백엔드, GPU passthrough, MCP 네이티브 CLI를 갖춘 오픈소스 에이전트 런타임이다. 2026-11-03 커밋 4be7f81(#3455, #3468)은 이 런타임의 internal/server 로그에서 테넌트가 제공한 문자열을 %s 대신 %q로 인용하도록 바꿨다.
배경은 로그 파밍과 터미널 제어다. 사용자 이름이나 컨테이너 이름처럼 테넌트가 정할 수 있는 값이 개행 문자를 품고 있으면 로그 한 줄을 위조할 수 있었고, ESC 문자는 운영자 터미널로 그대로 전달될 수 있었다. 이번 변경은 사용자 이름, box·컨테이너 이름, tracker 연결·프로젝트 이름, 볼륨과 시크릿 키 이름, 프로세스 이름, run id와 token id를 대상으로 하며, internal/server의 log.Printf 346개와 run-checkout sweep의 주입 로거 4개를 함께 고쳤다. 설정 경로, IP, 지속 시간, peer id, enum 상태, 서버가 만든 id 같은 운영자·데몬 측 값은 그대로 뒀다.
검증도 함께 들어왔다. 503줄짜리 log_quote_test.go는 값 계열마다 핸들러 하나씩에 개행과 \x1b를 넣어 로그에 제어 바이트와 위조된 줄이 남지 않는지 확인하고, 패키지 AST를 훑어 테넌트 값 표현식이 %s나 %v에 묶인 log.Printf가 다시 들어오면 실패시킨다. 리뷰 후속 커밋은 이 검사를 log.Print·Println·Fatal·Panic과 주입된 printf 로거까지 넓혔고, 토큰 회전 줄의 jti와 family id, checkout sweep 이름을 인용했다. 사용자 삭제 실패 로그에서 이름을 'sudo userdel -r' 힌트에 붙이지 않게 한 것도 같은 계열의 정리다. Go의 %q는 셸 인용이 아니기 때문이다.
한계는 분명히 남았다. changelog fragment가 밝히듯 로그 줄 뒤에 붙는 에러 텍스트는 아직 %v로 인용되지 않아, 에러 안에 실린 값은 여전히 줄을 깨울 수 있고 별도로 추적 중이다. 기존 로그 필터가 user=alice 같은 옛 형식을 전제로 했다면 갱신이 필요하다. 값은 이제 user="alice" 형태로, sweep 줄은 [run-checkout-sweep] "<name>-container": 형태로, box에서 잡은 stderr는 stderr="line one\nline two"처럼 한 줄로 남는다. 테넌트 값으로 로그를 오염시키는 경로를 막는 방어적 수정이고 검증도 붙었지만, 에러 경로 잔여분과 필터 마이그레이션은 운영자가 감당할 몫이다.