Skip to content

fix(sdk-js): decode v0 hex strictly instead of silently truncating - #1347

Merged
kvinwang merged 1 commit into
nextfrom
fix/sdk-js-v0-strict-hex
Sep 24, 2026
Merged

kvinwang merged 1 commit into
nextfrom
fix/sdk-js-v0-strict-hex

Conversation

@kvinwang

@kvinwang kvinwang commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Buffer.from(s, 'hex') stops at the first invalid pair and returns the prefix without error. A v0 GetKey response with junk after valid digits yielded a truncated but plausible key, and toViemAccount turned it into a working account at an address nobody chose. Rust, Python and Go all reject the same input.

Also: a null signature_chain threw a bare TypeError naming no field, and a non-string tcb_info was returned typed as TcbInfo.

Fix

Move v1's strict decoders (unchanged) into shared.ts and use them from v0 as well.

Compatibility

  • Malformed hex, a missing signature_chain, and a non-string tcb_info now throw. The values previously returned were unusable (a truncated private key, a number typed as TcbInfo).
  • v0 getKey, info and sign now call throwOnRpcError like the other v0 methods, so an RPC error response throws instead of being decoded as a result.

Well-formed responses, empty hex and empty chains are unchanged.

Verification

sdk/js: 164 passed against the simulator (13 new).

Split out of #1281.

Node's hex decoder stops at the first pair it cannot parse and returns the
prefix, with no error. A `GetKey` response whose 64 valid digits are followed
by junk therefore yielded a plausible 32-byte `key`, and `toViemAccount` turned
that into a working account at an address nobody chose. Rust, Python and Go all
refuse the identical response.

v1 already guards this (`decode_hex` in `client-v1.ts`); the frozen v0 client
never got the same treatment. Move v1's decoders into `shared.ts` -- which
exists for exactly this -- and use them from both surfaces, so the two cannot
drift again.

Also from the same pass: a null or absent `signature_chain` threw a bare
`TypeError: Cannot read properties of null (reading 'map')`, which names no
field and reads like an SDK bug; and `info()` accepted a numeric `tcb_info`,
because `JSON.parse` stringifies its argument, handing back `42` typed as
`TcbInfo` with every `.mrtd` read `undefined`.

Compat: this rejects three response shapes that previously returned a value --
malformed hex, a missing repeated field, and a non-string `tcb_info`. In every
case the value returned was unusable (a truncated private key, an empty chain,
a number typed as a struct), so no working application can depend on it. A
well-formed response, an empty hex string and an empty chain are unchanged.

`getKey`, `info` and `sign` now call `throwOnRpcError` like the rest of v0,
so an RPC error response throws instead of being decoded as a result.
@kvinwang
kvinwang force-pushed the fix/sdk-js-v0-strict-hex branch from 6d5cef9 to 6fce643 Compare September 24, 2026 05:21
@kvinwang
kvinwang merged commit 2efe14a into next Sep 24, 2026
7 checks passed
@kvinwang
kvinwang deleted the fix/sdk-js-v0-strict-hex branch September 24, 2026 05:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant