From 82f277480cd219f080c5773bb9a5914f93840609 Mon Sep 17 00:00:00 2001 From: Yilin Jing Date: Wed, 25 Mar 2026 12:06:41 +0800 Subject: [PATCH] fix(sdk): use sender's protocol version for HTTP signature verification verifyHttpRequestHeaders and verifyHttpResponseHeaders hardcoded the local PROTOCOL_VERSION when reconstructing the signing input. When gateway (SDK 1.6) verified requests from worlds (SDK 1.5), the v: field mismatched and signatures always failed with 403. Now both verify functions read X-AgentWorld-Version from the incoming headers and use the sender's version in the signing input, falling back to local PROTOCOL_VERSION when the header is absent. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .changeset/fix-cross-version-sig-verify.md | 5 +++++ packages/agent-world-sdk/src/crypto.ts | 10 ++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 .changeset/fix-cross-version-sig-verify.md diff --git a/.changeset/fix-cross-version-sig-verify.md b/.changeset/fix-cross-version-sig-verify.md new file mode 100644 index 0000000..9191af9 --- /dev/null +++ b/.changeset/fix-cross-version-sig-verify.md @@ -0,0 +1,5 @@ +--- +"@resciencelab/agent-world-sdk": patch +--- + +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. diff --git a/packages/agent-world-sdk/src/crypto.ts b/packages/agent-world-sdk/src/crypto.ts index 8aed34e..164ed14 100644 --- a/packages/agent-world-sdk/src/crypto.ts +++ b/packages/agent-world-sdk/src/crypto.ts @@ -160,9 +160,10 @@ function buildRequestSigningInput(opts: { authority: string; path: string; contentDigest: string; + v?: string; }): Record { return { - v: PROTOCOL_VERSION, + v: opts.v ?? PROTOCOL_VERSION, from: opts.from, kid: opts.kid, ts: opts.ts, @@ -232,6 +233,7 @@ export function verifyHttpRequestHeaders( const kid = h["x-agentworld-keyid"] as string | undefined; const ts = h["x-agentworld-timestamp"] as string | undefined; const cd = h["content-digest"] as string | undefined; + const senderVersion = h["x-agentworld-version"] as string | undefined; if (!sig || !from || !kid || !ts || !cd) { return { ok: false, error: "Missing required AgentWorld headers" }; @@ -258,6 +260,7 @@ export function verifyHttpRequestHeaders( authority, path, contentDigest: cd, + v: senderVersion, }); const ok = verifyWithDomainSeparator( DOMAIN_SEPARATORS.HTTP_REQUEST, @@ -287,9 +290,10 @@ function buildResponseSigningInput(opts: { ts: string; status: number; contentDigest: string; + v?: string; }): Record { return { - v: PROTOCOL_VERSION, + v: opts.v ?? PROTOCOL_VERSION, from: opts.from, kid: opts.kid, ts: opts.ts, @@ -351,6 +355,7 @@ export function verifyHttpResponseHeaders( const kid = h["x-agentworld-keyid"]; const ts = h["x-agentworld-timestamp"]; const cd = h["content-digest"]; + const senderVersion = h["x-agentworld-version"]; if (!sig || !from || !kid || !ts || !cd) { return { ok: false, error: "Missing required AgentWorld response headers" }; @@ -375,6 +380,7 @@ export function verifyHttpResponseHeaders( ts, status, contentDigest: cd, + v: senderVersion ?? undefined, }); const ok = verifyWithDomainSeparator( DOMAIN_SEPARATORS.HTTP_RESPONSE,