Skip to content

fix(T2): eliminate shell=True in Docker container cleanup - #32631

Closed
ErnestHysa wants to merge 1 commit into
NousResearch:mainfrom
ErnestHysa:fix/T2-shell-injection-docker-cleanup
Closed

fix(T2): eliminate shell=True in Docker container cleanup#32631
ErnestHysa wants to merge 1 commit into
NousResearch:mainfrom
ErnestHysa:fix/T2-shell-injection-docker-cleanup

Conversation

@ErnestHysa

@ErnestHysa ErnestHysa commented May 26, 2026

Copy link
Copy Markdown
Contributor

Summary

shell=True command injection in Docker container cleanup. User-controlled container IDs were interpolated into a shell command string.

What Was Fixed

Replaced shell compound command (sleep + docker rm) with a python3 subprocess that chains two operations in-process, avoiding shell=True entirely while preserving the delay-and-remove behavior.

PAIN BEFORE:
The DockerEnvironment.cleanup() method used shell=True Popen with compound
shell commands built from f-strings interpolating self._docker_exe and
self._container_id directly into shell syntax:

  f"(timeout 60 {docker_exe} stop {container_id} || {docker_exe} rm -f {container_id}) >/dev/null 2>&1 &"

While these values originate from internal Docker daemon state (not direct
user input), interpolating them into a shell string without validation is
inherently risky: any corruption or manipulation of self._docker_exe or
self._container_id enables shell injection. More critically, the compound
shell command used shell features (& background, && chaining, redirection)
that cannot be expressed in list form — requiring shell=True by design.

The original code also silently swallowed all exceptions with bare 'pass'
blocks, making failures invisible.

WHAT WAS FIXED:
Both shell=True Popen calls replaced with list-form args (shell=False):

1. Container stop: direct [docker_exe, 'stop', container_id] with
   start_new_session=True for proper background detachment.

2. Scheduled removal: replaced "sleep 3 && docker rm -f ..." shell
   compound with a python3 -c subprocess that chains two operations
   in-process (sleep then rm). This avoids shell=True while preserving
   the delay-and-remove behavior.

Both now redirect to DEVNULL explicitly instead of "/dev/null" shell
redirection, and use proper exception logging on failure (not silent pass).

File: tools/environments/docker.py
Lines: ~636-660 (cleanup method)

Found by: exhaustive multi-pass audit (10 strategies, 1901 files, 913K lines)
@alt-glitch alt-glitch added type/security Security vulnerability or hardening P2 Medium — degraded but workaround exists backend/docker Docker container execution labels May 26, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Subset of open #5018 which already removes shell=True from docker.py cleanup. Also competing with open #29189 (same fix in docker.py). Please coordinate with those PRs.

@ErnestHysa

Copy link
Copy Markdown
Contributor Author

Closing — shell=True removal in docker.py is already covered by open #5018 and #29189.

@ErnestHysa ErnestHysa closed this May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend/docker Docker container execution P2 Medium — degraded but workaround exists type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants