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
L11: bind Telegram clarify callbacks to request and originating user (#83)
- cmd/odek/telegram.go: replace global per-chat clarify channel with
pendingClarifyReqs keyed by random request ID; embed reqID in callback
data; verify the callback comes from the originating user; reject
expired/unknown requests.
- internal/telegram/handler.go: pass callback user's userID into
OnCallbackQuery so callers can enforce per-user binding.
- cmd/odek/telegram_clarify_test.go + internal/telegram/*_test.go:
regression tests and signature updates.
- docs/SECURITY.md + AGENTS.md: document L11 mitigation.
-**Telegram plan file size cap** (`internal/telegram/plan.go`) — plan files larger than 1 MiB are rejected by `ReadPlan` and `MostRecentPlan`, and `ListPlans` only reads the first 8 KiB for preview. This prevents a prompt-injected agent from causing an OOM via a multi-hundred-megabyte plan file.
182
182
-**Telegram log file permissions** (`internal/telegram/log.go`) — Telegram log files are created with `0600`, and `os.Chmod` hardens existing files. Chat IDs and task snippets are no longer world-readable by default.
183
183
-**Telegram chat-scoped sessions and plans** (`internal/telegram/session.go`, `internal/telegram/plan.go`, `cmd/odek/telegram.go`) — `/sessions`, `/resume`, `/prune`, `/plans`, `/plan_view`, `/plan_delete`, and `/plan_resume` are scoped to the requesting chat. Sessions are filtered by the `tg-<chatID>` prefix, `ResumeSession` rejects cross-chat IDs, and plans live under `~/.odek/plans/chat<chatID>/` so one chat cannot list, read, delete, or resume another chat's sessions/plans.
184
+
-**Telegram clarify callback binding** (`cmd/odek/telegram.go`, `internal/telegram/handler.go`) — each `clarify` prompt now uses a random request ID in its inline-keyboard callback data (`clarify:<reqID>:yes/no`). The handler validates the request ID and binds the answer to the originating user, so a group member or stale keyboard cannot answer someone else's clarify prompt. `Handler.OnCallbackQuery` now receives the `userID` for consistent callback binding.
184
185
-**odek self-invocation gate** (`internal/danger/classifier.go`) — any shell stage whose program basename is `odek` is classified as `system_write`. This prevents a prompt-injected agent from reaching the human-gated trust mutations (`odek memory promote`, `odek memory extended confirm`, `odek skill promote --force`) through the shell tool and flipping its own taint gates.
185
186
-**MCP inputSchema hardening** (`cmd/odek/mcp_approval.go`) — every string in an MCP tool's `inputSchema` is recursively guard-scanned for injection patterns; schemas larger than 256 KiB are rejected; the interactive approval prompt shows a SHA-256 hash and byte size of the schema so operators can detect changes.
186
187
-**MCP tool batch classification** (`internal/loop/loop.go`) — MCP tools (`<server>__<tool>`) are classified as `unknown` by `classifyToolCall`, so the batch approval gate shows them and untrusted sub-agents force them to `deny`.
Copy file name to clipboardExpand all lines: docs/SECURITY.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -667,6 +667,12 @@ Now:
667
667
668
668
`persist()` now hardens any existing file with `os.Chmod(path, 0600)` and opens the file with `os.O_WRONLY|os.O_CREATE|os.O_TRUNC` and mode `0600`, matching the permission model already applied to sessions, audit logs, and Telegram logs.
669
669
670
+
### 39n. Telegram clarify callback binding
671
+
672
+
The Telegram bot's `clarify` tool sent inline keyboard buttons with literal callback data `clarify:yes` and `clarify:no`. Because the data carried no request identifier or user binding, any group member (or a stale keyboard from an earlier task) could answer a clarify prompt intended for someone else, and a later clarify could be answered by a stale button from an earlier one.
673
+
674
+
Each clarify prompt now generates a random request ID (embedded in callback data as `clarify:<reqID>:yes/no`). The handler validates the request ID, rejects callbacks from a different user than the one who triggered the prompt, and ignores callbacks for expired or already-answered prompts. The `Handler.OnCallbackQuery` signature now receives the originating `userID` so other callback handlers can apply the same binding.
675
+
670
676
### 40. `/api/resources` result limit cap
671
677
672
678
The `/api/resources?q=...&limit=N` autocomplete endpoint previously accepted any positive `limit` value. It is now capped to 100 results both in the HTTP handler and in `Registry.Search`. This prevents a prompt-injected or attacker-forged request from forcing an unbounded directory walk and returning a multi-megabyte JSON response.
0 commit comments