#21756: [AI-Assisted] Sandbox: add support for env_file in Docker sandboxes
docker
agents
size: L
## Summary
- **Problem:** Docker sandboxes required sensitive keys (API tokens, credentials, etc.) to be explicitly listed in the `openclaw.json` `env` object. This creates two risks:
1. **Supply chain exposure:** When users share their config file with AI tools for review or troubleshooting against the latest codebase, sensitive values — and even the _existence_ of certain environment variable names — are submitted to third-party models.
2. **Accidental commit:** Secrets inlined in JSON config are easily committed to version control.
- **Why it matters:** Keeping secrets in a separate `.env` file that config validation and AI review tools never read reduces supply chain risk and improves DX for users managing multiple environments or agents.
- **What changed:**
- Added `envFile` support (string or string array) to global and per-agent Docker sandbox configurations.
- Implemented secure file loading with `inspectPathPermissions` (symlink, world-writable, directory rejection) and `dotenv` parsing.
- File-loaded variables merge into the existing sanitization pipeline: sensitive keys are blocked from `docker create` args but remain available for tool-call injection via `SandboxContext`.
- Added comprehensive unit tests covering sanitization, array precedence, and explicit `env` override behavior.
- **What did NOT change:** The behavior of the existing `env` object remains identical; `env` values always override `envFile` values on key collision. Non-Docker sandboxes (e.g., Browser) are out of scope.
- **Design note:** The gateway process reads and parses `.env` file contents because the current sandbox architecture requires env vars in the `env` object for `SandboxContext` — they're filtered by keyword matching for container creation but still needed for tool-call injection. This is architecturally necessary today.
## Change Type (select all)
- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Docs
- [x] Security hardening
- [ ] Chore/infra
## Scope (select all touched areas)
- [x] Gateway / orchestration
- [ ] Skills / tool execution
- [ ] Auth / tokens
- [ ] Memory / storage
- [ ] Integrations
- [ ] API / contracts
- [x] UI / DX
- [ ] CI/CD / infra
## Linked Issue/PR
- Related to user request for secret isolation in sandboxes.
## User-visible / Behavior Changes
- **New Config Key:** `envFile` (string or string array) under `sandbox.docker` — both global defaults and per-agent overrides. Follows Docker's established `--env-file` convention and aligns with existing Docker-convention config keys like `tmpfs`.
- **Path Enforcement:** Only absolute paths are accepted (validated via `path.isAbsolute()` for cross-platform support).
- **File Security:** Files are validated at container-ensure time via `inspectPathPermissions`: symlinks, directories, and world-writable files are rejected.
- **Merge Precedence:** Later files in an array override earlier ones on key collision. Explicit `env` values always take final precedence over any file-loaded values.
- **Sanitization:** Variables loaded from files flow through the existing `sanitizeEnvVars` pipeline — identical behavior to values specified in the `env` object.
- **Container Recreation:** Env file contents are included in the config hash. If file contents change, the container is recreated (Docker bakes `--env` at creation time, so this is correct behavior to apply updates).
## Security Impact (required)
- New permissions/capabilities? (`No`)
- Secrets/tokens handling changed? (`Yes` — Improved: secrets can now be stored outside the main application config, reducing exposure when config is shared with AI review tools or committed to VCS.)
- New/changed network calls? (`No`)
- Command/tool execution surface changed? (`No`)
- Data access scope changed? (`No`)
- **If any `Yes`, explain risk + mitigation:**
- **Risk:** Gateway reads `.env` file contents into process memory before forwarding via `--env` flags.
- **Mitigation:** File access requires `openclaw.json` edit access to specify a path. Files are validated with `inspectPathPermissions` (rejects symlinks, world-writable files). Values pass through `sanitizeEnvVars` before container creation.
- **Known limitation:** A small TOCTOU window exists between `inspectPathPermissions` (stat) and `fs.readFile` (open). Eliminating this requires `O_NOFOLLOW` fd-level operations, which is non-trivial in Node. Practical risk is low since env files are admin-controlled.
## Repro + Verification
### Environment
- OS: Linux
- Runtime/container: Node 22 (verified via Docker `node:22-slim`)
- Model/provider: N/A
- Integration/channel (if any): N/A
- Relevant config (redacted): `agent.sandbox.docker.env_file`
### Steps
1. Create a `.env.test` file on the host with `MY_SECRET=hidden_value`.
2. Configure an agent with `"sandbox": { "docker": { "env_file": "/path/to/.env.test" } }`.
3. Run a tool that prints environment variables.
### Expected
- `MY_SECRET` is available within the tool execution environment.
- `MY_SECRET` does **NOT** appear in `docker inspect` or container logs (verified via sanitization tests).
### Actual
- Environment variables are correctly merged and sanitized according to the existing security policy.
## Evidence
Attach at least one:
- [x] Passing test/log before + passing after: `src/agents/sandbox/docker.env-file.test.ts`
- [x] Trace/log snippets: `pnpm check && pnpm build` passed inside Docker.
- [ ] Screenshot/recording
- [ ] Perf numbers (if relevant)
## Human Verification (required)
What you personally verified (not just CI), and how:
- **Verified scenarios:** Single path string vs. array; global vs. agent-specific merging; hashing triggers recreation.
- **Edge cases checked:** Missing files (throws error); malformed paths (blocked by Zod); key collisions (`env` wins).
- **What you did **not** verify:** Windows support (POSIX-only enforcement).
## Compatibility / Migration
- Backward compatible? (`Yes`)
- Config/env changes? (`Yes` - Optional `env_file` field added).
- Migration needed? (`No`)
## Failure Recovery (if this breaks)
- How to disable/revert this change quickly: Remove `env_file` from `openclaw.json`.
- Files/config to restore: N/A
- Known bad symptoms reviewers should watch for: "Failed to read sandbox env file" errors if paths are incorrect.
## Risks and Mitigations
- Risk: Host filesystem access for .env files.
- Mitigation: Gated by absolute path validation in Zod and standard configuration access controls.
---
### AI-Assisted PR Tracking
- **Testing Degree:** Fully tested (Unit tests added + manual verification of build/formatting).
- **Session Context:** Created types, schema validation, and runtime logic for Docker sandbox env file support.
- **Model:** Gemini 3 Flash (Preview) via GitHub Copilot.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Added `env_file` support to Docker sandboxes allowing secrets to be stored in external `.env` files instead of directly in `openclaw.json`. The implementation includes Zod validation for absolute POSIX paths, asynchronous file loading with dotenv, and proper integration with the existing sanitization pipeline.
**Key changes:**
- Added `envFile` field to sandbox Docker config (string or array)
- Implemented env file loading in `ensureSandboxContainer` before container creation
- Added path validation requiring absolute POSIX paths
- Merging strategy: env file values are loaded first, then `env` object values override on collision
- Variables from env files are sanitized (blocked from container creation) just like `env` values
**Issues found:**
- Critical logic bug: config hash is computed AFTER loading env file contents into the env object, causing container recreation whenever .env file contents change (even if the path stays the same)
<h3>Confidence Score: 2/5</h3>
- Contains a critical logic bug that will cause operational issues with container recreation
- The implementation has a significant logical flaw in the hash computation timing that will cause containers to be unnecessarily recreated whenever .env file contents change, defeating one of the main benefits of this feature (stability). The security implementation (path validation, sanitization) appears sound, and the test coverage demonstrates understanding of the sanitization flow, but the hash computation bug is a critical runtime issue.
- src/agents/sandbox/docker.ts - fix the hash computation timing to exclude dynamically loaded env values
<sub>Last reviewed commit: 3c62747</sub>
<!-- greptile_other_comments_section -->
<sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#14308: fix(sandbox): pass docker.env config to container creation
by wboudy · 2026-02-11
75.6%
#8161: fix(sandbox): block dangerous environment variables from Docker con...
by yubrew · 2026-02-03
75.0%
#19566: [AI-Assisted] feat: add openclaw sandbox run command
by bundasht · 2026-02-17
73.5%
#7826: feat(sandbox): add Docker Sandboxes (microVM) as alternative backend
by HODL-Community · 2026-02-03
71.9%
#3907: fix(sandbox): use absolute /bin/sh path + add allowedReadPaths config
by pvoo · 2026-01-29
71.6%
#4226: Fix/sandbox containerworkdir rw access
by ozgur-polat · 2026-01-29
71.1%
#10174: fix(docker): exclude .env files from Docker build context
by coygeek · 2026-02-06
70.6%
#7133: feat: Automated Docker setup with environment-based configuration
by synetalsolutions · 2026-02-02
70.5%
#13873: fix(sandbox): prevent Windows PATH from poisoning docker exec
by alessandrorodi · 2026-02-11
70.1%
#13953: feat(docker): add .env template and improve Dockerfile
by n24q02m · 2026-02-11
69.8%