Workspace Sandbox Configuration
The LLM4S workspace subsystem provides powerful capabilities (read/write files, execute commands, search) that require explicit sandboxing and security configuration.
Overview
- WorkspaceSandboxConfig: Explicit configuration describing allowed paths, resource limits, shell access, and timeouts
- Validation at startup: Config is validated when the runner starts; invalid config falls back to permissive
- Enforcement: Runner enforces limits and shell allowance; file path boundaries are enforced via
resolvePath
Configuration
Environment Variables (Runner)
When running the workspace runner (e.g. in Docker):
| Variable | Description | Default |
|---|---|---|
WORKSPACE_PATH |
Workspace root directory | /workspace |
WORKSPACE_SANDBOX_PROFILE |
Sandbox profile: permissive or locked |
permissive |
Profiles
- permissive: Current behavior—shell allowed with the read-write command allowlist (
ReadWriteCommands), standard limits (1MB file size, 500 dir entries, 30s command timeout) - locked: Shell disabled; strict limits (10s timeout). File writes and modifications remain allowed; this profile does not enforce a read-only filesystem.
HOCON (Client)
For the workspace client, sandbox config can be loaded via WorkspaceConfigSupport.loadSandboxConfig():
1
2
3
llm4s.workspace.sandbox {
profile = "locked" # or "permissive"
}
WorkspaceSandboxConfig Structure
| Field | Type | Description |
|---|---|---|
limits |
WorkspaceLimits | maxFileSize, maxDirectoryEntries, maxSearchResults, maxOutputSize |
excludePatterns |
List[String] | Glob patterns excluded from explore/search (e.g. node_modules, .git) |
shellAllowed |
Boolean | Whether executeCommand is allowed |
defaultCommandTimeout |
FiniteDuration | Default timeout for shell commands (more than zero, at most 1 hour) |
readOnlyPaths |
List[String] | Paths under workspace that are read-only (Phase 2) |
allowedPaths |
List[String] | If non-empty, only these paths accessible (Phase 2) |
networkAllowed |
Boolean | Documentation only; Phase 2: enforce network restrictions |
allowedCommands |
Set[String] | Executable names executeCommand may run; field default ReadOnlyCommands; the permissive profile (the default profile) uses ReadWriteCommands, which adds write-capable ones (cp, mv, rm, mkdir, …). Arguments are not checked, so this is not a read-only guarantee (#1715) |
Security Gaps Addressed
| Gap | Phase 1 | Phase 2 |
|---|---|---|
| Explicit config | ✓ WorkspaceSandboxConfig | |
| Validation at startup | ✓ | |
| Shell allow/block | ✓ shellAllowed | |
| Resource limits | ✓ limits configurable | |
| Read-only areas | Config present | Enforcement |
| Allowed/blocked paths | Config present | Enforcement |
| Network restrictions | Documentation only | Enforcement |
Example: Locked-Down Sandbox
Run the minimal demo (local filesystem, no Docker):
1
sbt "workspaceSamples/runMain org.llm4s.samples.workspace.LockedDownSandboxDemo"
Run the containerized runner with locked sandbox:
- After
sbt workspaceRunner/docker:publishLocal, get the image tag:1
docker images llm4s/workspace-runner --format "{{.Tag}}"
Use that tag (for example
0.3.2or a dynver snapshot such as0.3.2+abc123-SNAPSHOT) in place ofTAGbelow. - Run the container (replace
TAGand the host path to your workspace):1
docker run --rm -e WORKSPACE_SANDBOX_PROFILE=locked -v /path/to/workspace:/workspace -p 8080:8080 llm4s/workspace-runner:TAG
On Windows with Docker Desktop, use a path Docker can mount (e.g.
C:\Users\you\workspaceor//c/Users/you/workspacedepending on your setup).
Phased Implementation Plan
Phase 1: Config + docs + sample ✓
- Affected: workspaceShared, workspaceRunner, workspaceClient, workspaceSamples, docs
- Complexity: Low
- Risks: Minimal; backward compatible (default = permissive)
Phase 2: Enforcement
- Affected: WorkspaceAgentInterfaceImpl (readOnlyPaths, allowedPaths), tools
- Complexity: Medium
- Risks: Path validation edge cases; breaking changes if strict
Phase 3: Advanced policies (optional)
- Affected: New policies module, profiles (dev/staging/prod)
- Complexity: High
- Risks: Over-engineering; maintenance burden