fix(security): require source CIDR allowlisting for public msgraph webhook binds
This commit is contained in:
@@ -25,6 +25,7 @@ from gateway.platforms.base import (
|
||||
MessageEvent,
|
||||
MessageType,
|
||||
SendResult,
|
||||
is_network_accessible,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -132,12 +133,24 @@ class MSGraphWebhookAdapter(BasePlatformAdapter):
|
||||
def set_notification_scheduler(self, scheduler: Optional[NotificationScheduler]) -> None:
|
||||
self._notification_scheduler = scheduler
|
||||
|
||||
def _source_allowlist_required_but_missing(self) -> bool:
|
||||
return is_network_accessible(self._host) and not self._allowed_source_networks
|
||||
|
||||
async def connect(self) -> bool:
|
||||
if self._client_state is None:
|
||||
logger.error(
|
||||
"[msgraph_webhook] Refusing to start without extra.client_state configured"
|
||||
)
|
||||
return False
|
||||
if self._source_allowlist_required_but_missing():
|
||||
logger.error(
|
||||
"[msgraph_webhook] Refusing to start: binding to %s requires "
|
||||
"extra.allowed_source_cidrs. Configure the Microsoft Graph "
|
||||
"source CIDRs or bind to loopback (127.0.0.1/::1) behind a "
|
||||
"tunnel or reverse proxy.",
|
||||
self._host,
|
||||
)
|
||||
return False
|
||||
|
||||
app = web.Application()
|
||||
app.router.add_get(self._health_path, self._handle_health)
|
||||
@@ -177,6 +190,8 @@ class MSGraphWebhookAdapter(BasePlatformAdapter):
|
||||
return {"name": chat_id, "type": "webhook"}
|
||||
|
||||
async def _handle_health(self, request: "web.Request") -> "web.Response":
|
||||
if not self._source_ip_allowed(request):
|
||||
return web.Response(status=403)
|
||||
return web.json_response(
|
||||
{
|
||||
"status": "ok",
|
||||
@@ -271,9 +286,12 @@ class MSGraphWebhookAdapter(BasePlatformAdapter):
|
||||
def _source_ip_allowed(self, request: "web.Request") -> bool:
|
||||
"""Return True if the request's source IP is in the configured allowlist.
|
||||
|
||||
When ``allowed_source_cidrs`` is empty (the default), everything is
|
||||
allowed — preserves behavior for dev tunnels / localhost setups.
|
||||
Loopback-only binds may omit ``allowed_source_cidrs`` for local reverse
|
||||
proxies and dev tunnels. Network-accessible binds fail closed until an
|
||||
explicit CIDR allowlist is configured.
|
||||
"""
|
||||
if self._source_allowlist_required_but_missing():
|
||||
return False
|
||||
if not self._allowed_source_networks:
|
||||
return True
|
||||
peer = request.remote or ""
|
||||
|
||||
Reference in New Issue
Block a user