Skip to content

fix(paymaster): verify the signed hash is the expected outside execution - #1734

Merged
PhilippeR26 merged 1 commit into
starknet-io:developfrom
PhilippeR26:fix/snip29verification-message
Oct 20, 2026
Merged

PhilippeR26 merged 1 commit into
starknet-io:developfrom
PhilippeR26:fix/snip29verification-message

Conversation

@PhilippeR26

Copy link
Copy Markdown
Collaborator

Motivation and Resolution

When paying through a SNIP-29 paymaster, the SDK receives a SNIP-9 typed data to sign, checks it, then signs it. The check read fields of the returned message — but the account signs a hash, and that hash covers only the fields declared in the message's own types list, which the paymaster controls. So a malicious or compromised paymaster could get one call array checked while a different, renamed array was the one actually signed, or get the user's calls checked inside a message of another kind (for example a session key) that was signed in their place. The caller and the time bounds were not checked either.

assertPaymasterTransactionSafety now rebuilds the outside execution it expects — from the SDK's own SNIP-9 shape, the provider chain and the user's own calls — and refuses the transaction when the hash the account would sign differs from the one the paymaster returned. When the user passes timeBounds, the signed execution window must stay inside the requested one. The check also moved into preparePaymasterTransaction, so a flow built on the lower-level methods is protected too. This continues the hardening of the paymaster check started in 10.7.2 (#1694).

RPC version (if applicable)

No change. RPC spec versions 0.9 and 0.10.x remain supported.

Usage related changes

  • A paymaster transaction is now refused when the hash to sign is not the outside execution built from the user's own calls — a renamed signed field, or a foreign message carrying the user's calls as an unsigned facade.
  • With timeBounds, the signed execution window must stay inside the requested one, or the transaction is refused. Without timeBounds the window is not constrained.
  • preparePaymasterTransaction now takes (preparedTransaction, calls, paymasterDetails, maxFeeInGasToken?) and runs the safety check itself. Only code calling this lower-level method directly is affected; executePaymasterTransaction is unchanged. Documented in the v10 to v11 migration guide, section 14.

Development related changes

  • __tests__/accountPaymaster.test.ts: the base typed data is now a real SNIP-9 outside execution, and four cases were added — a renamed signed field, a foreign message, an execution window past the requested bounds, and a window inside them.

Checklist:

  • Performed a self-review of the code
  • Rebased to the last commit of the target branch (or merged it into my branch)
  • Documented the changes in code (API docs will be generated automatically)
  • Updated the tests
  • All tests are passing

The paymaster safety check read fields of the returned message, but the account signs a hash that covers only the fields the paymaster's own types list declares. A paymaster could therefore get one call array checked while a different, renamed array was the one actually signed, or get the user calls checked inside a message of another kind that was signed in their place. assertPaymasterTransactionSafety now rebuilds the outside execution it expects from the SDK's own SNIP-9 shape, the provider chain and the user calls, and refuses the transaction when the hash the account would sign differs from the one the paymaster returned.

When the user passes timeBounds, the signed execution window must now stay inside the requested one.

The check also moved into preparePaymasterTransaction, so a flow built on the lower-level methods is protected too: it now takes the user calls and the fee details, and executePaymasterTransaction delegates to it. This changes the signature of preparePaymasterTransaction; see the v10 to v11 migration guide, section 14.
@PhilippeR26
PhilippeR26 merged commit e16ca5e into starknet-io:develop Oct 20, 2026
9 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 11.4.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant