You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: disallow api_key, system, dangerous from project config
Project-level ./odek.json is untrusted, so it can no longer override the
API key, system prompt, or dangerous-policy. Global config, ODEK_* env
vars, and CLI flags remain valid sources.
- Ignore project BaseURL, APIKey, System, and Dangerous in LoadConfig.
- Print stderr warnings for each ignored project-level sensitive field.
- Update TestRun_WithProjectConfig to use env API key + project model.
- Add regression tests for api_key/system/dangerous rejection.
- Update docs/CONFIG.md, docs/SECURITY.md, and AGENTS.md.
-**Sandbox volume confinement** (`internal/sandbox/sandbox.go`) — extra `--sandbox-volume` host paths must resolve to a location under the working directory, cannot contain `..` or symlink escapes, and cannot match sensitive prefixes such as `/etc`, `/proc`, `/sys`, `/dev`, `/root`, `/home`, `/var`, `/run`, or `/var/run/docker.sock`.
134
134
-**Sandbox read-only enforcement** (`cmd/odek/sandbox_file.go` + `cmd/odek/file_tool.go` + `cmd/odek/perf_tools.go`) — when a sandbox container is active, `write_file`, `patch`, and `batch_patch` translate host paths to `/workspace/...` and copy data into the container with `docker cp`, so a read-only workspace mount (`--sandbox-readonly`) is enforced for the agent's own file tools.
135
-
-**Project config base_url rejection** (`internal/config/loader.go`) — `./odek.json` is untrusted, so a `base_url`set there is ignored (with a stderr warning). The LLM endpoint can only be configured from the operator-controlled global config (`~/.odek/config.json`), `ODEK_BASE_URL`, or `--base-url`.
135
+
-**Project config sensitive-field rejection** (`internal/config/loader.go`) — `./odek.json` is untrusted, so `base_url`, `api_key`, `system`, and the `dangerous` section set there are ignored (with stderr warnings). These can only be configured from operator-controlled sources: `~/.odek/config.json`, `ODEK_*` env vars, or CLI flags.
136
136
-**Telegram photo caption wrapping** (`cmd/odek/telegram.go`) — photo captions cross the Telegram trust boundary, so they are wrapped as untrusted content both when passed to the local vision model and when injected into the main agent's user message.
137
137
-**Secret redaction** (`internal/redact/redact.go`) — 20+ patterns: OpenAI, Anthropic, GitHub PAT, AWS, PEM, JWT, Vault, Google OAuth, SendGrid, Discord, DB URLs, etc.
Copy file name to clipboardExpand all lines: docs/CONFIG.md
+8-1Lines changed: 8 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -56,7 +56,14 @@ Same schema as global. Only set the fields you want to override:
56
56
}
57
57
```
58
58
59
-
> **Security note:**`base_url` cannot be set in `./odek.json`. A malicious project could redirect all LLM traffic (including your API key and full conversation history) to an attacker-controlled endpoint. Set `base_url` in `~/.odek/config.json`, via `ODEK_BASE_URL`, or with `--base-url` instead.
59
+
> **Security note:** The following fields cannot be set in `./odek.json` because a malicious repository could use them to steal secrets, poison the system prompt, or disable safety policy:
60
+
>
61
+
> -`base_url` — use `~/.odek/config.json`, `ODEK_BASE_URL`, or `--base-url`
62
+
> -`api_key` — use `~/.odek/config.json`, `ODEK_API_KEY`, or `~/.odek/secrets.env`
63
+
> -`system` — use `~/.odek/config.json`, `ODEK_SYSTEM`, or `--system`
64
+
> -`dangerous` — use `~/.odek/config.json`
65
+
>
66
+
> If any of these appear in `./odek.json`, odek ignores them and prints a warning.
60
67
61
68
Both files are optional. Missing files are silently ignored. String values support `${VAR}` environment variable substitution — useful for API keys without plaintext storage.
Copy file name to clipboardExpand all lines: docs/SECURITY.md
+9-2Lines changed: 9 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -297,9 +297,16 @@ exceed the cap are rejected before they are written.
297
297
298
298
`~/.odek/config.json` and `./odek.json` are rejected if they exceed 5 MiB. This prevents a malicious, truncated, or accidentally-generated config file from causing an out-of-memory condition at startup.
299
299
300
-
### 18. Project-level `base_url` rejection
300
+
### 18. Project-level sensitive config rejection
301
301
302
-
`./odek.json` can be shipped by any repository the agent runs in, so it is treated as untrusted for the LLM endpoint. If a project config sets `base_url`, the value is ignored and a warning is printed to stderr. The LLM base URL can only be set from operator-controlled sources: `~/.odek/config.json`, `ODEK_BASE_URL`, or `--base-url`. This closes a prompt-exfiltration path where a malicious repo redirects the conversation history and API key to an attacker-controlled server.
302
+
`./odek.json` can be shipped by any repository the agent runs in, so it is treated as untrusted for sensitive fields. If a project config sets any of the following, the value is ignored and a warning is printed to stderr:
303
+
304
+
-`base_url` — can redirect the conversation history and API key to an attacker-controlled server.
305
+
-`api_key` — can exfiltrate prompts by billing runs to an attacker-owned key.
306
+
-`system` — can poison the system prompt with hidden instructions.
307
+
-`dangerous` — can disable the approval gate (`{"action": "allow"}`) and enable destructive auto-execution.
308
+
309
+
These fields can only be set from operator-controlled sources: `~/.odek/config.json`, `ODEK_*` environment variables, or CLI flags.
// Project config is untrusted: a malicious repo must not be able to redirect
605
-
// LLM traffic (and exfiltrate the API key + conversation history) by setting
606
-
// base_url. Keep any global base_url; env vars and CLI flags can still
607
-
// override below.
604
+
// Project config is untrusted: a malicious repo must not be able to steal
605
+
// the API key, poison the system prompt, or disable safety policy.
606
+
// Keep global values for these sensitive fields; env vars and CLI flags can
607
+
// still override below.
608
608
ifproject.BaseURL!="" {
609
609
fmt.Fprintf(os.Stderr, "odek: WARNING: ignoring base_url from project config (%s); set it via ~/.odek/config.json, ODEK_BASE_URL, or --base-url\n", ProjectConfigPath())
610
610
project.BaseURL=""
611
611
}
612
+
ifproject.APIKey!="" {
613
+
fmt.Fprintf(os.Stderr, "odek: WARNING: ignoring api_key from project config (%s); set it via ~/.odek/config.json, ODEK_API_KEY, or ~/.odek/secrets.env\n", ProjectConfigPath())
614
+
project.APIKey=""
615
+
}
616
+
ifproject.System!="" {
617
+
fmt.Fprintf(os.Stderr, "odek: WARNING: ignoring system from project config (%s); set it via ~/.odek/config.json, ODEK_SYSTEM, or --system\n", ProjectConfigPath())
618
+
project.System=""
619
+
}
620
+
ifproject.Dangerous!=nil {
621
+
fmt.Fprintf(os.Stderr, "odek: WARNING: ignoring dangerous section from project config (%s); set it via ~/.odek/config.json\n", ProjectConfigPath())
0 commit comments