Skip to content

Commit ac97d0e

Browse files
fix(sdk): use sender's protocol version for HTTP signature verification (#171)
## Summary `verifyHttpRequestHeaders` and `verifyHttpResponseHeaders` hardcoded the local `PROTOCOL_VERSION` (derived from the SDK's own semver) when reconstructing the signing input for verification. When the gateway (SDK 1.6, `v: "1.6"`) verified requests from worlds running SDK 1.5 (`v: "1.5"`), the `v:` field in the reconstructed signing input mismatched the one the sender actually signed, causing **every signature to fail with 403**. ## Root Cause `buildRequestSigningInput` and `buildResponseSigningInput` always used: ```ts v: PROTOCOL_VERSION // local SDK version, e.g. "1.6" ``` But the sender signed with their own version (e.g. `"1.5"`), sent via the `X-AgentWorld-Version` header. The verifier ignored that header. ## Fix Both verify functions now: 1. Extract `X-AgentWorld-Version` from incoming headers 2. Pass it to the signing input builder as `v:` 3. Fall back to local `PROTOCOL_VERSION` when the header is absent This ensures cross-version compatibility: a gateway on SDK 1.6 can verify requests from worlds on SDK 1.5 (or any other version). ## Testing - 203/203 tests pass - Build succeeds for both root and SDK packages Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
1 parent 0b02d8b commit ac97d0e

2 files changed

Lines changed: 13 additions & 2 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@resciencelab/agent-world-sdk": patch
3+
---
4+
5+
Fix cross-version HTTP signature verification: use sender's X-AgentWorld-Version header instead of local PROTOCOL_VERSION when reconstructing signing input, so gateway and peers running different SDK minor versions can still verify each other's signatures.

packages/agent-world-sdk/src/crypto.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,10 @@ function buildRequestSigningInput(opts: {
160160
authority: string;
161161
path: string;
162162
contentDigest: string;
163+
v?: string;
163164
}): Record<string, string> {
164165
return {
165-
v: PROTOCOL_VERSION,
166+
v: opts.v ?? PROTOCOL_VERSION,
166167
from: opts.from,
167168
kid: opts.kid,
168169
ts: opts.ts,
@@ -232,6 +233,7 @@ export function verifyHttpRequestHeaders(
232233
const kid = h["x-agentworld-keyid"] as string | undefined;
233234
const ts = h["x-agentworld-timestamp"] as string | undefined;
234235
const cd = h["content-digest"] as string | undefined;
236+
const senderVersion = h["x-agentworld-version"] as string | undefined;
235237

236238
if (!sig || !from || !kid || !ts || !cd) {
237239
return { ok: false, error: "Missing required AgentWorld headers" };
@@ -258,6 +260,7 @@ export function verifyHttpRequestHeaders(
258260
authority,
259261
path,
260262
contentDigest: cd,
263+
v: senderVersion,
261264
});
262265
const ok = verifyWithDomainSeparator(
263266
DOMAIN_SEPARATORS.HTTP_REQUEST,
@@ -287,9 +290,10 @@ function buildResponseSigningInput(opts: {
287290
ts: string;
288291
status: number;
289292
contentDigest: string;
293+
v?: string;
290294
}): Record<string, unknown> {
291295
return {
292-
v: PROTOCOL_VERSION,
296+
v: opts.v ?? PROTOCOL_VERSION,
293297
from: opts.from,
294298
kid: opts.kid,
295299
ts: opts.ts,
@@ -351,6 +355,7 @@ export function verifyHttpResponseHeaders(
351355
const kid = h["x-agentworld-keyid"];
352356
const ts = h["x-agentworld-timestamp"];
353357
const cd = h["content-digest"];
358+
const senderVersion = h["x-agentworld-version"];
354359

355360
if (!sig || !from || !kid || !ts || !cd) {
356361
return { ok: false, error: "Missing required AgentWorld response headers" };
@@ -375,6 +380,7 @@ export function verifyHttpResponseHeaders(
375380
ts,
376381
status,
377382
contentDigest: cd,
383+
v: senderVersion ?? undefined,
378384
});
379385
const ok = verifyWithDomainSeparator(
380386
DOMAIN_SEPARATORS.HTTP_RESPONSE,

0 commit comments

Comments
 (0)