mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-21 16:18:55 +00:00
fix(security): widen non-ASCII compare_digest crash fix to all sibling sites
Same bug class as the salvaged #65305/#65307: hmac.compare_digest (and secrets.compare_digest) raise TypeError when given a str containing non-ASCII characters, and these call sites feed it raw request input. Compare as UTF-8 bytes everywhere: - gateway/platforms/msgraph_webhook.py: clientState from request body - gateway/platforms/whatsapp_cloud.py: hub.verify_token query param + X-Hub-Signature-256 header (comment claimed 'works on str' — it doesn't for non-ASCII) - plugins/platforms/feishu: verification token + x-lark-signature - plugins/platforms/raft: bridge token header - plugins/platforms/line: X-Line-Signature - plugins/platforms/sms: X-Twilio-Signature - tools/code_execution_tool.py: sandbox RPC token (both loops) Regression tests for the two gateway-core sites (msgraph, whatsapp).
This commit is contained in:
parent
4ccb232af9
commit
a6d9d1d2cf
9 changed files with 76 additions and 13 deletions
|
|
@ -3512,7 +3512,11 @@ class FeishuAdapter(BasePlatformAdapter):
|
|||
if self._verification_token:
|
||||
header = payload.get("header") or {}
|
||||
incoming_token = str(header.get("token") or payload.get("token") or "")
|
||||
if not incoming_token or not hmac.compare_digest(incoming_token, self._verification_token):
|
||||
# Compare as bytes: compare_digest raises TypeError on a str with
|
||||
# non-ASCII characters, and the token comes from the request body.
|
||||
if not incoming_token or not hmac.compare_digest(
|
||||
incoming_token.encode(), self._verification_token.encode()
|
||||
):
|
||||
logger.warning("[Feishu] Webhook rejected: invalid verification token from %s", remote_ip)
|
||||
self._record_webhook_anomaly(remote_ip, "401-token")
|
||||
return web.Response(status=401, text="Invalid verification token")
|
||||
|
|
@ -3575,7 +3579,9 @@ class FeishuAdapter(BasePlatformAdapter):
|
|||
body_str = body_bytes.decode("utf-8", errors="replace")
|
||||
content = f"{timestamp}{nonce}{self._encrypt_key}{body_str}"
|
||||
computed = hashlib.sha256(content.encode("utf-8")).hexdigest()
|
||||
return hmac.compare_digest(computed, signature)
|
||||
# Compare as bytes: compare_digest raises TypeError on a str with
|
||||
# non-ASCII characters, and the signature is a raw request header.
|
||||
return hmac.compare_digest(computed.encode(), signature.encode())
|
||||
except Exception:
|
||||
logger.debug("[Feishu] Signature verification raised an exception", exc_info=True)
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -273,7 +273,9 @@ def verify_line_signature(body: bytes, signature: str, channel_secret: str) -> b
|
|||
expected = base64.b64encode(digest).decode("utf-8")
|
||||
except Exception:
|
||||
return False
|
||||
return hmac.compare_digest(expected, signature)
|
||||
# Compare as bytes: compare_digest raises TypeError on a str with
|
||||
# non-ASCII characters, and the signature is a raw request header.
|
||||
return hmac.compare_digest(expected.encode(), signature.encode())
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -692,7 +692,9 @@ class RaftAdapter(BasePlatformAdapter):
|
|||
def _validate_bridge_token(self, token: str) -> bool:
|
||||
if not self._bridge_token or not token:
|
||||
return False
|
||||
return hmac.compare_digest(token, self._bridge_token)
|
||||
# Compare as bytes: compare_digest raises TypeError on a str with
|
||||
# non-ASCII characters, and the token is a raw request header.
|
||||
return hmac.compare_digest(token.encode(), self._bridge_token.encode())
|
||||
|
||||
async def _accept_wake(self, payload: Dict[str, Any]) -> bool:
|
||||
if not self._message_handler:
|
||||
|
|
|
|||
|
|
@ -257,7 +257,9 @@ class SmsAdapter(BasePlatformAdapter):
|
|||
hashlib.sha1,
|
||||
)
|
||||
computed = base64.b64encode(mac.digest()).decode("utf-8")
|
||||
return hmac.compare_digest(computed, signature)
|
||||
# Compare as bytes: compare_digest raises TypeError on a str with
|
||||
# non-ASCII characters, and the signature is a raw request header.
|
||||
return hmac.compare_digest(computed.encode(), signature.encode())
|
||||
|
||||
@staticmethod
|
||||
def _port_variant_url(url: str) -> str | None:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue