Skip to content

Commit 656cd5e

Browse files
committed
docs: document project-level sandbox approval gate
1 parent a639950 commit 656cd5e

5 files changed

Lines changed: 62 additions & 0 deletions

File tree

docs/CHEATSHEET.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ Flags: `--sandbox`, `--sandbox-image`, `--sandbox-network`, `--sandbox-readonly`
229229

230230
Env vars: `ODEK_SANDBOX=true`, `ODEK_SANDBOX_IMAGE`, `ODEK_SANDBOX_NETWORK`, etc.
231231

232+
> **Project config approval:** sandbox knobs set in `./odek.json` (`sandbox_env`, `sandbox_image`, `sandbox_network`, `sandbox_volumes`) require an interactive approval prompt. Use `ODEK_APPROVE_PROJECT_SANDBOX=1` in CI/scripts, or set sandbox config via `~/.odek/config.json` / env vars / CLI flags instead.
233+
232234
Default network: `bridge` (internet access). Set `none` for air-gapped execution.
233235

234236
## Telegram Bot
@@ -289,6 +291,7 @@ odek mcp # stdio transport
289291
| `ODEK_SANDBOX_MEMORY` | sandbox_memory |
290292
| `ODEK_SANDBOX_CPUS` | sandbox_cpus |
291293
| `ODEK_SANDBOX_USER` | sandbox_user |
294+
| `ODEK_APPROVE_PROJECT_SANDBOX` | auto-approve project-level sandbox config (CI) |
292295
| `ODEK_SYSTEM` | system |
293296
| `ODEK_NO_COLOR` | no_color |
294297
| `ODEK_NO_AGENTS` | no_agents |

docs/CLI.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ Use `odek skill reset-skips` to clear the skip list and re-enable suppressed sug
296296

297297
`odek serve` enables `--sandbox` by default. `odek run` and `odek repl` keep sandbox opt-in but print a startup warning when running unsandboxed. Set `ODEK_SUPPRESS_SANDBOX_WARNING=1` to silence the warning if you've made an informed decision.
298298

299+
**Project-level sandbox approval:** if `./odek.json` sets `sandbox_env`, `sandbox_image`, `sandbox_network`, or `sandbox_volumes`, odek prompts for approval before applying them. In CI or scripted invocations, set `ODEK_APPROVE_PROJECT_SANDBOX=1` to auto-approve, or place sandbox config in `~/.odek/config.json` / `ODEK_*` env vars / CLI flags instead, which do not require approval.
300+
299301
## Audit log
300302

301303
`odek audit` reads the per-session prompt-injection audit log written under `<sessions>/audit/<id>.json`. Every time the agent ingests externally-sourced content (browser fetch, file read, MCP tool response, audio transcript) the log records:

docs/CONFIG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ Every config knob has a `ODEK_*` counterpart:
122122
| `ODEK_SANDBOX_MEMORY` | `--sandbox-memory` | string |
123123
| `ODEK_SANDBOX_CPUS` | `--sandbox-cpus` | string |
124124
| `ODEK_SANDBOX_USER` | `--sandbox-user` | string |
125+
| `ODEK_APPROVE_PROJECT_SANDBOX` || bool | approve project-level `./odek.json` sandbox config without prompting |
125126
| `ODEK_MAX_TOOL_PARALLEL` | `max_tool_parallel` | int |
126127
| `ODEK_MEMORY_EXTENDED_ENABLED` | `--memory-extended-enabled` | bool |
127128
| `ODEK_MEMORY_EXTENDED_MAX_SIZE_MB` | `--memory-extended-max-size-mb` | int |
@@ -828,6 +829,11 @@ odek run "list files"
828829
echo '{"max_iterations": 30}' > ./odek.json
829830
odek run "quick status"
830831

832+
# Project-level sandbox knobs require explicit approval (or the CI bypass)
833+
# because they can read host env vars and pick arbitrary images/networks.
834+
echo '{"sandbox": true, "sandbox_env": {"X": "${HOME}"}}' > ./odek.json
835+
ODEK_APPROVE_PROJECT_SANDBOX=1 odek run "run untrusted script"
836+
831837
# Env var override for one-off
832838
ODEK_SANDBOX=true odek run "run untrusted script"
833839

docs/SANDBOXING.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,46 @@ All sandbox settings are available in `~/.odek/config.json`, `./odek.json`, `ODE
6868
> or symlinks are rejected. Relative paths are resolved relative to the working
6969
> directory and must stay inside it.
7070
71+
## Project-level sandbox approval
72+
73+
`./odek.json` can be shipped by any repository the agent runs in. Because
74+
project-level sandbox knobs (`sandbox_env`, `sandbox_image`, `sandbox_network`,
75+
`sandbox_volumes`) can exfiltrate host secrets via `${VAR}` interpolation, pull
76+
an attacker-controlled image, or widen network access, odek requires explicit
77+
operator approval before applying them.
78+
79+
When a project requests any sandbox override, odek prints a warning and prompts:
80+
81+
```text
82+
WARNING: project config (./odek.json) requests sandbox overrides:
83+
image: alpine:latest
84+
network: bridge
85+
env: X
86+
⚠️ sandbox_env values contain ${...} interpolation against host environment variables
87+
88+
Allowing this means code in the sandbox can read workspace files and,
89+
depending on network mode, contact external hosts.
90+
91+
Approve? [y = once / t = trust this project / N]
92+
```
93+
94+
Approval options:
95+
96+
- `y` / `yes` — approve once for this run.
97+
- `t` / `trust` — persist approval for this project/sandbox fingerprint in
98+
`~/.odek/project_sandbox_approvals.json`.
99+
- `N` / empty — abort.
100+
101+
For non-interactive use (CI, cron, scheduled tasks), set:
102+
103+
```bash
104+
export ODEK_APPROVE_PROJECT_SANDBOX=1
105+
```
106+
107+
Operator-controlled sources (`~/.odek/config.json`, `ODEK_*` env vars, and CLI
108+
flags) do not require approval — only values coming from the project-level
109+
`./odek.json` are gated.
110+
71111
### Env var examples
72112

73113
```bash

docs/SECURITY.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,17 @@ exceed the cap are rejected before they are written.
351351

352352
These fields can only be set from operator-controlled sources: `~/.odek/config.json` (and `ODEK_TELEGRAM_*` env vars for `telegram`, `ODEK_GUARD_*` env vars for `guard`).
353353

354+
### 18a. Project-level sandbox config approval
355+
356+
`./odek.json` can also set sandbox knobs (`sandbox_env`, `sandbox_image`, `sandbox_network`, `sandbox_volumes`). Rather than silently rejecting them, odek gates them behind explicit operator approval, mirroring the MCP-server approval flow:
357+
358+
- Interactive TTY prompt (`y` = once, `t` = trust this project, `N` = deny).
359+
- Persistent per-project approvals stored in `~/.odek/project_sandbox_approvals.json`.
360+
- `ODEK_APPROVE_PROJECT_SANDBOX=1` bypass for CI/non-interactive use.
361+
- Non-TTY runs without the bypass fail closed.
362+
363+
This prevents a malicious repo from exfiltrating host secrets via `${VAR}` interpolation in `sandbox_env`, pulling an attacker-controlled image, or widening the container's network access without the operator's consent.
364+
354365
### SSRF guard and configured-backend allowlist
355366

356367
The `browser`, `http_batch`, and `web_search` tools use a shared SSRF / DNS-rebinding dial guard (`cmd/odek/ssrf_guard.go`). After the policy gate classifies a hostname as `network_egress`, the guard resolves the name itself and refuses any answer that points at a loopback, RFC1918, RFC4193, link-local, or metadata IP. It then pins the dial to the validated IP so the kernel cannot re-resolve to a different address.

0 commit comments

Comments
 (0)