Skip to content

fix(gateway): fail-close Telegram auth when TELEGRAM_ALLOWED_USERS is empty; warn on ALLOW_ALL - #24602

Closed
wesleysimplicio wants to merge 1 commit into
NousResearch:mainfrom
wesleysimplicio:fix/cx14-issue-24457-telegram-fail-closed
Closed

fix(gateway): fail-close Telegram auth when TELEGRAM_ALLOWED_USERS is empty; warn on ALLOW_ALL#24602
wesleysimplicio wants to merge 1 commit into
NousResearch:mainfrom
wesleysimplicio:fix/cx14-issue-24457-telegram-fail-closed

Conversation

@wesleysimplicio

Copy link
Copy Markdown
Contributor

Problem

When TELEGRAM_ALLOWED_USERS is unset, TelegramAdapter._is_authorized_user() returns True unconditionally — any Telegram account that discovers the bot gets full local agent access (filesystem, terminal, GitHub). The gateway/run.py startup log also emits no warning when GATEWAY_ALLOW_ALL_USERS=true is set, the most dangerous open state.

Root cause

gateway/platforms/telegram.py line 498–499:

allowed_csv = os.getenv("TELEGRAM_ALLOWED_USERS", "").strip()
if not allowed_csv:
    return True    # fails OPEN when env var is absent

gateway/run.py line 3360–3365 only warns when neither allowlist nor allow-all is set; it is silent when _allow_all=True.

Fix

gateway/platforms/telegram.py — fail closed when no allowlist is configured; permit only when an explicit allow-all flag is set:

if not allowed_csv:
    _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

gateway/run.py — add a loud SECURITY WARNING log when *_ALLOW_ALL_USERS=true is active, so operators are never silently in the open state.

flowchart TD
    A[Telegram update received] --> B{auth_fn available?}
    B -- yes --> C[auth_fn result]
    B -- no / raises --> D{TELEGRAM_ALLOWED_USERS set?}
    D -- yes --> E{user_id in allowlist or wildcard?}
    E -- yes --> PERMIT
    E -- no --> DENY
    D -- no --> F{GATEWAY_ALLOW_ALL_USERS or TELEGRAM_ALLOW_ALL_USERS = true?}
    F -- yes --> PERMIT
    F -- no --> DENY
Loading

Tests

New tests/gateway/test_telegram_auth_fail_closed.py — 7 cases:

Scenario Expected
No allowlist, no allow-all flags False (deny)
No allowlist, GATEWAY_ALLOW_ALL_USERS=true True (permit)
No allowlist, TELEGRAM_ALLOW_ALL_USERS=1 True (permit)
No allowlist, GATEWAY_ALLOW_ALL_USERS=false False (deny)
Known user in TELEGRAM_ALLOWED_USERS True (permit)
Unknown user in TELEGRAM_ALLOWED_USERS False (deny)
Wildcard * in allowlist True (permit)

All 7 pass.

Closes #24457

… empty; warn on ALLOW_ALL

When TELEGRAM_ALLOWED_USERS is unset, _is_authorized_user previously returned
True unconditionally, allowing any Telegram user to access the local agent.
Now returns False unless GATEWAY_ALLOW_ALL_USERS or TELEGRAM_ALLOW_ALL_USERS
is explicitly set to true/1/yes. Also adds a startup security warning when the
gateway is in open-to-all mode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 12, 2026 23:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens gateway authorization defaults for Telegram by preventing “fail-open” behavior when no allowlist is configured, and improves operator visibility when the gateway is explicitly configured for open access.

Changes:

  • Update Telegram callback authorization fallback to deny by default when TELEGRAM_ALLOWED_USERS is empty, only permitting access when an explicit allow-all flag is set.
  • Add a loud startup SECURITY WARNING log when any *_ALLOW_ALL_USERS mode is enabled.
  • Add a new test file covering allowlist/allow-all combinations for the intended fail-closed behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
gateway/platforms/telegram.py Changes Telegram callback auth fallback to fail closed unless allow-all is explicitly enabled.
gateway/run.py Adds a startup warning when open-access allow-all mode is active.
tests/gateway/test_telegram_auth_fail_closed.py Introduces tests for the allowlist/allow-all decision logic (currently via a simulated helper).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +5
"""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 +3 to +41

def _simulate_is_authorized(user_id: str, env: dict) -> bool:
"""Replicate the env-based auth logic from TelegramAdapter._is_authorized_user."""
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 497 to 503
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 thread gateway/run.py
Comment on lines +3366 to +3372
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 "
"(filesystem, terminal, credentials). "
"Set TELEGRAM_ALLOWED_USERS / DISCORD_ALLOWED_USERS etc. to restrict access."
)
Comment thread gateway/run.py
Comment on lines +3366 to +3369
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 "
@alt-glitch alt-glitch added type/security Security vulnerability or hardening comp/gateway Gateway runner, session dispatch, delivery platform/telegram Telegram bot adapter P1 High — major feature broken, no workaround duplicate This issue or pull request already exists labels May 12, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of #24468 — both implement fail-closed Telegram auth when TELEGRAM_ALLOWED_USERS is empty, checking GATEWAY_ALLOW_ALL_USERS for explicit opt-in. Fixes #24457.

@liuhao1024

Copy link
Copy Markdown
Contributor

Minor issue in test documentation:

The test file tests/gateway/test_telegram_auth_fail_closed.py contains a docstring that references a non-existent function:

The actual function being modified is , not . The function does not exist in the codebase.

Suggestion: Update the docstring to reference the correct function name for accuracy.

Note: This doesn't affect the test logic (which correctly replicates the auth check), just the documentation within the test.

@wesleysimplicio

Copy link
Copy Markdown
Contributor Author

Closing as duplicate/superseded by #24667 to keep one canonical PR per fix topic and avoid review split.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery duplicate This issue or pull request already exists P1 High — major feature broken, no workaround platform/telegram Telegram bot adapter type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Security: Telegram gateway can be open to all users by default / setup should fail closed

4 participants