Skip to content

[Bug] Git pager processes spin at 100% CPU indefinitely in non-interactive terminal sessions #1697

Description

@Draco-Lunaris

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

  1. Start Agent Zero with code_execution_tool enabled
  2. 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)
  3. Observe that git spawns a pager process (/usr/bin/pager/usr/bin/more)
  4. The pager process spins at 100% CPU indefinitely because no interactive terminal input is provided
  5. 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-linuxnot 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:

  1. more enters a busy loop waiting for keyboard input (space/q)
  2. The busy loop consumes 100% of one CPU core
  3. The process never terminates because no input ever arrives
  4. 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:

  1. Add GIT_PAGER=cat and PAGER=cat to their docker-compose environment
  2. Kill stuck pager processes: docker exec agent-zero pkill -f "pager"
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions