Summary
When Agent Zero's code_execution_tool runs git commands that produce long output (e.g., git diff, git branch -a, git log), git pipes the output through the default pager (more or less). In the non-interactive terminal sessions created by code_execution_tool, the pager waits for user input (space/q) that never comes. The pager then spins at 100% CPU per process indefinitely, consuming cores until the container is restarted.
On a 16-core/32-thread system, we observed 5 stuck pager processes consuming 5 full cores for over 8 hours.
Environment
- Agent Zero version: Latest (docker image
agent0ai/agent-zero:latest)
- Host OS: Ubuntu 24.04 (kernel 6.8.0)
- Docker: 29.1.3, Compose 2.40.3
- Container OS: Kali GNU/Linux Rolling
- Git version: Latest in container image
- Default pager:
/usr/bin/pager → /etc/alternatives/pager → /usr/bin/more (from util-linux 2.42-6)
Steps to Reproduce
- Start Agent Zero with
code_execution_tool enabled
- Have the agent run any git command that produces output longer than one page, e.g.:
git diff (with large diffs)
git branch -a (with many branches)
git log (with long history)
- Observe that git spawns a pager process (
/usr/bin/pager → /usr/bin/more)
- The pager process spins at 100% CPU indefinitely because no interactive terminal input is provided
- Each subsequent git command that triggers a pager spawns another stuck process
Expected Behavior
Git commands should complete and return their output to the agent without spawning interactive pagers. The code_execution_tool terminal environment should set GIT_PAGER=cat (or PAGER=cat) so git never invokes an interactive pager.
Actual Behavior
Git spawns /usr/bin/pager (which resolves to /usr/bin/more), which waits for terminal input in a busy loop, consuming 100% CPU per process. The processes never terminate because the terminal session doesn't provide interactive input.
Evidence
Process tree inside the container
PID 260: /opt/venv-a0/bin/python /a0/run_ui.py --dockerized=true --port=80 --host=0.0.0.0
└─ PID 40541: git diff master...fix/docker-build-dependencies
└─ PID 40542: /usr/bin/pager (sleeping, 0% CPU — coordinator)
└─ PID 41719: /usr/bin/pager (99.9% CPU, started Jun07, 940 min accumulated)
PID 41718: git diff Dockerfile
└─ PID 41719: /usr/bin/pager (99.9% CPU)
PID 58032: git branch -a
└─ PID 58033: /usr/bin/pager (99.9% CPU, started 01:35, 760 min accumulated)
PID 64228: git branch -a
└─ PID 64229: /usr/bin/pager (99.8% CPU, started 01:59, 730 min accumulated)
PID 65735: git diff
└─ PID 65736: /usr/bin/pager (99.9% CPU, started 02:01, 730 min accumulated)
PID 84602: git diff Dockerfile
└─ PID 84603: /usr/bin/pager (99.9% CPU, started 03:38, 640 min accumulated)
Process details
Name: pager
State: R (running)
VmSize: 6048 kB
VmRSS: 1820-1996 kB
Threads: 1
Binary: /usr/bin/pager → /etc/alternatives/pager → /usr/bin/more
Package: util-linux 2.42-6
SHA256: 198880b1feb33f286df8746baf7b80aa6ddc24bd3b6b8b6bb43bf492ac50d333
Network: No TCP or UDP connections
Key observations
- Every
pager process is a direct child of a git command
- The binary is the legitimate
/usr/bin/more from util-linux — not malware or a replaced binary
- No network connections (rules out cryptominer C2)
- No LD_PRELOAD or suspicious environment variables
- No suspicious pip packages
- No suspicious files in
/tmp or /dev/shm
- The
more binary is 63,888 bytes, dynamically linked to libtinfo and libc
Root Cause
The code_execution_tool creates non-interactive terminal sessions (via bash -c or supervisord) that don't provide TTY input. When git produces output longer than one page, git invokes the default pager (more), which expects interactive terminal input. In the absence of TTY input:
more enters a busy loop waiting for keyboard input (space/q)
- The busy loop consumes 100% of one CPU core
- The process never terminates because no input ever arrives
- Each new git command that triggers a pager spawns another stuck process
Suggested Fix
Set GIT_PAGER=cat and PAGER=cat in the environment for all terminal sessions created by code_execution_tool. This tells git to skip the interactive pager and output directly to stdout.
Option A: Framework-level fix (recommended)
In the code that sets up terminal sessions for code_execution_tool, add these environment variables:
# In the terminal session setup code (likely in helpers/ somewhere)
env = os.environ.copy()
env["GIT_PAGER"] = "cat"
env["PAGER"] = "cat"
# Pass env to the subprocess/Popen call
Option B: Docker compose environment (quick workaround)
services:
agent-zero:
environment:
- GIT_PAGER=cat
- PAGER=cat
Option C: Container /etc/environment (survives restart, not recreation)
docker exec agent-zero bash -c 'echo "GIT_PAGER=cat" >> /etc/environment && echo "PAGER=cat" >> /etc/environment'
Why cat and not less -F?
cat is the simplest fix — it just outputs to stdout with no buffering
less -F would also work but adds a dependency on less being available
cat is always available in the container's base image
Workaround
Until the fix is merged, users can:
- Add
GIT_PAGER=cat and PAGER=cat to their docker-compose environment
- Kill stuck pager processes:
docker exec agent-zero pkill -f "pager"
- Monitor for stuck processes:
docker exec agent-zero ps aux | grep pager | grep -v grep
Impact
- CPU waste: Each stuck pager consumes 100% of one CPU core indefinitely
- Accumulation: Each git command that triggers a pager adds another stuck process
- No auto-recovery: Processes persist until the container is restarted or manually killed
- Silent failure: No error is reported to the agent or user — the git command appears to hang or time out, while the pager silently consumes CPU
Severity
Medium-High. Not a security vulnerability, but causes significant resource waste and can degrade host performance over time. On shared infrastructure, this can impact other workloads.
Related Issues
Summary
When Agent Zero's
code_execution_toolruns git commands that produce long output (e.g.,git diff,git branch -a,git log), git pipes the output through the default pager (moreorless). In the non-interactive terminal sessions created bycode_execution_tool, the pager waits for user input (space/q) that never comes. The pager then spins at 100% CPU per process indefinitely, consuming cores until the container is restarted.On a 16-core/32-thread system, we observed 5 stuck
pagerprocesses consuming 5 full cores for over 8 hours.Environment
agent0ai/agent-zero:latest)/usr/bin/pager→/etc/alternatives/pager→/usr/bin/more(fromutil-linux2.42-6)Steps to Reproduce
code_execution_toolenabledgit diff(with large diffs)git branch -a(with many branches)git log(with long history)/usr/bin/pager→/usr/bin/more)Expected Behavior
Git commands should complete and return their output to the agent without spawning interactive pagers. The
code_execution_toolterminal environment should setGIT_PAGER=cat(orPAGER=cat) so git never invokes an interactive pager.Actual Behavior
Git spawns
/usr/bin/pager(which resolves to/usr/bin/more), which waits for terminal input in a busy loop, consuming 100% CPU per process. The processes never terminate because the terminal session doesn't provide interactive input.Evidence
Process tree inside the container
Process details
Key observations
pagerprocess is a direct child of agitcommand/usr/bin/morefromutil-linux— not malware or a replaced binary/tmpor/dev/shmmorebinary is 63,888 bytes, dynamically linked to libtinfo and libcRoot Cause
The
code_execution_toolcreates non-interactive terminal sessions (viabash -corsupervisord) that don't provide TTY input. When git produces output longer than one page, git invokes the default pager (more), which expects interactive terminal input. In the absence of TTY input:moreenters a busy loop waiting for keyboard input (space/q)Suggested Fix
Set
GIT_PAGER=catandPAGER=catin the environment for all terminal sessions created bycode_execution_tool. This tells git to skip the interactive pager and output directly to stdout.Option A: Framework-level fix (recommended)
In the code that sets up terminal sessions for
code_execution_tool, add these environment variables:Option B: Docker compose environment (quick workaround)
Option C: Container
/etc/environment(survives restart, not recreation)Why
catand notless -F?catis the simplest fix — it just outputs to stdout with no bufferingless -Fwould also work but adds a dependency onlessbeing availablecatis always available in the container's base imageWorkaround
Until the fix is merged, users can:
GIT_PAGER=catandPAGER=catto their docker-compose environmentdocker exec agent-zero pkill -f "pager"docker exec agent-zero ps aux | grep pager | grep -v grepImpact
Severity
Medium-High. Not a security vulnerability, but causes significant resource waste and can degrade host performance over time. On shared infrastructure, this can impact other workloads.
Related Issues