[ANCHOR-1233]: SEP-24 withdraw skips the destination-account check its SEP-24 deposit sibling enforces - #1968
Merged
Merged
Conversation
* add robust destination account validation for sep24 withdraw requests * add tests for destination account whitelisting and 'allowAnyDestination' client configurations
Contributor
There was a problem hiding this comment.
Pull request overview
This PR closes a SEP-24 authorization gap by aligning Sep24Service.withdraw with deposit and SEP-6 flows: the client-supplied account is now validated against the operator’s configured destination-account policy (allowlist / allow-any), not just syntactically.
Changes:
- Updated SEP-24 withdraw to call
SepRequestValidator.validateDestinationAccount(token, sourceAccount)instead ofvalidateAccount(sourceAccount). - Added SEP-24 withdraw unit tests mirroring deposit’s destination-account policy coverage (token mismatch, allowlisted, non-allowlisted, allowAnyDestination).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| core/src/main/java/org/stellar/anchor/sep24/Sep24Service.java | Enforces operator destination-account policy on SEP-24 withdraw account, matching deposit/SEP-6 behavior. |
| core/src/test/kotlin/org/stellar/anchor/sep24/Sep24ServiceTest.kt | Adds withdraw-side tests to cover token mismatch, allowlist, denylist, and allowAnyDestination cases. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
* add `destination_accounts` to `client-wallet-server` configuration * add `GAIUIZPHLIHQEMNJGSZKCEUWHAZVGUZDBDMO2JXNAJZZZVNSVHQCEWJ4` as a valid destination account
* update expected error message for sep6 account validation * fix test assertions to match new error message
JiahuiWho
approved these changes
Jul 7, 2026
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.
Description
Sep24Service.withdrawonly applied the syntacticrequestValidator.validateAccount(sourceAccount)check to the client-suppliedaccountfield before persisting it asfrom_account. Its siblingSep24Service.deposit, on the same endpoint and reading the same sharedCustodialClient.destinationAccounts/allowAnyDestinationconfiguration, enforces the operator's account-authorization policy viarequestValidator.validateDestinationAccount(token, account). A client could therefore record a withdrawfrom_accountthat is neither its own SEP-10 identity nor a member of the operator's configured allowlist - exactly what deposit already blocks on the same field. Impact is bounded (the user must still own and sign from that account for the on-chain payment to settle, so no third-party funds are redirected), but it's a real operator-policy bypass and an audit inconsistency.The ANCHOR-1212 work that generalized this check into
SepRequestValidator.validateDestinationAccounthad already landed ondevelop, applied to SEP-6 deposit/deposit-exchange/withdraw/withdraw-exchange and SEP-24 deposit - SEP-24 withdraw was the one path left behind.Changes
Sep24Service.withdraw: replacedrequestValidator.validateAccount(sourceAccount)withrequestValidator.validateDestinationAccount(token, sourceAccount), matchingdepositand all four SEP-6 call sites.validateDestinationAccountalready callsvalidateAccountinternally, so syntactic validation is preserved.Sep24ServiceTest: added withdraw-side tests mirroring the existing deposit templates — non-custodial token-mismatch rejected, custodial-allowlisted account accepted, custodial non-allowlisted account rejected, andallowAnyDestinationaccepted.Acceptance Criteria
accountthat doesn't match the token and has no custodial client config is rejected withERR_TOKEN_ACCOUNT_MISMATCH.accountin the caller'sCustodialClient.destinationAccountsallowlist is accepted and persisted asfrom_account.accountnot in the allowlist is rejected with"Provided 'account' is not allowed".accountis accepted unconditionally when the caller'sCustodialClienthasallowAnyDestination = true.Context
#3827007
Testing
./gradlew :core:test --tests "org.stellar.anchor.sep24.Sep24ServiceTest"./gradlew :core:buildDocumentation
N/A
Known limitations
N/A