Skip to content
Merged
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
38 changes: 37 additions & 1 deletion gateway/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from contextvars import copy_context
from pathlib import Path
from datetime import datetime
from typing import Dict, Optional, Any, List, Union
from typing import Callable, Dict, Optional, Any, List, Union

# account_usage imports the OpenAI SDK chain (~230 ms). Only needed by
# /usage; we still import it at module top in the gateway because test
Expand Down Expand Up @@ -6354,6 +6354,7 @@ async def start(self) -> bool:
adapter.set_session_store(self.session_store)
adapter.set_busy_session_handler(self._handle_active_session_busy_message)
adapter.set_topic_recovery_fn(self._recover_telegram_topic_thread_id)
adapter.set_authorization_check(self._make_adapter_auth_check(adapter.platform))
adapter._busy_text_mode = self._busy_text_mode

# Try to connect
Expand Down Expand Up @@ -7162,6 +7163,7 @@ async def _platform_reconnect_watcher(self) -> None:
adapter.set_session_store(self.session_store)
adapter.set_busy_session_handler(self._handle_active_session_busy_message)
adapter.set_topic_recovery_fn(self._recover_telegram_topic_thread_id)
adapter.set_authorization_check(self._make_adapter_auth_check(adapter.platform))
adapter._busy_text_mode = self._busy_text_mode

# Reconnect after an outage: preserve the platform's
Expand Down Expand Up @@ -7818,6 +7820,7 @@ async def _start_one_profile_adapters(
adapter.set_session_store(self.session_store)
adapter.set_busy_session_handler(self._handle_active_session_busy_message)
adapter.set_topic_recovery_fn(self._recover_telegram_topic_thread_id)
adapter.set_authorization_check(self._make_adapter_auth_check(adapter.platform))
adapter._busy_text_mode = self._busy_text_mode

try:
Expand Down Expand Up @@ -7986,6 +7989,39 @@ def _create_adapter(

return None

def _make_adapter_auth_check(
self,
platform: Platform,
) -> Callable[[str, Optional[str], Optional[str]], bool]:
"""Build a platform-bound auth callback for adapter use.

Adapters that fetch external context (e.g. Slack
``conversations.replies``) call this through
``BasePlatformAdapter._is_sender_authorized`` to mark non-allowlisted
senders as unverified in LLM context, mitigating indirect prompt
injection from third parties in shared threads/channels.

The returned callback delegates to :meth:`_is_user_authorized` so the
full auth chain — platform allowlists, group allowlists, pairing
store, allow-all flags — stays the single source of truth.
"""
def check(
user_id: str,
chat_type: Optional[str] = None,
chat_id: Optional[str] = None,
) -> bool:
if not user_id:
return False
source = SessionSource(
platform=platform,
chat_id=chat_id or "",
chat_type=chat_type or "group",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 _make_adapter_auth_check defaults chat_type to 'group', creating latent allowlist-scope bypass (security)

In gateway/run.py, the _make_adapter_auth_check method (introduced in this PR) constructs a SessionSource with chat_type=chat_type or 'group' (line 8018). When chat_type is not provided by the caller, this defaults to 'group', which causes _is_user_authorized (authz_mixin.py:375-377) to consult group-scoped allowlists (TELEGRAM_GROUP_ALLOWED_USERS and similar platform-specific group user allowlists) and merge their entries into allowed_ids (line 466-467). This means a user who is only on the group allowlist could be authorized for a non-group context. The code's own comment at authz_mixin.py:459-462 explicitly states: 'TELEGRAM_GROUP_ALLOWED_USERS is the scoped allowlist and should not imply DM access.' The default contradicts this intent. Currently, the sole caller (SlackAdapter._fetch_thread_context at adapter.py:3675) always passes chat_type='thread', so the unsafe default is never exercised. However, it creates a latent privilege-escalation path for any future adapter or code path that calls _is_sender_authorized without an explicit chat_type.

💡 Suggestion: Change the default from chat_type or 'group' to chat_type or 'dm' to match SessionSource's own default (session.py:105) and prevent future auth decisions from accidentally using group-scoped allowlists for non-group messages. Alternatively, log a warning when chat_type is not provided to catch callers that should be explicit.

Suggested change
chat_type=chat_type or "group",
chat_type=chat_type or "dm",
📋 Prompt for AI Agents

In gateway/run.py, line 8018, change chat_type=chat_type or "group" to chat_type=chat_type or "dm" so the fallback matches SessionSource's own default ('dm') and does not incorrectly trigger group-scoped authorization paths when a caller omits chat_type.

user_id=user_id,
)
return self._is_user_authorized(source)
return check





Expand Down
3 changes: 2 additions & 1 deletion scripts/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@

# Auto-extracted from noreply emails + manual overrides
AUTHOR_MAP = {
"syahidfrd@gmail.com": "syahidfrd", # PR #17059 salvage (tag unverified senders in Slack thread context to mitigate indirect prompt injection)
"5823452+sgabel@users.noreply.github.com": "sgabel", # PR #13139 salvage (redact secrets in user-facing approval prompts)
"130270192+CRWuTJ@users.noreply.github.com": "CRWuTJ", # PR #17082 salvage (cancel delayed Telegram deliveries on disconnect so buffered flushes don't dispatch into a torn-down session)
"cyb3rwr3n@users.noreply.github.com": "cyb3rwr3n", # PR #11333 salvage (sanitize FTS5 queries for natural-language recall in holographic memory)
"9350182+codexGW@users.noreply.github.com": "codexGW", # PR #12302 salvage (Discord raw <@!ID> mention detection + drop bare mention-only pings)
"186512915+lEWFkRAD@users.noreply.github.com": "lEWFkRAD", # PR #53848 salvage (stream the MoA aggregator response to the user)
Expand Down Expand Up @@ -196,6 +196,7 @@
"290859878+synapsesx@users.noreply.github.com": "synapsesx",
"157689911+itsflownium@users.noreply.github.com": "itsflownium",
"dirtyren@users.noreply.github.com": "dirtyren",
"92324143+ypwcharles@users.noreply.github.com": "ypwcharles",
"mailtowbd@gmail.com": "marco0158",
"157793278+jacobmansonlkevincc@users.noreply.github.com": "lkevincc0",
"121278003+Cossackx@users.noreply.github.com": "Cossackx", # PR #52528 salvage (Windows hermes-shim resolution + prefer --update on recovery; #52378)
Expand Down
Loading