Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion gateway/platforms/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,9 @@ def _is_callback_user_authorized(

allowed_csv = os.getenv("TELEGRAM_ALLOWED_USERS", "").strip()
if not allowed_csv:
return True
_global_open = os.getenv("GATEWAY_ALLOW_ALL_USERS", "").lower() in ("true", "1", "yes")
_tg_open = os.getenv("TELEGRAM_ALLOW_ALL_USERS", "").lower() in ("true", "1", "yes")
return _global_open or _tg_open
allowed_ids = {uid.strip() for uid in allowed_csv.split(",") if uid.strip()}
return "*" in allowed_ids or normalized_user_id in allowed_ids
Comment on lines 497 to 503

Expand Down
7 changes: 7 additions & 0 deletions gateway/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -3363,6 +3363,13 @@ async def start(self) -> bool:
"Set GATEWAY_ALLOW_ALL_USERS=true in ~/.hermes/.env to allow open access, "
"or configure platform allowlists (e.g., TELEGRAM_ALLOWED_USERS=your_id)."
)
elif _allow_all:
logger.warning(
"SECURITY WARNING: Gateway is open to ALL users (*_ALLOW_ALL_USERS=true). "
"Any user who finds this bot can interact with your local agent "
Comment on lines +3366 to +3369
"(filesystem, terminal, credentials). "
"Set TELEGRAM_ALLOWED_USERS / DISCORD_ALLOWED_USERS etc. to restrict access."
)
Comment on lines +3366 to +3372

# Discover Python plugins before shell hooks so plugin block
# decisions take precedence in tie cases. The CLI startup path
Expand Down
42 changes: 42 additions & 0 deletions tests/gateway/test_telegram_auth_fail_closed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Tests for Telegram _is_authorized_user failing closed when no allowlist is set."""


def _simulate_is_authorized(user_id: str, env: dict) -> bool:
"""Replicate the env-based auth logic from TelegramAdapter._is_authorized_user."""
Comment on lines +1 to +5
allowed_csv = env.get("TELEGRAM_ALLOWED_USERS", "").strip()
if not allowed_csv:
_global_open = env.get("GATEWAY_ALLOW_ALL_USERS", "").lower() in ("true", "1", "yes")
_tg_open = env.get("TELEGRAM_ALLOW_ALL_USERS", "").lower() in ("true", "1", "yes")
return _global_open or _tg_open
allowed_ids = {uid.strip() for uid in allowed_csv.split(",") if uid.strip()}
return "*" in allowed_ids or user_id in allowed_ids


class TestTelegramAuthFailClosed:
def test_no_allowlist_no_allow_all_denies(self):
result = _simulate_is_authorized("999", {})
assert result is False

def test_no_allowlist_gateway_allow_all_true_permits(self):
result = _simulate_is_authorized("999", {"GATEWAY_ALLOW_ALL_USERS": "true"})
assert result is True

def test_no_allowlist_telegram_allow_all_true_permits(self):
result = _simulate_is_authorized("999", {"TELEGRAM_ALLOW_ALL_USERS": "1"})
assert result is True

def test_no_allowlist_allow_all_false_string_denies(self):
result = _simulate_is_authorized("999", {"GATEWAY_ALLOW_ALL_USERS": "false"})
assert result is False

def test_known_user_in_allowlist_permits(self):
result = _simulate_is_authorized("123456", {"TELEGRAM_ALLOWED_USERS": "123456,789012"})
assert result is True

def test_unknown_user_in_allowlist_denies(self):
result = _simulate_is_authorized("000000", {"TELEGRAM_ALLOWED_USERS": "123456,789012"})
assert result is False

def test_wildcard_in_allowlist_permits_anyone(self):
result = _simulate_is_authorized("999999", {"TELEGRAM_ALLOWED_USERS": "*"})
Comment on lines +3 to +41
assert result is True
Loading