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
-**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.
171
171
-**`send_message` callback prefix restriction** (`internal/tool/send_message.go` + `cmd/odek/telegram.go`) — the `send_message` tool rejects any button whose `callback_data` starts with a reserved internal prefix (`apr:`, `den:`, `trs:`, `clarify:`, `skill_save:`, `skill_skip:`); only user-facing `cb:` callbacks are allowed. The Telegram sender closure validates again as defense-in-depth, preventing a forged approval or skill button.
172
172
-**Telegram class-trust guard + friction** (`internal/telegram/approver.go`) — the "Trust Session" button is hidden for `destructive`, `blocked`, `unknown`, and the synthetic `tool_batch` class, and a trust callback for those classes is treated as a denial. After 3 approvals of the same class in 60 seconds, friction mode hides the Trust Session shortcut and adds a warning, forcing per-call approval and breaking reflexive tap-through.
173
-
-**Telegram outbound media hardening** (`internal/telegram/media_path.go` + `internal/telegram/approver.go` + `internal/telegram/handler.go` + `internal/tool/send_message.go` + `cmd/odek/telegram.go`) — paths supplied to `MEDIA:...` prefixes or `send_message(file=...)` are resolved to an absolute path and verified against an allowlist (cwd, `~/.odek/media/`, system temp dir). On Unix the final component is opened with `O_NOFOLLOW` and `fstat`'d to avoid a symlink TOCTOU race; `filepath.EvalSymlinks` ensures the resolved path does not escape the allowlist. Additionally, well-known secret subtrees (`~/.ssh`, `~/.aws`, `~/.gnupg`, `~/.odek` trust anchors, etc.) and any file whose basename starts with `.env` are rejected outright, and every outbound media upload now requires explicit user approval via `TelegramApprover.PromptMedia`, with an extra warning when the bot was launched from `$HOME` or `/`.
173
+
- **Telegram outbound media hardening** (`internal/telegram/media_path.go` + `internal/telegram/approver.go` + `internal/telegram/handler.go` + `internal/tool/send_message.go` + `cmd/odek/telegram.go`) — paths supplied to `MEDIA:...` prefixes or `send_message(file=...)` are resolved to an absolute path and verified against an allowlist (cwd, `~/.odek/media/`, system temp dir). On Unix the final component is opened with `O_NOFOLLOW` and `fstat`'d to avoid a symlink TOCTOU race; `filepath.EvalSymlinks` ensures the resolved path does not escape the allowlist. Additionally, well-known secret subtrees (`~/.ssh`, `~/.aws`, `~/.gnupg`, `~/.odek` trust anchors, etc.) and any file whose basename starts with `.env` are rejected outright, and every outbound media upload now requires explicit user approval via `TelegramApprover.PromptMedia`, with an extra warning when the bot was launched from `$HOME` or `/`. The shared `~/.odek/media/` directory is further scoped per chat: `ResolveMediaPathForChat` accepts a file there only when its basename contains the originating chat's `_chat<chatID>_` tag (matching downloads produced by `DownloadVoice`/`DownloadPhoto`/`DownloadDocument`) or it lives under `~/.odek/media/chat<chatID>/`, preventing one chat from re-disclosing another chat's uploaded documents or media.
174
174
-**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.
175
175
-**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.
176
176
-**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.
Copy file name to clipboardExpand all lines: docs/SECURITY.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -428,6 +428,8 @@ The path is resolved to an absolute, cleaned form with `filepath.Abs`, symlinks
428
428
429
429
On top of the allowlist, `ResolveMediaPath` now rejects well-known secret subtrees (`~/.ssh`, `~/.aws`, `~/.gnupg`, `~/.odek` trust anchors, etc.) and any file whose basename starts with `.env`, so project API keys and host secrets cannot be uploaded even when the bot is launched from a broad base such as `$HOME` or `/`.
430
430
431
+
The shared `~/.odek/media/` directory is additionally scoped per chat. Telegram callers use `ResolveMediaPathForChat`, which accepts a file inside `~/.odek/media/` only when its basename contains the originating chat's tag (`_chat<chatID>_`, matching the names produced by `DownloadVoice`, `DownloadPhoto`, and `DownloadDocument`) or when it lives under `~/.odek/media/chat<chatID>/`. This prevents a chat from asking the bot to re-send documents or media that were uploaded by a different chat.
432
+
431
433
Finally, every outbound media upload requires explicit user approval via `TelegramApprover.PromptMedia` (`internal/telegram/approver.go`). The approval card shows the full file path and the `network_egress` risk class, and adds an explicit warning when the current working directory is `$HOME` or `/`. If no approver is registered (e.g. a standalone `Handler` outside the bot runtime), the upload is denied outright.
432
434
433
435
### 24. Session ID entropy + session-scoped auth tokens
Copy file name to clipboardExpand all lines: docs/TELEGRAM.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -210,12 +210,13 @@ The handler uses `sync.Map` for `TelegramApprover` instances, keyed by `chatID`.
210
210
211
211
### Outbound Media
212
212
213
-
The agent can send files back to the chat either by emitting a `MEDIA:` prefix in its final answer (`MEDIA:photo:/path`, `MEDIA:voice:/path`, `MEDIA:document:/path`) or by calling `send_message` with the `file` parameter. Before any upload, the path is validated by `internal/telegram.ResolveMediaPath`:
213
+
The agent can send files back to the chat either by emitting a `MEDIA:` prefix in its final answer (`MEDIA:photo:/path`, `MEDIA:voice:/path`, `MEDIA:document:/path`) or by calling `send_message` with the `file` parameter. Before any upload, the path is validated by `internal/telegram.ResolveMediaPathForChat`:
214
214
215
215
- Allowed directories: current working directory, `~/.odek/media/`, and the system temporary directory.
216
216
- The path is resolved to an absolute, cleaned form and checked against the allowlist.
217
217
- Symlinks are rejected: on Unix the final component is opened with `O_NOFOLLOW` and verified with `fstat` to close a TOCTOU race; on other platforms it is checked with `os.Lstat`. The resolved path must not escape the allowlist.
218
218
- Files outside the allowlist (e.g. `/home/user/.ssh/id_rsa`) are refused, closing prompt-injection-driven exfiltration.
219
+
- Files inside the shared `~/.odek/media/` directory are additionally scoped to the originating chat. A file is accepted only when its basename contains the chat's `_chat<chatID>_` tag (matching files downloaded by the bot) or when it lives under `~/.odek/media/chat<chatID>/`. This prevents one chat from asking the bot to re-send documents or media uploaded by another chat.
0 commit comments