fix(aztec-nr)!: domain-separate account entrypoint authorization from generic authwits - #25166
Draft
vezenovm wants to merge 1 commit into
Draft
Conversation
…uthwits
The account entrypoint wrapped its payload hash with the generic authwit outer hash
(compute_authwit_message_hash / computeOuterAuthWitHash). That put the authorized
message in the image of the generic authwit path: a createAuthWit over
{ consumer: account, innerHash: <entrypoint payload hash> } produces exactly the
message the entrypoint validates, so a party able to request a generic authwit from
the account could mint an entrypoint authorization for a call list of its choosing.
The entrypoint now wraps the payload hash with a dedicated entrypoint_message domain
separator (compute_entrypoint_message_hash), moving the authorized message out of the
generic authwit image. compute_authwit_message_hash and verify_private_authwit are left
untouched, so the pinned AuthRegistry is unaffected (no standard-contract re-pin).
vezenovm
force-pushed
the
mv/f-844-domain-separate-entrypoint-message
branch
from
August 10, 2026 21:34
64e209a to
6ba76e3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #25157 (F-841). Breaking: changes the entrypoint authorization preimage.
Bug: the entrypoint wrapped its payload hash with the generic authwit outer hash, so
createAuthWit({ consumer: account, innerHash })mints the exact message the entrypoint validates, forging an entrypoint authorization for any calls.Exploit (pre-fix):
payload = AppPayload{calls: [Token.transfer(attacker, ALL)]}, thenX = poseidon2([payload.hash(), EXTERNAL, false], ENTRYPOINT_PAYLOAD_SEP).wallet.createAuthWit({ consumer: victimAccount, innerHash: X }). To the wallet this reads as "authorize consumer=self over opaque hash0x…": a self-authwit, not a transaction.IntentInnerHashbranch (authwit.ts:96) the message =computeOuterAuthWitHash(victimAccount, chainId, version, X): exactly what the pre-fix entrypoint validates.victimAccount.entrypoint(payload, EXTERNAL, false)with that witness.is_valid_implfinds the signature overmessage_hash→ passes.Fix: wrap with a dedicated
entrypoint_messagedomain separator, so the generic authwit path can no longer produce the entrypoint message.Likelihood & design: Low likelihood — a wallet talking to a dApp usually already trusts it, and the only gate is the sign step (step 2): the attacker submits the
entrypointtx himself, so there is no second prompt to catch it. The value is making the capability boundary explicit. The dApp-facingcreateAuthWitis structured-only (IntentInnerHash | CallIntent,wallet.ts:306), so post-fix every authwit it can request isAUTHWIT_OUTER-wrapped and disjoint from the entrypoint message; a wallet that scopescreateAuthWitbelowsendTxnow actually gets that separation. Posture: keep structured authwits narrowly scoped, treat raw opaque signing as high privilege (the fix cannot help a bare-field signer), domain-separate entrypoint authorization so the scopes cannot collapse cryptographically. If authwits instead stayed opaque and unscoped, equating the two capabilities would be the conservative alternative.Root cause: at the protocol layer the entrypoint authorization is an authwit (
consumer = the account). Authwits being separate from tx authority was a wallet-layer intention the protocol never enforced, so a generic app approval could carry the weight of a whole-account tx. Now enforced cryptographically.Change:
DOM_SEP__ENTRYPOINT_MESSAGE;AccountActions::entrypointusescompute_entrypoint_message_hash.DefaultAccountEntrypoint(computeEntrypointMessageHash).compute_authwit_message_hash/verify_private_authwituntouched, so no AuthRegistry re-pin.AccountActionson recompile.Exposure (ranked):
createAuthWitgated weaker thansendTx: directly exposed pre-fix; closed post-fix (structured authwits can no longer reach the entrypoint message).createAuthWit: credible.BaseWallettoday:requestCapabilitiesthrows, no capability boundary, so little added authority yet. Latent until capabilities ship.Tests: red/green (entrypoint message == new hash, != generic hash for the same payload); TS drift test + Noir collision test.