mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-01 12:02:05 +00:00
fix(matrix,mattermost): invite auth check + API path traversal guard
Two platform-security hardenings: - Matrix: _on_invite now checks the inviter against the existing allow-list (_allowed_user_ids / GATEWAY_ALLOW_ALL_USERS) before auto-joining. Without this any federated Matrix user could invite the bot into arbitrary rooms, exposing its presence and metadata. The message and reaction paths already enforce this allow-list; the invite path bypassed it. - Mattermost: _api_get / _api_post / _api_put reject any path containing '..'. WebSocket-event values (channel_id, post_id, file_id) are interpolated directly into API paths, so a malicious or compromised server could craft traversal payloads to make the bot issue authenticated requests to arbitrary endpoints with its bearer token. The configurable-E2EE-passphrase change from the original PR is dropped: the matrix adapter was rewritten onto mautrix and the passphrase-protected key-export file no longer exists.
This commit is contained in:
parent
9cf9d3a28f
commit
d836b2bac4
2 changed files with 28 additions and 0 deletions
|
|
@ -2892,6 +2892,25 @@ class MatrixAdapter(BasePlatformAdapter):
|
|||
is_direct = bool(getattr(content, "is_direct", False))
|
||||
inviter = str(getattr(event, "sender", ""))
|
||||
|
||||
# Only auto-join when the inviter is authorized. Without this, any
|
||||
# federated Matrix user could invite the bot into arbitrary rooms,
|
||||
# exposing its presence and metadata. Mirrors the allow-list gate
|
||||
# used on the message/reaction paths.
|
||||
allow_all = os.getenv("GATEWAY_ALLOW_ALL_USERS", "").lower() in {
|
||||
"true",
|
||||
"1",
|
||||
"yes",
|
||||
}
|
||||
if not allow_all and not (
|
||||
self._allowed_user_ids and inviter in self._allowed_user_ids
|
||||
):
|
||||
logger.warning(
|
||||
"Matrix: rejecting invite to %s from unauthorized user %s",
|
||||
room_id,
|
||||
inviter,
|
||||
)
|
||||
return
|
||||
|
||||
logger.info(
|
||||
"Matrix: invited to %s — joining (is_direct=%s)",
|
||||
room_id,
|
||||
|
|
|
|||
|
|
@ -117,6 +117,9 @@ class MattermostAdapter(BasePlatformAdapter):
|
|||
async def _api_get(self, path: str) -> Dict[str, Any]:
|
||||
"""GET /api/v4/{path}."""
|
||||
import aiohttp
|
||||
if ".." in path:
|
||||
logger.error("MM API path traversal blocked: %s", path)
|
||||
return {}
|
||||
url = f"{self._base_url}/api/v4/{path.lstrip('/')}"
|
||||
try:
|
||||
async with self._session.get(url, headers=self._headers(), timeout=aiohttp.ClientTimeout(total=30)) as resp:
|
||||
|
|
@ -134,6 +137,9 @@ class MattermostAdapter(BasePlatformAdapter):
|
|||
) -> Dict[str, Any]:
|
||||
"""POST /api/v4/{path} with JSON body."""
|
||||
import aiohttp
|
||||
if ".." in path:
|
||||
logger.error("MM API path traversal blocked: %s", path)
|
||||
return {}
|
||||
url = f"{self._base_url}/api/v4/{path.lstrip('/')}"
|
||||
self._last_post_status = None
|
||||
self._last_post_error = ""
|
||||
|
|
@ -213,6 +219,9 @@ class MattermostAdapter(BasePlatformAdapter):
|
|||
) -> Dict[str, Any]:
|
||||
"""PUT /api/v4/{path} with JSON body."""
|
||||
import aiohttp
|
||||
if ".." in path:
|
||||
logger.error("MM API path traversal blocked: %s", path)
|
||||
return {}
|
||||
url = f"{self._base_url}/api/v4/{path.lstrip('/')}"
|
||||
try:
|
||||
async with self._session.put(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue