3.0 KiB
3.0 KiB
Hermes Telegram Picker — Audit
Deep-dive findings from a focused code audit of the Telegram inline-keyboard picker. Component:
hermes-agent/plugins/platforms/telegram/adapter.py(gateway run.py orchestrates). Audit date: 2026-08-29.
Scope
- Model picker (
send_model_picker→_handle_model_picker_callback; callbacksmp:/mpg:/mpv:/mm:/mc:/mb/mx/mg:) - Choice picker (
send_choice_picker→_handle_choice_picker_callback; callbackcp:) - Shared pagination core
_format_choice_pageingateway/platforms/base.py(~line 4333)
Finding (broken / inconsistent)
- [BUG — auth gap]
_handle_model_picker_callbackperforms NO_is_callback_user_authorizedgate. Every other state-flipping inline-button path in the same adapter gates:- choice picker (
_handle_choice_picker_callback, line ~6673) — gated - approval buttons (
ea:, lines ~7238 / ~7418) — gated - slash-confirm (
sc:, ~7318) — gated - clarify (offer_job / scan, ~7531 / ~7602) — gated
- Only the model picker is ungated.
- choice picker (
- Consequence: in a shared group/supergroup/forum, any user who can reach the picker message can tap buttons and switch the session's active model (global-ish config flip) without being an allowed user. The choice-picker comment explicitly states the intent: "unauthorized users in a shared group must not flip session/config state via someone else's picker message" — the model picker violates exactly that rule, for the highest-impact state.
- Severity: medium (needs a group context + picker message reachable; DMs are single-user so only group/forum/channel contexts are exposed). A security inconsistency, not an outage.
Non-issues confirmed (looked, OK)
- Callback prefix routing
("mp:","mpg:","mpv:","mm:","mc:","mb","mx","mg:")— ordering safe;mpg:does not collide withmp:(different 2nd char),mc:present, no prefix collision. _format_choice_pagepagination math (clamp, slice,(N–M of T)suffix) is correct._build_model_keyboarduses globalabs_idx = start + isomm:maps correctly across pages.mx:nooppage-counter button handled by the catch-all branch.- Choice-picker button indices
cp:{i}use the flat local enumerate — correct for a single level.
Recommended fix
Add the same _is_callback_user_authorized gate at the top of _handle_model_picker_callback
(mirror the choice-picker gate at line ~6673). Gate before mutating _model_picker_state.
Owner / status
- ✅ FIXED (2026-08-29) — committed
38622dcto local hermes-agent checkout. Fix is structural / regression-proof: moved the auth gate to the single dispatch point in_handle_callback_query(telegram adapter.py ~7199), covering ALL picker callback prefixes (mp:/mpg:/mpv:/mm:/mc:/mb/mx/mg:/cp:) in one place. Any future picker callback prefix added there is auto-protected.py_compileOK. - Activation pending: running gateway PID 22864 loaded pre-patch code; will pick up the fix on its next (supervisor) restart. Do NOT force-kill mid-conversation.