mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-20 15:33:54 +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
|
|
@ -316,8 +316,30 @@ class TestMSGraphNotifications:
|
|||
|
||||
assert calls, "hmac.compare_digest was never called; clientState check is not timing-safe"
|
||||
provided, expected = calls[0]
|
||||
assert provided == "expected-client-state"
|
||||
assert expected == "expected-client-state"
|
||||
assert provided == b"expected-client-state"
|
||||
assert expected == b"expected-client-state"
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_non_ascii_client_state_rejected_without_raising(self):
|
||||
"""A non-ASCII clientState (attacker-controlled request body) must be
|
||||
rejected with 403, not crash the handler: hmac.compare_digest raises
|
||||
TypeError on a str containing non-ASCII characters."""
|
||||
adapter = _make_adapter()
|
||||
payload = {
|
||||
"value": [
|
||||
{
|
||||
"id": "notif-nonascii",
|
||||
"subscriptionId": "sub-1",
|
||||
"changeType": "updated",
|
||||
"resource": "communications/onlineMeetings/meeting-x",
|
||||
"clientState": "ské-not-the-secret",
|
||||
}
|
||||
]
|
||||
}
|
||||
response = await adapter._handle_notification(
|
||||
_FakeRequest(json_payload=payload)
|
||||
)
|
||||
assert response.status == 403
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_duplicate_notification_deduped(self):
|
||||
|
|
|
|||
|
|
@ -353,6 +353,22 @@ class TestWebhookVerify:
|
|||
|
||||
assert response.status == 403
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_verify_rejects_non_ascii_token_without_raising(self):
|
||||
"""A non-ASCII verify_token (raw query param) must be rejected with
|
||||
403, not crash the handler: hmac.compare_digest raises TypeError on a
|
||||
str containing non-ASCII characters."""
|
||||
adapter = _make_adapter(verify_token="shared-secret-123")
|
||||
request = _verify_request({
|
||||
"hub.mode": "subscribe",
|
||||
"hub.verify_token": "ské-not-the-secret",
|
||||
"hub.challenge": "abc-12345",
|
||||
})
|
||||
|
||||
response = await adapter._handle_verify(request)
|
||||
|
||||
assert response.status == 403
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_verify_rejects_wrong_mode(self):
|
||||
adapter = _make_adapter(verify_token="shared-secret-123")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue