Summary
Three container security concerns that together increase the blast radius of any in-container compromise.
Finding 1: Dockerfile runs as root
File: Dockerfile
No USER directive — the container runs everything as root, including the entrypoint and agent execution. While root-in-container is common for development/sandbox use cases, it maximizes the impact of container escapes via kernel exploits or Docker daemon vulnerabilities.
Suggested fix:
RUN groupadd --gid 1000 hermes && \
useradd --uid 1000 --gid 1000 --shell /bin/bash --create-home hermes && \
chown -R hermes:hermes /opt/hermes /opt/data
USER hermes:hermes
Finding 2: Excessive capabilities on bind-mounted directories
File: tools/environments/docker.py, _SECURITY_ARGS
The Docker environment retains DAC_OVERRIDE, CHOWN, and FOWNER capabilities after dropping ALL. DAC_OVERRIDE allows bypassing file permission checks on bind-mounted host directories (~/.hermes/sandboxes/<task_id>/). A malicious command running as container root can write to any file in mounted directories regardless of host permissions.
Suggested fix: Use --user $(id -u):$(id -g) to run containers as the host user, eliminating the need for these capabilities. If root is required inside, use --userns-remap.
Finding 3: shell=True in docker cleanup (incomplete fix for #1241)
File: tools/environments/docker.py, lines ~513-527
Two subprocess.Popen(shell=True) calls in cleanup() use f-string interpolation with self._container_id. While the container ID is Docker-daemon-generated (low injection risk), the pattern is the same root cause as the fixed #1241. Using list-form subprocess eliminates the risk entirely.
Suggested fix:
subprocess.Popen(
[self._docker_exe, "stop", self._container_id],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
start_new_session=True,
)
Risk Assessment
| Aspect |
Detail |
| Severity |
Medium (hardening) |
| Context |
These are defense-in-depth improvements, not actively exploitable vulnerabilities |
| Impact |
Reduces blast radius of container compromise |
Found during a community security review. We use Hermes Agent in production and wanted to contribute back.
Summary
Three container security concerns that together increase the blast radius of any in-container compromise.
Finding 1: Dockerfile runs as root
File:
DockerfileNo
USERdirective — the container runs everything as root, including the entrypoint and agent execution. While root-in-container is common for development/sandbox use cases, it maximizes the impact of container escapes via kernel exploits or Docker daemon vulnerabilities.Suggested fix:
Finding 2: Excessive capabilities on bind-mounted directories
File:
tools/environments/docker.py,_SECURITY_ARGSThe Docker environment retains
DAC_OVERRIDE,CHOWN, andFOWNERcapabilities after droppingALL.DAC_OVERRIDEallows bypassing file permission checks on bind-mounted host directories (~/.hermes/sandboxes/<task_id>/). A malicious command running as container root can write to any file in mounted directories regardless of host permissions.Suggested fix: Use
--user $(id -u):$(id -g)to run containers as the host user, eliminating the need for these capabilities. If root is required inside, use--userns-remap.Finding 3: shell=True in docker cleanup (incomplete fix for #1241)
File:
tools/environments/docker.py, lines ~513-527Two
subprocess.Popen(shell=True)calls incleanup()use f-string interpolation withself._container_id. While the container ID is Docker-daemon-generated (low injection risk), the pattern is the same root cause as the fixed #1241. Using list-form subprocess eliminates the risk entirely.Suggested fix:
Risk Assessment
Found during a community security review. We use Hermes Agent in production and wanted to contribute back.