fix(msteams): trust service URLs before replies

This commit is contained in:
hinotoi-agent
2026-05-29 16:46:46 +08:00
committed by Xubin Ren
parent 9d3fe7c34b
commit 5734c17ee0
2 changed files with 97 additions and 0 deletions
+51
View File
@@ -434,6 +434,38 @@ async def test_handle_activity_denied_sender_does_not_store_ref(make_channel, tm
assert not (tmp_path / "state" / "msteams_conversations.json").exists()
@pytest.mark.asyncio
async def test_handle_activity_rejects_untrusted_service_url(make_channel, tmp_path):
ch = make_channel(validateInboundAuth=False, allowFrom=["*"])
activity = {
"type": "message",
"id": "activity-poison",
"text": "Hello from forged Teams activity",
"serviceUrl": "https://attacker.example/collect",
"channelId": "msteams",
"conversation": {
"id": "conv-poison",
"conversationType": "personal",
},
"from": {
"id": "29:attacker-user-id",
"aadObjectId": "attacker-user-id",
"name": "Attacker",
},
"recipient": {
"id": "28:bot-id",
"name": "nanobot",
},
}
await ch._handle_activity(activity)
assert ch.bus.inbound == []
assert ch._conversation_refs == {}
assert not (tmp_path / "state" / "msteams_conversations.json").exists()
@pytest.mark.asyncio
async def test_handle_activity_mention_only_uses_default_response(make_channel):
ch = make_channel()
@@ -739,6 +771,25 @@ async def test_send_raises_when_conversation_ref_missing(make_channel):
await ch.send(OutboundMessage(channel="msteams", chat_id="missing", content="Reply text"))
@pytest.mark.asyncio
async def test_send_rejects_untrusted_service_url_before_bearer_post(make_channel):
ch = make_channel()
fake_http = FakeHttpClient()
ch._http = fake_http
ch._token = "tok"
ch._token_expires_at = 9999999999
ch._conversation_refs["conv-poison"] = ConversationRef(
service_url="https://attacker.example/collect",
conversation_id="conv-poison",
activity_id="activity-poison",
)
with pytest.raises(RuntimeError, match="untrusted service_url"):
await ch.send(OutboundMessage(channel="msteams", chat_id="conv-poison", content="Reply text"))
assert fake_http.calls == []
@pytest.mark.asyncio
async def test_send_raises_delivery_failures_for_retry(make_channel):
ch = make_channel()