Repository navigation
Keep proxy auth tokens at the wallet address - #410
Merged
Merged
Conversation
…ted change buildProxySpendTx (and buildProxyCleanupSweepTx) only excluded the single designated authTokenUtxo from caller-supplied walletUtxos before spending them and sending changeAddress(proxyAddress). A wallet holds up to 10 AuthToken UTxOs (minted at proxy setup, all sent to the wallet's own address). If any *other* AuthToken UTxO was included in walletUtxos - e.g. by a bot/integration doing ordinary coin selection via freeUtxos, which returned all UTxOs undifferentiated - it would silently become change at proxyAddress. The on-chain proxy spend validator only checks that an AuthToken appears in *some* output, with no signer/quorum check, so once an AuthToken sits at proxyAddress unprotected, anyone can drain the address with a raw transaction - no compromised keys required. Changes: - utxoUtils: add assertNoStrayAuthTokenUtxos(), a fail-closed guard that throws if walletUtxos contains any AuthToken-bearing UTxO other than the one explicitly designated. - txBuilders: call the guard in buildProxySpendTx and buildProxyCleanupSweepTx before building the transaction. - api/v1/freeUtxos: flag each returned UTxO with authToken: true/false (based on the wallet's active proxy AuthToken policy id) so callers have a positive signal to avoid selecting more than the one they intend. - SKILL.md: document the authToken flag and the exactly-one-AuthToken-UTxO requirement for proxySpend callers. - tests: new proxyAuthTokenLeakGuard.test.ts covering the guard and buildProxySpendTx rejection; updated freeUtxos.bot.test.ts mocks/assertions for the new authToken field. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…nsactions - Updated SKILL.md to clarify proxy auth token handling and safety measures. - Enhanced README.md with details on auth-token hygiene and transaction requirements. - Improved CI documentation for proxy lifecycle and cleanup processes. - Added tests for auth token conservation and auditing to ensure compliance with wallet address constraints. - Introduced new utility functions for auditing transactions involving proxy auth tokens. - Removed outdated proxy auth token leak guard tests, consolidating functionality into new audit mechanisms.
…on auditing - Updated SKILL.md to clarify proxy auth token handling and safety measures. - Enhanced README.md with details on auth-token hygiene and transaction requirements. - Improved CI documentation for proxy lifecycle and cleanup processes. - Added tests for auth token conservation and auditing to ensure compliance with wallet address constraints. - Introduced new utility functions for auditing transactions involving proxy auth tokens. - Consolidated proxy address stake credential handling to ensure consistency across implementations.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ion authorization tests - Enhanced transaction authorization tests to verify that the proxy's findMany method is called with the correct walletId. - Updated mock database to include a proxy implementation that returns an empty array for findMany calls.
Andre-Diamond
added a commit
that referenced
this pull request
Oct 11, 2026
Brings in the proxy auth-token hardening (PR #410) and VoteDelegation certificates on top of the Plutus transaction controls. Conflict resolutions: - tx-draft types: DraftCertificateKind gains "VoteDelegation". - validate.ts / to-tx-builder.ts: keep both import sets; drop preprod's fee-floor constants, which this branch already moved into funding.ts. - useTransaction.ts: keep the pre-sign proxy audit before signTx and add ctx to the callback deps. - useTransactionReview.test.ts: mock preSignProxyAudit so the hook reaches signTx, and cover the refusal path. Co-authored-by: Cursor <cursoragent@cursor.com>
This branch was successfully deployed
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.
Summary
The deployed proxy spend validator only checks that some output carries an auth token. It does not check the signer or the destination. A proxy wallet holds up to 10 of those tokens. If one lands anywhere other than the multisig wallet address — including as change at the proxy address — anyone can satisfy the validator and drain the proxy. This is an off-chain defense for that immutable validator.
proxySpendalso returns any auth token found among the proxy-address inputs, so a token that already leaked there can be recovered.src/lib/proxy/authTokenAudit.tsdecodes the transaction and requires every auth-token output to be at the wallet script address. v1 proxy handlers run that check before persisting (a failure is a 500, because the builder itself misbehaved).signTransactionand tRPCcreateTransaction,importTransaction, andupdateTransactionrefuse a pending transaction that would move a token (409 /PRECONDITION_FAILED). The check covers everyProxyrow for the wallet, active or not, because deactivating or deleting a proxy is a soft delete and does not remove tokens from the chain.wallet.signTx. The last signer broadcasts before the signature is recorded, so a later server refusal would be too late.transaction.preSignProxyAuditruns the same audit first and fails closed if it cannot be reached.freeUtxosmarks auth-token UTxOs. Each UTxO now includesauthTokenandauthTokenIdfor every proxy row of the wallet, so bots can keep permission tokens out of generic coin selection. Spend, DRep, and vote calls should pass exactly one token UTxO; cleanup needs all of them.