Skip to content

Commit 4865abf

Browse files
committed
docs: document per-path search classification and case-insensitive anchors
- AGENTS.md: add Search path classification bullet and note case-insensitive ~/.odek trust-anchor matching. - docs/SECURITY.md: add 3c subsection describing search_files/multi_grep per-path classification and the skipped field. - docs/CHEATSHEET.md: note that search_files/multi_grep report skipped sensitive paths.
1 parent 5777684 commit 4865abf

3 files changed

Lines changed: 8 additions & 3 deletions

File tree

AGENTS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ Layered prompt-injection / approval-fatigue defenses. Full reference: [docs/SECU
119119
- **REST API CSRF protection** (`cmd/odek/serve.go::requireLocalOrigin`) — state-changing HTTP endpoints (POST/PUT/PATCH/DELETE) require a localhost origin or no Origin header, and static responses set `X-Frame-Options: DENY` + `Content-Security-Policy: frame-ancestors 'none'` to block clickjacking.
120120
- **Browser history cap** (`cmd/odek/browser_tool.go`) — navigation history is capped at 50 snapshots to prevent memory DoS from repeated `browser_navigate` calls.
121121
- **Browser element cap** (`cmd/odek/browser_tool.go`) — the number of interactive elements extracted per page is capped at 500 so a hostile page cannot OOM the agent with thousands of links or buttons.
122+
- **Search path classification** (`cmd/odek/file_tool.go`, `cmd/odek/perf_tools.go`) — `search_files` and `multi_grep` classify every descended directory and every discovered file the same way the search root is classified. Sensitive paths that would require approval (or are denied) are skipped and reported in the `skipped` field rather than returned silently, closing the gap where a broad search root auto-approved sensitive files.
122123
- **Search result bounds** (`cmd/odek/file_tool.go`, `cmd/odek/perf_tools.go`) — `search_files` and `multi_grep` enforce a max match limit (500) and a total returned-content cap (1 MiB) to avoid unbounded result JSON.
123124
- **Perf-tool file-size cap** (`cmd/odek/perf_tools.go`) — `diff`, `base64`, `tr`, `sort`, `json_query`, and `batch_patch` reject files larger than 10 MiB to avoid loading multi-gigabyte files into memory.
124125
- **Shell output cap** (`cmd/odek/shell.go`, `cmd/odek/perf_tools.go`) — `shell` and `parallel_shell` cap captured stdout/stderr at 1 MiB per stream to prevent memory DoS from commands that dump huge files.
@@ -158,7 +159,7 @@ Layered prompt-injection / approval-fatigue defenses. Full reference: [docs/SECU
158159
- **Schedule cross-process lock hard error** (`internal/schedule/store.go`) — `fileLock` now returns an error instead of silently falling back to a no-op releaser when `~/.odek/schedules.lock` cannot be opened or locked. Mutating schedule operations abort rather than risk two concurrent processes loading the same baseline and overwriting each other.
159160
- **Schedule JSON file-size cap** (`internal/schedule/store.go`) — `schedules.json` and `schedule-state.json` are rejected if larger than 10 MiB before being read into memory, preventing a tampered multi-gigabyte file from OOMing the scheduler.
160161
- **Default non-interactive policy is deny** (`internal/danger/classifier.go`, `cmd/odek/main.go`) — headless/CI/piped runs no longer auto-approve dangerous operations. Operators must explicitly set `non_interactive: "allow"` for unattended execution.
161-
- **`~/.odek` trust-anchor protection** (`internal/danger/classifier.go`, `cmd/odek/file_tool.go`) — generic file tools reject writes to `~/.odek/config.json`, `secrets.env`, `IDENTITY.md`, `skills/`, `sessions/`, `audit/`, `plans/`, `schedules.json`, `schedule-state.json`, `mcp_approvals.json`, `mcp_tool_approvals.json`, `restart.json`, `telegram.lock`, and related state files. These paths classify as `system_write` and must be modified through their dedicated subsystems. Shell reads of these trust anchors are also escalated to `system_write`.
162+
- **`~/.odek` trust-anchor protection** (`internal/danger/classifier.go`, `cmd/odek/file_tool.go`) — generic file tools reject writes to `~/.odek/config.json`, `secrets.env`, `IDENTITY.md`, `skills/`, `sessions/`, `audit/`, `plans/`, `schedules.json`, `schedule-state.json`, `mcp_approvals.json`, `mcp_tool_approvals.json`, `restart.json`, `telegram.lock`, and related state files. These paths classify as `system_write` and must be modified through their dedicated subsystems. Matching is case-insensitive so variants such as `CONFIG.JSON` or `SECRETS.ENV` are also blocked on case-insensitive filesystems (e.g. macOS APFS). Shell reads of these trust anchors are also escalated to `system_write`.
162163
- **Nonce'd tool-result delimiter** (`internal/loop/loop.go`) — the static `┌── TOOL RESULT: ... └── END TOOL RESULT: ...` delimiter is now unique per tool call via a random hex nonce embedded in both the opening and closing lines. A tool or MCP server can no longer forge the closing delimiter to break out of the data framing and inject instructions.
163164
- **`parallel_shell` context + process-group kill** (`cmd/odek/perf_tools.go`) — commands now run via `exec.CommandContext` bound to the agent context, in their own process group. Cancellation or timeout kills the whole group (negative PID), so `sh -c 'sleep 3600 &'` cannot leave orphaned children. Per-command timeouts are also capped at 30 minutes.
164165
- **`batch_patch` trusted-class propagation** (`cmd/odek/perf_tools.go`) — `batch_patch` now passes its cached `trustedClasses` to `CheckOperation`, matching `write_file` and `patch`. A trusted `local_write` class is honored across all patches in the batch instead of re-prompting per patch.

docs/CHEATSHEET.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ odek mcp # stdio transport
324324
| `file_info` | Stat metadata (size, mod_time, mode, type) |
325325
| `sort` | Sort lines asc/desc/unique/numeric/case-insensitive |
326326
| `head_tail` | First/last N lines, streaming, parallel |
327-
| `search_files` | Regex content search or glob file find |
327+
| `search_files` | Regex content search or glob file find; sensitive discovered paths are returned in `skipped` |
328328

329329
### Data Processing (in-process, no shell fork)
330330
| Tool | Description |
@@ -348,7 +348,7 @@ odek mcp # stdio transport
348348
### Multi-Pattern (parallel goroutine search)
349349
| Tool | Description |
350350
|------|-------------|
351-
| `multi_grep` | Search N regex patterns in parallel |
351+
| `multi_grep` | Search N regex patterns in parallel; sensitive discovered paths are returned in `skipped` |
352352
| `search_files` | Single-pattern content/file search |
353353

354354
### Execution (shell replacement)

docs/SECURITY.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ If the sidecar flags content, the behavior mirrors a local scan flag: writes are
119119

120120
The `guard` section is operator-controlled: project-level `./odek.json` cannot set it, so a malicious repository cannot disable the local scan or redirect memory/system-prompt content to an attacker-controlled endpoint.
121121

122+
### 3c. Path classification for broad searches
123+
124+
`search_files` and `multi_grep` do not stop at classifying the search root. Every descended directory and every discovered file is run through the same `danger.ClassifyPath` check used by `read_file` and `write_file`. If a discovered path is more sensitive than the root (for example, a `~/.odek/config.json` or `~/.bashrc` encountered while scanning a broader directory), it is skipped and reported in the tool result's `skipped` field instead of being read or returned silently. This closes the gap where a prompt-injected broad search smuggles out files that would be gated if read individually.
125+
122126
### 4. Tool-call approval
123127

124128
When a classification is set to `prompt`, an approver pauses the agent until the user decides. Two implementations:

0 commit comments

Comments
 (0)