Skip to content

feat(docker): add opt-in sandbox support for Docker deployments#29974

Merged
vincentkoc merged 16 commits intoopenclaw:mainfrom
jamtujest:feat/docker-sandbox-support
Mar 2, 2026
Merged

feat(docker): add opt-in sandbox support for Docker deployments#29974
vincentkoc merged 16 commits intoopenclaw:mainfrom
jamtujest:feat/docker-sandbox-support

Conversation

@jamtujest
Copy link
Contributor

Summary

  • Add opt-in Docker sandbox support to enable agents.defaults.sandbox in Docker deployments
  • Targets all Docker-based hosting: self-hosted, Hostinger 1-Click, DigitalOcean 1-Click
  • All changes are backwards-compatible — zero impact on existing deployments

Problem

The current Docker setup (Dockerfile, docker-compose.yml, docker-setup.sh) does not include Docker socket access or Docker CLI. This makes OpenClaw's sandbox feature completely non-functional in any Docker deployment. Without sandbox, agent code execution shares the gateway container's filesystem, network, and credentials — a significant security gap when agents process untrusted input (Telegram, WhatsApp, web).

See #29933 for detailed security analysis and list of ~20 related issues this unblocks.

Changes

Dockerfile

  • New build arg OPENCLAW_INSTALL_DOCKER_CLI (same pattern as existing OPENCLAW_INSTALL_BROWSER)
  • Installs only Docker CLI + compose plugin (~50MB), no daemon
  • Opt-in: default builds are unchanged

docker-compose.yml

  • Added commented-out docker.sock volume mount with documentation
  • Added commented-out group_add with DOCKER_GID variable reference
  • No behavior change unless user uncomments

docker-setup.sh

  • New OPENCLAW_SANDBOX environment variable to enable sandbox setup
  • Auto-detects Docker socket and its GID
  • Auto-adds socket mount to OPENCLAW_EXTRA_MOUNTS
  • Auto-sets OPENCLAW_INSTALL_DOCKER_CLI=1 for local builds
  • Adds group_add with detected GID in write_extra_compose()
  • Builds openclaw-sandbox:bookworm-slim from existing Dockerfile.sandbox
  • Configures agents.defaults.sandbox (mode=non-main, scope=agent, workspaceAccess=none)
  • Restarts gateway to apply sandbox config

Usage

# With sandbox (new):
OPENCLAW_SANDBOX=1 ./docker-setup.sh

# Without sandbox (unchanged default):
./docker-setup.sh

For hosting providers (Hostinger, DigitalOcean)

Minimum change on their side to enable sandbox in their templates:

volumes:
  - /var/run/docker.sock:/var/run/docker.sock  # +1 line
group_add:
  - "999"  # Docker socket GID

Plus building with --build-arg OPENCLAW_INSTALL_DOCKER_CLI=1.

Test plan

  • ./docker-setup.sh without OPENCLAW_SANDBOX works exactly as before
  • OPENCLAW_SANDBOX=1 ./docker-setup.sh auto-detects socket, builds sandbox image, enables config
  • Gateway starts with sandbox enabled, creates ephemeral containers for agent exec
  • docker build --build-arg OPENCLAW_INSTALL_DOCKER_CLI=1 installs Docker CLI
  • docker build without the arg does not install Docker CLI
  • group_add in extra compose uses correct GID from host

Related issues

Closes #29933

Partially addresses / unblocks:

🤖 Generated with Claude Code

@openclaw-barnacle openclaw-barnacle bot added docker Docker and sandbox tooling size: S labels Feb 28, 2026
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 64256e8ebe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 28, 2026

Greptile Summary

This PR adds comprehensive opt-in Docker sandbox support with strong backward compatibility guarantees. The implementation spans three files with a well-designed architecture that defers security-sensitive operations (Docker socket mounting) until all prerequisites are validated.

Key implementation details:

  • Dockerfile: Adds conditional Docker CLI installation (~50MB) via OPENCLAW_INSTALL_DOCKER_CLI build arg, following the existing pattern used for browser installation
  • docker-compose.yml: Provides clear documentation for manual sandbox enablement with commented-out socket mount and group_add configuration
  • docker-setup.sh: Implements automated sandbox setup that detects Docker socket GID, verifies Docker CLI availability, builds sandbox image, configures OpenClaw settings, and handles all prerequisite checks before exposing Docker socket

Error handling and safety:

  • Script uses set -euo pipefail to exit on unexpected errors while gracefully handling expected failures
  • All previously reported issues (silent Dockerfile.sandbox skip, swallowed config errors) have been addressed with explicit warnings
  • Cross-platform stat command support (Linux -c and BSD -f flags) with safe fallback
  • Socket mount is only added after successful prerequisite validation, preventing security exposure when sandbox cannot function

Backward compatibility:

  • Changes are completely opt-in via OPENCLAW_SANDBOX=1 environment variable
  • Default behavior unchanged - existing deployments unaffected
  • No breaking changes to configuration or APIs

Confidence Score: 5/5

  • This PR is safe to merge with high confidence - thoroughly tested through iterative fixes, zero impact on existing deployments
  • Score reflects excellent code quality with proper error handling (set -euo pipefail), comprehensive prerequisite validation, security-conscious design (deferred socket mounting), and resolution of all previously identified issues. The opt-in nature ensures zero risk to existing deployments while enabling critical security sandbox functionality for Docker users
  • No files require special attention - all three files have been reviewed and demonstrate solid implementation with appropriate error handling and documentation

Last reviewed commit: bded88a

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 28, 2026

Additional Comments (1)

docker-setup.sh
OPENCLAW_SANDBOX and DOCKER_GID not persisted — group_add lost on re-runs

OPENCLAW_EXTRA_MOUNTS is saved to .env (line 365), so the Docker socket bind-mount correctly survives re-runs. However, OPENCLAW_SANDBOX, DOCKER_GID, and OPENCLAW_INSTALL_DOCKER_CLI are not saved.

Because write_extra_compose only injects group_add when SANDBOX_ENABLED and DOCKER_GID are non-empty (line 233), any subsequent run of ./docker-setup.sh without OPENCLAW_SANDBOX=1 will regenerate docker-compose.extra.yml without the group_add stanza. The container will still have /var/run/docker.sock mounted (from OPENCLAW_EXTRA_MOUNTS), but the node user won't have the Docker group membership needed to access it — silently breaking sandbox.

Fix: add OPENCLAW_SANDBOX, DOCKER_GID, and OPENCLAW_INSTALL_DOCKER_CLI to the upsert_env call, or re-derive DOCKER_GID whenever the socket mount is already present in OPENCLAW_EXTRA_MOUNTS regardless of SANDBOX_ENABLED.

upsert_env "$ENV_FILE" \
  OPENCLAW_CONFIG_DIR \
  OPENCLAW_WORKSPACE_DIR \
  OPENCLAW_GATEWAY_PORT \
  OPENCLAW_BRIDGE_PORT \
  OPENCLAW_GATEWAY_BIND \
  OPENCLAW_GATEWAY_TOKEN \
  OPENCLAW_IMAGE \
  OPENCLAW_EXTRA_MOUNTS \
  OPENCLAW_HOME_VOLUME \
  OPENCLAW_DOCKER_APT_PACKAGES \
  OPENCLAW_SANDBOX \
  DOCKER_GID \
  OPENCLAW_INSTALL_DOCKER_CLI
Prompt To Fix With AI
This is a comment left during a code review.
Path: docker-setup.sh
Line: 357-367

Comment:
**`OPENCLAW_SANDBOX` and `DOCKER_GID` not persisted — `group_add` lost on re-runs**

`OPENCLAW_EXTRA_MOUNTS` is saved to `.env` (line 365), so the Docker socket bind-mount correctly survives re-runs. However, `OPENCLAW_SANDBOX`, `DOCKER_GID`, and `OPENCLAW_INSTALL_DOCKER_CLI` are **not** saved.

Because `write_extra_compose` only injects `group_add` when `SANDBOX_ENABLED` and `DOCKER_GID` are non-empty (line 233), any subsequent run of `./docker-setup.sh` without `OPENCLAW_SANDBOX=1` will regenerate `docker-compose.extra.yml` *without* the `group_add` stanza. The container will still have `/var/run/docker.sock` mounted (from `OPENCLAW_EXTRA_MOUNTS`), but the `node` user won't have the Docker group membership needed to access it — silently breaking sandbox.

Fix: add `OPENCLAW_SANDBOX`, `DOCKER_GID`, and `OPENCLAW_INSTALL_DOCKER_CLI` to the `upsert_env` call, or re-derive `DOCKER_GID` whenever the socket mount is already present in `OPENCLAW_EXTRA_MOUNTS` regardless of `SANDBOX_ENABLED`.

```suggestion
upsert_env "$ENV_FILE" \
  OPENCLAW_CONFIG_DIR \
  OPENCLAW_WORKSPACE_DIR \
  OPENCLAW_GATEWAY_PORT \
  OPENCLAW_BRIDGE_PORT \
  OPENCLAW_GATEWAY_BIND \
  OPENCLAW_GATEWAY_TOKEN \
  OPENCLAW_IMAGE \
  OPENCLAW_EXTRA_MOUNTS \
  OPENCLAW_HOME_VOLUME \
  OPENCLAW_DOCKER_APT_PACKAGES \
  OPENCLAW_SANDBOX \
  DOCKER_GID \
  OPENCLAW_INSTALL_DOCKER_CLI
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6caec4c9a6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 406c8711b2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@thewilloftheshadow
Copy link
Member

This already exists

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bded88ad53

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@jamtujest
Copy link
Contributor Author

@thewilloftheshadow Could you clarify what you mean by "this already exists"?

I'm aware that scripts/sandbox-setup.sh, Dockerfile.sandbox, and the agents.defaults.sandbox config exist. That's the host-based sandbox setup — where the gateway runs directly on the host and has native access to the Docker CLI and daemon.

This PR addressed a different scenario: Docker-in-Docker — when the gateway itself runs inside a Docker container (e.g. via docker-setup.sh / docker-compose.yml). In that case:

  • There is no Docker CLI inside the gateway container
  • There is no /var/run/docker.sock mounted
  • scripts/sandbox-setup.sh cannot work because docker build is not available inside the container
  • The existing sandbox config has no effect — commands run unsandboxed in the gateway container

The PR added:

  1. OPENCLAW_INSTALL_DOCKER_CLI build arg to bake Docker CLI into the gateway image
  2. Opt-in docker.sock mount via docker-setup.sh (OPENCLAW_SANDBOX=1)
  3. Automatic sandbox config after verifying prerequisites

None of this exists today in the Docker deployment path. Did you read the PR description? It specifically explains the Docker-in-Docker gap. See also issue #29933 for the real-world context (Hostinger VPS template).

@thewilloftheshadow
Copy link
Member

Ahh this went on the wrong docker pr!

@jamtujest
Copy link
Contributor Author

@thewilloftheshadow No worries! Could you take a look when you get a chance?

Greptile gave it 5/5 confidence, all previous review issues have been fixed (4 commits total). The only failing CI check is the check job which fails on a pre-existing TypeScript error in src/gateway/server-cron.ts:197 on main — unrelated to this PR (we only touch Dockerfile, docker-compose.yml, docker-setup.sh).

Would appreciate a review/approval if it looks good to you. Thanks!

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 06a8e8289a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@jamtujest
Copy link
Contributor Author

@vincentkoc @steipete Would appreciate a review on this one when you have a moment.

This enables sandbox isolation for Docker-based deployments (docker-setup.sh / docker-compose.yml) — currently the gateway container has no Docker CLI and no socket access, so agents.defaults.sandbox has no effect. All agent commands run unsandboxed inside the gateway container with full access to credentials.

Changes are fully opt-in (OPENCLAW_SANDBOX=1) and backward-compatible. Greptile scored 5/5 confidence.

Closes #29933.

@vincentkoc vincentkoc self-assigned this Mar 2, 2026
@vincentkoc vincentkoc force-pushed the feat/docker-sandbox-support branch from 06a8e82 to dbe3ef8 Compare March 2, 2026 05:45
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dbe3ef8240

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Jakub Karwowski and others added 7 commits March 1, 2026 22:25
Enable Docker-based sandbox isolation via OPENCLAW_SANDBOX=1 env var
in docker-setup.sh. This is a prerequisite for agents.defaults.sandbox
to function in any Docker deployment (self-hosted, Hostinger, DigitalOcean).

Changes:
- Dockerfile: add OPENCLAW_INSTALL_DOCKER_CLI build arg (~50MB, opt-in)
- docker-compose.yml: add commented-out docker.sock mount with docs
- docker-setup.sh: auto-detect Docker socket, inject mount, detect GID,
  build sandbox image, configure sandbox defaults, add group_add

All changes are opt-in. Zero impact on existing deployments.

Usage: OPENCLAW_SANDBOX=1 ./docker-setup.sh

Closes openclaw#29933
Related: openclaw#7575, openclaw#7827, openclaw#28401, openclaw#10361, openclaw#12505, openclaw#28326

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Persist OPENCLAW_SANDBOX, DOCKER_GID, OPENCLAW_INSTALL_DOCKER_CLI
  to .env via upsert_env so group_add survives re-runs
- Show config set errors instead of swallowing them silently;
  report partial failure when sandbox config is incomplete
- Warn when Dockerfile.sandbox is missing but sandbox config
  is still applied (sandbox image won't exist)
- Fix non-canonical whitespace in apt sources.list entry
  by using printf instead of echo with line continuation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…CLI check

- Remove `local` keyword from top-level `sandbox_config_ok` assignment
  which caused script exit under `set -euo pipefail` (bash `local`
  outside a function is an error)
- Add Docker CLI prerequisite check for pre-built (non-local) images:
  runs `docker --version` inside the container and skips sandbox setup
  with a clear warning if the CLI is missing
- Split sandbox block so config is only applied after prerequisites pass

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move Docker socket mounting from the early setup phase (before image
build/pull) to a dedicated compose overlay created only after:
1. Docker CLI is verified inside the container image
2. /var/run/docker.sock exists on the host

Previously the socket was mounted optimistically at startup, leaving
the host Docker daemon exposed even when sandbox setup was later
skipped due to missing Docker CLI. Now the gateway starts without
the socket, and a docker-compose.sandbox.yml overlay is generated
only when all prerequisites pass. The gateway restart at the end of
sandbox setup picks up both the socket mount and sandbox config.

Also moves group_add from write_extra_compose() into the sandbox
overlay, keeping all sandbox-specific compose configuration together.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vincentkoc vincentkoc force-pushed the feat/docker-sandbox-support branch from dbe3ef8 to 085cee5 Compare March 2, 2026 06:25
@vincentkoc
Copy link
Member

Addressed the remaining sandbox hardening/review concerns and pushed updates.

What changed:

  • docker-setup.sh

    • Parse OPENCLAW_SANDBOX as explicit truthy (1|true|yes|on) to avoid accidental enablement from 0.
    • Support/persist OPENCLAW_DOCKER_SOCKET and derive fallback from DOCKER_HOST (unix://...) or /var/run/docker.sock.
    • Verify Docker CLI availability in the container image before applying sandbox config.
    • Keep docker.sock mount deferred until prerequisites pass.
    • If sandbox config writes fail, skip the sandbox restart and remove sandbox overlay to avoid partial high-privilege state.
    • When sandbox is not active for the run (opt-out or failed prerequisites), reset agents.defaults.sandbox.mode to off and clean stale docker-compose.sandbox.yml.
  • src/docker-setup.e2e.test.ts

    • Added/extended coverage for:
      • OPENCLAW_SANDBOX=0 treated as disabled.
      • sandbox config write failure does not trigger second gateway restart and removes overlay.
      • stale sandbox overlay + non-usable sandbox path gets cleaned and mode reset to off.

Validation run:

  • pnpm exec vitest run --config vitest.e2e.config.ts src/docker-setup.e2e.test.ts
  • pnpm check

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 085cee56ff

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@vincentkoc
Copy link
Member

Addressed both of these review concerns in latest commits:

  • Missing Dockerfile.sandbox warning path: already implemented with explicit warnings before sandbox config apply.
  • Persisted sandbox mode on non-opt-in reruns: now explicitly reset to agents.defaults.sandbox.mode=off when sandbox is not active for the current run.

Additional hardening shipped now:

  • If sandbox config writes are partial (e.g. mode succeeds, scope fails), script now rolls sandbox mode back to off and skips sandbox restart.

Validation:

  • pnpm exec vitest run --config vitest.e2e.config.ts src/docker-setup.e2e.test.ts
  • pnpm check

@openclaw-barnacle openclaw-barnacle bot added the docs Improvements or additions to documentation label Mar 2, 2026
@vincentkoc
Copy link
Member

@aisle-research-bot review

@aisle-research-bot
Copy link

aisle-research-bot bot commented Mar 2, 2026

🔒 Aisle Security Analysis

We found 2 potential security issue(s) in this PR:

# Severity Title
1 🟡 Medium Unverified Docker APT GPG key download during image build (trust-on-first-use)
2 🟡 Medium docker.sock may be mounted despite failed sandbox policy due to docker compose run starting/recreating gateway with sandbox overlay

1. 🟡 Unverified Docker APT GPG key download during image build (trust-on-first-use)

Property Value
Severity Medium
CWE CWE-494
Location Dockerfile:64-74

Description

The Dockerfile optionally installs Docker CLI by downloading a repository signing key at build time and trusting it without verifying an expected fingerprint.

  • The build fetches https://download.docker.com/.../gpg and immediately imports it into /etc/apt/keyrings/docker.gpg.
  • There is no pinned fingerprint / checksum validation of the key material before it becomes a trust root for subsequent apt-get install docker-ce-cli docker-compose-plugin.
  • If the network path (DNS/TLS), the upstream host, or a mirror is compromised at build time, an attacker could provide a different key and then serve attacker-signed packages from a repo, leading to supply-chain compromise of the produced image.

Vulnerable code:

curl -fsSL https://download.docker.com/linux/debian/gpg | \
  gpg --dearmor -o /etc/apt/keyrings/docker.gpg

Note: using signed-by=/etc/apt/keyrings/docker.gpg is good practice (limits the key scope), but the initial key acquisition still lacks authenticity verification.

Recommendation

Verify the Docker APT key by fingerprint (allowlist) before trusting it, and fail the build if it does not match.

Example (illustrative):

RUN if [ -n "$OPENCLAW_INSTALL_DOCKER_CLI" ]; then \
  apt-get update && apt-get install -y --no-install-recommends ca-certificates curl gnupg && \
  install -m 0755 -d /etc/apt/keyrings && \
  curl -fsSL https://download.docker.com/linux/debian/gpg -o /tmp/docker.gpg && \
  gpg --no-default-keyring --keyring /tmp/docker.gpg --list-keys --with-fingerprint && \
  gpg --dearmor -o /etc/apt/keyrings/docker.gpg /tmp/docker.gpg && \
  rm -f /tmp/docker.gpg && \
  ...; \
fi

Additionally (hardening / reproducibility):

  • Consider pinning docker-ce-cli / docker-compose-plugin versions (or using snapshot/apt pinning) to make builds deterministic.
  • Consider documenting key rotation procedures (update allowlisted fingerprints when Docker rotates keys).

2. 🟡 docker.sock may be mounted despite failed sandbox policy due to docker compose run starting/recreating gateway with sandbox overlay

Property Value
Severity Medium
CWE CWE-269
Location docker-setup.sh:478-521

Description

In docker-setup.sh, the sandbox flow tries to avoid exposing the host Docker socket unless sandbox prerequisites and policy configuration succeed. However, the script adds the sandbox compose overlay (which mounts docker.sock) to COMPOSE_ARGS before running a series of docker compose run openclaw-cli config set ... commands.

Because openclaw-cli is defined with depends_on: openclaw-gateway and network_mode: "service:openclaw-gateway", docker compose run may start (or potentially recreate) the openclaw-gateway service to satisfy dependencies using the current project configuration — which now includes the sandbox overlay with the Docker socket mount.

Impact if any sandbox config step fails (or the gateway container is not running/crashes between steps):

  • openclaw-gateway can end up running with /var/run/docker.sock mounted even though sandbox policy was only partially applied or rolled back.
  • The rollback path deletes docker-compose.sandbox.yml, but does not force-recreate/restart the gateway without the mount, so an already-started gateway container can keep the socket mount.

This is effectively an unintended privilege escalation surface: any compromise of the gateway container while it has docker.sock mounted typically permits host root-equivalent control via the Docker API.

Recommendation

Prevent docker compose run from implicitly starting/recreating openclaw-gateway with the sandbox overlay until after policy config has succeeded.

Recommended changes:

  1. Run config commands with --no-deps so Compose does not start/recreate openclaw-gateway using the overlay:
docker compose "${COMPOSE_ARGS[@]}" run --rm --no-deps openclaw-cli \
  config set agents.defaults.sandbox.mode "non-main" >/dev/null
  1. In the partial-failure rollback path, explicitly ensure the gateway is running without the sandbox overlay (and therefore without the docker.sock mount). For example, keep a separate BASE_COMPOSE_ARGS (without the sandbox -f) and do:
# After failure/rollback:
docker compose "${BASE_COMPOSE_ARGS[@]}" up -d --force-recreate openclaw-gateway
  1. Optionally add a trap to remove docker-compose.sandbox.yml on unexpected exits so the filesystem state is always cleaned up.

Analyzed PR: #29974 at commit b26fcf0

Last updated on: 2026-03-02T06:58:07Z

@vincentkoc
Copy link
Member

Addressed the Aisle security findings in the latest commits:

  1. Docker apt key trust-on-first-use (CWE-494)
  • Added fingerprint verification for the Docker apt signing key before dearmor/trust in Dockerfile.
  • New build arg: OPENCLAW_DOCKER_GPG_FINGERPRINT (default pinned to current Docker Debian release key fingerprint).
  • Build now fails closed on mismatch.
  1. Possible docker.sock exposure on sandbox policy failure path (CWE-269)
  • Sandbox policy writes now run with docker compose run --no-deps to avoid dependency-triggered gateway starts/recreates while overlay args are active.
  • Added BASE_COMPOSE_ARGS (without sandbox overlay) and use it for rollback mode reset.
  • On partial sandbox config failure, force-recreate gateway with base compose args to ensure service comes back without docker.sock overlay mount.

Validation:

  • pnpm exec vitest run --config vitest.e2e.config.ts src/docker-setup.e2e.test.ts
  • pnpm check

Commits:

  • be1054f Docker: verify Docker apt signing key fingerprint
  • 5dd7f7f Docker: avoid sandbox overlay deps during policy writes
  • 9876f26 Tests: assert no-deps sandbox rollback gateway recreate

@vincentkoc vincentkoc merged commit cb491df into openclaw:main Mar 2, 2026
10 checks passed
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ab19e40e5a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +552 to +553
if ! docker compose "${COMPOSE_ARGS[@]}" run --rm openclaw-cli \
config set agents.defaults.sandbox.mode "off" >/dev/null; then

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restart gateway after resetting sandbox mode to off

In the non-sandbox path, this config set agents.defaults.sandbox.mode off runs after the gateway has already been started, so it does not fix the live process state for this run. Fresh evidence: src/gateway/config-reload.ts marks the agents prefix as kind: "none", so changing agents.defaults.sandbox.* is not hot-reloaded; if the previous config was non-main, the running gateway keeps sandbox mode without the docker.sock mount and agent exec remains broken until a restart.

Useful? React with 👍 / 👎.

hanqizheng pushed a commit to hanqizheng/openclaw that referenced this pull request Mar 2, 2026
…claw#29974)

* feat(docker): add opt-in sandbox support for Docker deployments

Enable Docker-based sandbox isolation via OPENCLAW_SANDBOX=1 env var
in docker-setup.sh. This is a prerequisite for agents.defaults.sandbox
to function in any Docker deployment (self-hosted, Hostinger, DigitalOcean).

Changes:
- Dockerfile: add OPENCLAW_INSTALL_DOCKER_CLI build arg (~50MB, opt-in)
- docker-compose.yml: add commented-out docker.sock mount with docs
- docker-setup.sh: auto-detect Docker socket, inject mount, detect GID,
  build sandbox image, configure sandbox defaults, add group_add

All changes are opt-in. Zero impact on existing deployments.

Usage: OPENCLAW_SANDBOX=1 ./docker-setup.sh

Closes openclaw#29933
Related: openclaw#7575, openclaw#7827, openclaw#28401, openclaw#10361, openclaw#12505, openclaw#28326

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address code review feedback on sandbox support

- Persist OPENCLAW_SANDBOX, DOCKER_GID, OPENCLAW_INSTALL_DOCKER_CLI
  to .env via upsert_env so group_add survives re-runs
- Show config set errors instead of swallowing them silently;
  report partial failure when sandbox config is incomplete
- Warn when Dockerfile.sandbox is missing but sandbox config
  is still applied (sandbox image won't exist)
- Fix non-canonical whitespace in apt sources.list entry
  by using printf instead of echo with line continuation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove `local` outside function and guard sandbox behind Docker CLI check

- Remove `local` keyword from top-level `sandbox_config_ok` assignment
  which caused script exit under `set -euo pipefail` (bash `local`
  outside a function is an error)
- Add Docker CLI prerequisite check for pre-built (non-local) images:
  runs `docker --version` inside the container and skips sandbox setup
  with a clear warning if the CLI is missing
- Split sandbox block so config is only applied after prerequisites pass

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: defer docker.sock mount until sandbox prerequisites pass

Move Docker socket mounting from the early setup phase (before image
build/pull) to a dedicated compose overlay created only after:
1. Docker CLI is verified inside the container image
2. /var/run/docker.sock exists on the host

Previously the socket was mounted optimistically at startup, leaving
the host Docker daemon exposed even when sandbox setup was later
skipped due to missing Docker CLI. Now the gateway starts without
the socket, and a docker-compose.sandbox.yml overlay is generated
only when all prerequisites pass. The gateway restart at the end of
sandbox setup picks up both the socket mount and sandbox config.

Also moves group_add from write_extra_compose() into the sandbox
overlay, keeping all sandbox-specific compose configuration together.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs(docker): fix sandbox docs URL in setup output

* Docker: harden sandbox setup fallback behavior

* Tests: cover docker-setup sandbox edge paths

* Docker: roll back sandbox mode on partial config failure

* Tests: assert sandbox mode rollback on partial setup

* Docs: document Docker sandbox bootstrap env controls

* Changelog: credit Docker sandbox bootstrap hardening

* Update CHANGELOG.md

* Docker: verify Docker apt signing key fingerprint

* Docker: avoid sandbox overlay deps during policy writes

* Tests: assert no-deps sandbox rollback gateway recreate

* Docs: mention OPENCLAW_INSTALL_DOCKER_CLI in Docker env vars

---------

Co-authored-by: Jakub Karwowski <jakubkarwowski@Mac.lan>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
execute008 pushed a commit to execute008/openclaw that referenced this pull request Mar 2, 2026
…claw#29974)

* feat(docker): add opt-in sandbox support for Docker deployments

Enable Docker-based sandbox isolation via OPENCLAW_SANDBOX=1 env var
in docker-setup.sh. This is a prerequisite for agents.defaults.sandbox
to function in any Docker deployment (self-hosted, Hostinger, DigitalOcean).

Changes:
- Dockerfile: add OPENCLAW_INSTALL_DOCKER_CLI build arg (~50MB, opt-in)
- docker-compose.yml: add commented-out docker.sock mount with docs
- docker-setup.sh: auto-detect Docker socket, inject mount, detect GID,
  build sandbox image, configure sandbox defaults, add group_add

All changes are opt-in. Zero impact on existing deployments.

Usage: OPENCLAW_SANDBOX=1 ./docker-setup.sh

Closes openclaw#29933
Related: openclaw#7575, openclaw#7827, openclaw#28401, openclaw#10361, openclaw#12505, openclaw#28326

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address code review feedback on sandbox support

- Persist OPENCLAW_SANDBOX, DOCKER_GID, OPENCLAW_INSTALL_DOCKER_CLI
  to .env via upsert_env so group_add survives re-runs
- Show config set errors instead of swallowing them silently;
  report partial failure when sandbox config is incomplete
- Warn when Dockerfile.sandbox is missing but sandbox config
  is still applied (sandbox image won't exist)
- Fix non-canonical whitespace in apt sources.list entry
  by using printf instead of echo with line continuation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove `local` outside function and guard sandbox behind Docker CLI check

- Remove `local` keyword from top-level `sandbox_config_ok` assignment
  which caused script exit under `set -euo pipefail` (bash `local`
  outside a function is an error)
- Add Docker CLI prerequisite check for pre-built (non-local) images:
  runs `docker --version` inside the container and skips sandbox setup
  with a clear warning if the CLI is missing
- Split sandbox block so config is only applied after prerequisites pass

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: defer docker.sock mount until sandbox prerequisites pass

Move Docker socket mounting from the early setup phase (before image
build/pull) to a dedicated compose overlay created only after:
1. Docker CLI is verified inside the container image
2. /var/run/docker.sock exists on the host

Previously the socket was mounted optimistically at startup, leaving
the host Docker daemon exposed even when sandbox setup was later
skipped due to missing Docker CLI. Now the gateway starts without
the socket, and a docker-compose.sandbox.yml overlay is generated
only when all prerequisites pass. The gateway restart at the end of
sandbox setup picks up both the socket mount and sandbox config.

Also moves group_add from write_extra_compose() into the sandbox
overlay, keeping all sandbox-specific compose configuration together.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs(docker): fix sandbox docs URL in setup output

* Docker: harden sandbox setup fallback behavior

* Tests: cover docker-setup sandbox edge paths

* Docker: roll back sandbox mode on partial config failure

* Tests: assert sandbox mode rollback on partial setup

* Docs: document Docker sandbox bootstrap env controls

* Changelog: credit Docker sandbox bootstrap hardening

* Update CHANGELOG.md

* Docker: verify Docker apt signing key fingerprint

* Docker: avoid sandbox overlay deps during policy writes

* Tests: assert no-deps sandbox rollback gateway recreate

* Docs: mention OPENCLAW_INSTALL_DOCKER_CLI in Docker env vars

---------

Co-authored-by: Jakub Karwowski <jakubkarwowski@Mac.lan>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
dawi369 pushed a commit to dawi369/davis that referenced this pull request Mar 3, 2026
…claw#29974)

* feat(docker): add opt-in sandbox support for Docker deployments

Enable Docker-based sandbox isolation via OPENCLAW_SANDBOX=1 env var
in docker-setup.sh. This is a prerequisite for agents.defaults.sandbox
to function in any Docker deployment (self-hosted, Hostinger, DigitalOcean).

Changes:
- Dockerfile: add OPENCLAW_INSTALL_DOCKER_CLI build arg (~50MB, opt-in)
- docker-compose.yml: add commented-out docker.sock mount with docs
- docker-setup.sh: auto-detect Docker socket, inject mount, detect GID,
  build sandbox image, configure sandbox defaults, add group_add

All changes are opt-in. Zero impact on existing deployments.

Usage: OPENCLAW_SANDBOX=1 ./docker-setup.sh

Closes openclaw#29933
Related: openclaw#7575, openclaw#7827, openclaw#28401, openclaw#10361, openclaw#12505, openclaw#28326

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address code review feedback on sandbox support

- Persist OPENCLAW_SANDBOX, DOCKER_GID, OPENCLAW_INSTALL_DOCKER_CLI
  to .env via upsert_env so group_add survives re-runs
- Show config set errors instead of swallowing them silently;
  report partial failure when sandbox config is incomplete
- Warn when Dockerfile.sandbox is missing but sandbox config
  is still applied (sandbox image won't exist)
- Fix non-canonical whitespace in apt sources.list entry
  by using printf instead of echo with line continuation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove `local` outside function and guard sandbox behind Docker CLI check

- Remove `local` keyword from top-level `sandbox_config_ok` assignment
  which caused script exit under `set -euo pipefail` (bash `local`
  outside a function is an error)
- Add Docker CLI prerequisite check for pre-built (non-local) images:
  runs `docker --version` inside the container and skips sandbox setup
  with a clear warning if the CLI is missing
- Split sandbox block so config is only applied after prerequisites pass

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: defer docker.sock mount until sandbox prerequisites pass

Move Docker socket mounting from the early setup phase (before image
build/pull) to a dedicated compose overlay created only after:
1. Docker CLI is verified inside the container image
2. /var/run/docker.sock exists on the host

Previously the socket was mounted optimistically at startup, leaving
the host Docker daemon exposed even when sandbox setup was later
skipped due to missing Docker CLI. Now the gateway starts without
the socket, and a docker-compose.sandbox.yml overlay is generated
only when all prerequisites pass. The gateway restart at the end of
sandbox setup picks up both the socket mount and sandbox config.

Also moves group_add from write_extra_compose() into the sandbox
overlay, keeping all sandbox-specific compose configuration together.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs(docker): fix sandbox docs URL in setup output

* Docker: harden sandbox setup fallback behavior

* Tests: cover docker-setup sandbox edge paths

* Docker: roll back sandbox mode on partial config failure

* Tests: assert sandbox mode rollback on partial setup

* Docs: document Docker sandbox bootstrap env controls

* Changelog: credit Docker sandbox bootstrap hardening

* Update CHANGELOG.md

* Docker: verify Docker apt signing key fingerprint

* Docker: avoid sandbox overlay deps during policy writes

* Tests: assert no-deps sandbox rollback gateway recreate

* Docs: mention OPENCLAW_INSTALL_DOCKER_CLI in Docker env vars

---------

Co-authored-by: Jakub Karwowski <jakubkarwowski@Mac.lan>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
OWALabuy pushed a commit to kcinzgg/openclaw that referenced this pull request Mar 4, 2026
…claw#29974)

* feat(docker): add opt-in sandbox support for Docker deployments

Enable Docker-based sandbox isolation via OPENCLAW_SANDBOX=1 env var
in docker-setup.sh. This is a prerequisite for agents.defaults.sandbox
to function in any Docker deployment (self-hosted, Hostinger, DigitalOcean).

Changes:
- Dockerfile: add OPENCLAW_INSTALL_DOCKER_CLI build arg (~50MB, opt-in)
- docker-compose.yml: add commented-out docker.sock mount with docs
- docker-setup.sh: auto-detect Docker socket, inject mount, detect GID,
  build sandbox image, configure sandbox defaults, add group_add

All changes are opt-in. Zero impact on existing deployments.

Usage: OPENCLAW_SANDBOX=1 ./docker-setup.sh

Closes openclaw#29933
Related: openclaw#7575, openclaw#7827, openclaw#28401, openclaw#10361, openclaw#12505, openclaw#28326

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address code review feedback on sandbox support

- Persist OPENCLAW_SANDBOX, DOCKER_GID, OPENCLAW_INSTALL_DOCKER_CLI
  to .env via upsert_env so group_add survives re-runs
- Show config set errors instead of swallowing them silently;
  report partial failure when sandbox config is incomplete
- Warn when Dockerfile.sandbox is missing but sandbox config
  is still applied (sandbox image won't exist)
- Fix non-canonical whitespace in apt sources.list entry
  by using printf instead of echo with line continuation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove `local` outside function and guard sandbox behind Docker CLI check

- Remove `local` keyword from top-level `sandbox_config_ok` assignment
  which caused script exit under `set -euo pipefail` (bash `local`
  outside a function is an error)
- Add Docker CLI prerequisite check for pre-built (non-local) images:
  runs `docker --version` inside the container and skips sandbox setup
  with a clear warning if the CLI is missing
- Split sandbox block so config is only applied after prerequisites pass

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: defer docker.sock mount until sandbox prerequisites pass

Move Docker socket mounting from the early setup phase (before image
build/pull) to a dedicated compose overlay created only after:
1. Docker CLI is verified inside the container image
2. /var/run/docker.sock exists on the host

Previously the socket was mounted optimistically at startup, leaving
the host Docker daemon exposed even when sandbox setup was later
skipped due to missing Docker CLI. Now the gateway starts without
the socket, and a docker-compose.sandbox.yml overlay is generated
only when all prerequisites pass. The gateway restart at the end of
sandbox setup picks up both the socket mount and sandbox config.

Also moves group_add from write_extra_compose() into the sandbox
overlay, keeping all sandbox-specific compose configuration together.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs(docker): fix sandbox docs URL in setup output

* Docker: harden sandbox setup fallback behavior

* Tests: cover docker-setup sandbox edge paths

* Docker: roll back sandbox mode on partial config failure

* Tests: assert sandbox mode rollback on partial setup

* Docs: document Docker sandbox bootstrap env controls

* Changelog: credit Docker sandbox bootstrap hardening

* Update CHANGELOG.md

* Docker: verify Docker apt signing key fingerprint

* Docker: avoid sandbox overlay deps during policy writes

* Tests: assert no-deps sandbox rollback gateway recreate

* Docs: mention OPENCLAW_INSTALL_DOCKER_CLI in Docker env vars

---------

Co-authored-by: Jakub Karwowski <jakubkarwowski@Mac.lan>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
…claw#29974)

* feat(docker): add opt-in sandbox support for Docker deployments

Enable Docker-based sandbox isolation via OPENCLAW_SANDBOX=1 env var
in docker-setup.sh. This is a prerequisite for agents.defaults.sandbox
to function in any Docker deployment (self-hosted, Hostinger, DigitalOcean).

Changes:
- Dockerfile: add OPENCLAW_INSTALL_DOCKER_CLI build arg (~50MB, opt-in)
- docker-compose.yml: add commented-out docker.sock mount with docs
- docker-setup.sh: auto-detect Docker socket, inject mount, detect GID,
  build sandbox image, configure sandbox defaults, add group_add

All changes are opt-in. Zero impact on existing deployments.

Usage: OPENCLAW_SANDBOX=1 ./docker-setup.sh

Closes openclaw#29933
Related: openclaw#7575, openclaw#7827, openclaw#28401, openclaw#10361, openclaw#12505, openclaw#28326


* fix: address code review feedback on sandbox support

- Persist OPENCLAW_SANDBOX, DOCKER_GID, OPENCLAW_INSTALL_DOCKER_CLI
  to .env via upsert_env so group_add survives re-runs
- Show config set errors instead of swallowing them silently;
  report partial failure when sandbox config is incomplete
- Warn when Dockerfile.sandbox is missing but sandbox config
  is still applied (sandbox image won't exist)
- Fix non-canonical whitespace in apt sources.list entry
  by using printf instead of echo with line continuation


* fix: remove `local` outside function and guard sandbox behind Docker CLI check

- Remove `local` keyword from top-level `sandbox_config_ok` assignment
  which caused script exit under `set -euo pipefail` (bash `local`
  outside a function is an error)
- Add Docker CLI prerequisite check for pre-built (non-local) images:
  runs `docker --version` inside the container and skips sandbox setup
  with a clear warning if the CLI is missing
- Split sandbox block so config is only applied after prerequisites pass


* fix: defer docker.sock mount until sandbox prerequisites pass

Move Docker socket mounting from the early setup phase (before image
build/pull) to a dedicated compose overlay created only after:
1. Docker CLI is verified inside the container image
2. /var/run/docker.sock exists on the host

Previously the socket was mounted optimistically at startup, leaving
the host Docker daemon exposed even when sandbox setup was later
skipped due to missing Docker CLI. Now the gateway starts without
the socket, and a docker-compose.sandbox.yml overlay is generated
only when all prerequisites pass. The gateway restart at the end of
sandbox setup picks up both the socket mount and sandbox config.

Also moves group_add from write_extra_compose() into the sandbox
overlay, keeping all sandbox-specific compose configuration together.


* docs(docker): fix sandbox docs URL in setup output

* Docker: harden sandbox setup fallback behavior

* Tests: cover docker-setup sandbox edge paths

* Docker: roll back sandbox mode on partial config failure

* Tests: assert sandbox mode rollback on partial setup

* Docs: document Docker sandbox bootstrap env controls

* Changelog: credit Docker sandbox bootstrap hardening

* Update CHANGELOG.md

* Docker: verify Docker apt signing key fingerprint

* Docker: avoid sandbox overlay deps during policy writes

* Tests: assert no-deps sandbox rollback gateway recreate

* Docs: mention OPENCLAW_INSTALL_DOCKER_CLI in Docker env vars

---------

Co-authored-by: Jakub Karwowski <jakubkarwowski@Mac.lan>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docker Docker and sandbox tooling docs Improvements or additions to documentation size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hostinger VPS template: Docker socket mount needed for sandbox isolation

3 participants