Skip to content

fix: validate signature inputs across Keypair.verify and authorizeEntry - #1649

Merged
quietbits merged 5 commits into
mainfrom
issue-1639-keypair-verify
Aug 14, 2026
Merged

fix: validate signature inputs across Keypair.verify and authorizeEntry#1649
quietbits merged 5 commits into
mainfrom
issue-1639-keypair-verify

Conversation

@quietbits

@quietbits quietbits commented Aug 14, 2026

Copy link
Copy Markdown
Contributor
  • Fixed Keypair.verify and verifyMessage reporting a valid signature as invalid when handed the xdr.Signature wrapper that DecoratedSignature.signature holds — kp.verify(tx.hash(), tx.signatures[0].signature) returned false
  • Changed both to throw a TypeError for arguments whose type they don't accept instead of returning false — breaking, and the reason the above went unnoticed: a caller mistake was indistinguishable from a forgery. verify takes data as a Uint8Array and signature as a Uint8Array or xdr.Signature; verifyMessage takes the same signature plus a string or Uint8Array message. A base64 signature string, a plain number[], or the whole xdr.DecoratedSignature now throws, and signMessage does the same for a message that is neither string nor bytes
  • Fixed authorizeEntry accepting a signatureScVal that isn't an xdr.ScVal, which produced a signed-looking entry that only failed later at toXdr(). The value is round-tripped through the local ScVal schema, so a lookalike carrying the brand but not encoding as an ScVal is rejected at the call, and the credential stores a locally rebuilt value rather than the caller's object
  • Added validation of the signature and publicKey a signer returns, where the callback and signer-object paths converge — nothing checked them before, so a wrong shape drew a misleading signature doesn't match payload, and once verify learned to accept xdr.Signature, a wrapper would have reached nativeToScVal two layers down instead
  • Matched the xdr.Signature and xdr.ScVal wrappers structurally instead of with instanceof, and byte arrays with isUint8Array, so values from another realm or a second copy of the SDK in one process still work
  • Added a compile-time type test locking which signature types verify and verifyMessage accept
  • Rewrote the @throws docs for verify, verifyMessage and signMessage to name the accepted and rejected types — the old wording contradicted a string message and an xdr.Signature — and regenerated docs/reference/

Copilot AI balanced review requested due to automatic review settings August 14, 2026 01:27
@github-project-automation github-project-automation Bot moved this to Backlog (Not Ready) in DevX Aug 14, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds stricter signature validation while supporting XDR signature wrappers across SDK instances.

Changes:

  • Accepts xdr.Signature in verification APIs.
  • Validates signer outputs and custom authorization ScVal values.
  • Adds runtime/type tests and updates generated references and changelog.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/base/keypair.ts Validates verification inputs and unwraps signatures.
src/base/auth.ts Validates authorization signer results.
test/unit/base/keypair.test.ts Tests verification input behavior.
test/unit/base/auth.test.ts Tests authorization validation.
test/types/keypair-verify.ts Locks accepted verification types.
docs/reference/core-keys.md Updates generated key API reference.
docs/reference/core-soroban-primitives.md Refreshes generated source links.
CHANGELOG.md Documents breaking validation changes.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/base/auth.ts Outdated
Comment thread src/base/keypair.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/base/keypair.ts:323

  • A structurally branded object with a callable toBytes can still throw from that method (or from a getter used by isSignature). Because extraction happens before the validation/catch, that arbitrary error escapes instead of the documented TypeError for an unusable signature input. Normalize extraction failures through the same type guard error.
    const signatureBytes = isSignature(signature)
      ? signature.toBytes()
      : signature;

src/base/auth.ts:91

  • The try only covers invoking toXdrObject; a throwing constructor or toXdrObject getter escapes directly. Such a malformed branded value therefore bypasses the intended signatureScVal must be an xdr.ScVal TypeError, even though an equally unusable throwing method is normalized correctly. Include all structural property access in the guarded block.
  const ctor = value.constructor as { schema?: { name?: string } } | undefined;
  if (ctor?.schema?.name !== ScVal.schema.name) return null;
  const toXdrObject = (value as { toXdrObject?: () => ScValWire }).toXdrObject;

@quietbits
quietbits requested a review from Ryang-21 August 14, 2026 13:41
Comment thread CHANGELOG.md
@quietbits
quietbits merged commit a02b264 into main Aug 14, 2026
16 checks passed
@quietbits
quietbits deleted the issue-1639-keypair-verify branch August 14, 2026 18:16
@github-project-automation github-project-automation Bot moved this from Backlog (Not Ready) to Done in DevX Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

XDR byte fields of named typedef types are wrapper objects, not Uint8Array

3 participants