feat: gate input-note script execution behind a trust policy#2136
Open
JereSalo wants to merge 21 commits into
Open
feat: gate input-note script execution behind a trust policy#2136JereSalo wants to merge 21 commits into
JereSalo wants to merge 21 commits into
Conversation
The check now lives in `GrpcClient::get_note_script_by_root` and returns `RpcError::InvalidResponse` on a root mismatch, with the invariant documented on the `NodeRpcClient` trait. Removes the duplicate check from `ClientDataStore::get_note_script` and ensures every caller of the RPC method (including `ensure_ntx_scripts_registered`) gets the verification.
Introduces NoteScriptTrustPolicy on TransactionRequest so the SDK no longer silently fetches and executes unknown input-note scripts. The policy is checked at the user-facing transaction boundary (execute_transaction and submit_new_transaction_with_prover) before any side-effectful work, and is also applied by the note screener so discovery does not run unverified bytecode. Defaults to StandardScriptsOnly (P2ID, P2IDE, SWAP, MINT, BURN). Custom scripts are opted in via TransactionRequestBuilder::trusted_input_note_ script_roots, or the request can opt out of root-based gating with allow_unlisted_note_scripts_after_user_approval for clients that have their own approval flow. Failures surface as ClientError::UntrustedNoteScript. The policy is part of TransactionRequest's serialized form, so a deserialized request carries its own trust decision through the same preflight as a freshly built one.
Adds a `--allow-unlisted-note-scripts` flag to the `consume-notes` CLI and updates the integration tests that consume custom-script notes to opt in via `trusted_input_note_script_roots`, so they pass under the new default `StandardScriptsOnly` policy.
… opt-in The CLI's --allow-unlisted-note-scripts flag was collecting every input note's script root and passing them as TrustedScriptRoots, which is equivalent to AllowUnlistedAfterApproval here since the notes are fixed at that point. Call the unlisted-policy method directly instead. Drop the _after_user_approval suffix on the builder method: calling the method is the approval, and the suffix is doc copy in name form.
…trust-policy # Conflicts: # CHANGELOG.md
Distinguish gated user-authorized transaction execution from speculative consumability probes (NoteScreener during sync, consume-notes auto-discovery) that may run scripts but discard their effects and stay outside the policy.
TomasArrachea
approved these changes
May 5, 2026
TomasArrachea
left a comment
Collaborator
There was a problem hiding this comment.
Looks good! This feature seems like worth mentioning in the docs.
# Conflicts: # CHANGELOG.md # crates/rust-client/src/rpc/tonic_client/mod.rs
After merging next, NoteScript::root() and StandardNote::script_root() now return NoteScriptRoot instead of Word. Convert at boundaries so the policy API and call sites continue to use Word.
Collaborator
Author
Yeah I've now added mention to it, I don't know if I chose the right place to do so but I documented it both in the cli and in the rust-client library docs. LMK if you were expecting it to be somewhere else. |
# Conflicts: # CHANGELOG.md # bin/miden-cli/src/commands/new_transactions.rs # crates/rust-client/src/errors.rs # crates/rust-client/src/transaction/mod.rs # crates/testing/miden-client-tests/src/tests.rs # docs/external/src/rust-client/library.md
- collect all rejected note-script roots before erroring (was: first only) - add error hint with remediation for UntrustedNoteScript - display the active trust policy in the error message - note in builder rustdoc that the two policy setters overwrite rather than append - link StandardNote docs.rs in the library guide and polish wording - add multi-root regression test
# Conflicts: # crates/rust-client/src/transaction/mod.rs
SantiagoPittella
approved these changes
May 27, 2026
After merging next, Felt::new is fallible and setup_two_wallets_and_faucet takes AccountType instead of AccountStorageMode. Update the trust-policy tests (Word::from integer arrays, AccountType::Private) so the test build compiles.
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.
Adds a per-request
NoteScriptTrustPolicythat controls whether the client will execute the script of an input note. The new default,StandardScriptsOnly, rejects any input note whose script root is not a recognized standard (P2ID, P2IDE, SWAP, MINT, BURN). Previously, non-standard scripts could be silently fetched from the node and executed.Callers that need to consume notes with custom scripts must opt in explicitly, either by listing the script roots they trust via
TransactionRequestBuilder::trusted_input_note_script_roots(...), or by acknowledging that they have already approved the unlisted scripts via::allow_unlisted_note_scripts_after_user_approval(). The preflight check runs before the network-transaction script registration submits its own transaction, and again before directexecute_transactioncallers, so a rejected request never reaches execution.The CLI gains an
--allow-unlisted-note-scriptsflag onconsume-notesfor the equivalent opt-in.Closes #2133