microsoft / microsoft/agent-governance-toolkit

AgentMesh relay: connect-frame DID proof-of-possession is replayable within its 5-minute window

Open
#3,525 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
6.3k
Forks
1.1k
Avg merge
5d 11h
Merged PRs (30d)
142

Description

### Summary

`_verify_connect_pop` in `agent-governance-python/agent-mesh/src/agentmesh/relay/app.py` signs
only an ISO-8601 timestamp and accepts it inside a ±5 minute window
(`DID_POP_REPLAY_WINDOW`). The signature is not bound to a server-issued nonce, to the relay
URL, or to the TLS channel, so a captured `connect` frame can be replayed within that window
to authenticate as the captured DID.

### Why it matters

A replayed connect frame *owns* the mailbox, so it passes every downstream identity check:

- it satisfies the recipient-ownership check on `ack`, so it can acknowledge and therefore
delete the victim's queued messages;
- it satisfies the frame `from`-binding, so it can emit frames as the victim;
- it displaces the victim's live socket.

Note this is not a weakness in those controls — they are working as designed against a
connection the relay considers authenticated. The gap is upstream, in what "authenticated"
means at connect time.

### Suggested fix

Either of:

1. **Challenge-response nonce.** Relay sends a random nonce on connect; the client signs it.
2. **Bind the proof to the channel.** Sign `relay_url || nonce` (or a TLS exporter value)
instead of a bare timestamp.

Both change the connect handshake on the client and the relay, so this needs its own change
with a compatibility story for existing clients.

### Current mitigations

- TLS is required in production, which prevents passive capture of connect frames on the wire.
- As of #3411 a displaced socket is closed with `WS_CLOSE_SESSION_REPLACED` (4006) instead of
`1000`, and the client raises it through `onError`, so the displacement is now observable
rather than silent. That is detection only — it does not prevent the takeover.

### Provenance

Raised by @MohammadHaroonAbuomar in review of #3411, who confirmed it with a probe
(mailbox takeover + queued-mail deletion) and asked for it to be filed separately as
pre-existing. Recorded under "Known gaps" in
`docs/security/audits/2026-07-21-agentmesh-message-authentication-hardening.md`.

Contributor guide

Open the contributing guide

Research direction

Start at _verify_connect_pop in agent-governance-python/agent-mesh/src/agentmesh/relay/app.py and inspect how DID_POP_REPLAY_WINDOW is applied during the connect handshake. Review the corresponding client and relay handshake paths, then define completion as a proof bound to a nonce or channel context with existing-client compatibility addressed.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
authentication, backend, security
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.