Conversation
The client migration entrypoints (`propose_client_migration` / `accept_client_migration`) previously allowed changing the client address when the contract was in `PartiallyFunded` or `Funded` status. Once funds have been deposited, the client address is security-sensitive: the current client can cancel or refund, so swapping the client after funding would allow the original client to transfer cancellation rights to an accomplice and drain escrowed funds. This commit tightens `require_migration_allowed` in `migration.rs` to reject migration proposals when the contract holds escrowed funds (`PartiallyFunded` or `Funded`), leaving `Created` as the only safe status for client migration. Changes: - `migration.rs`: Add `PartiallyFunded` and `Funded` to blocked statuses in `require_migration_allowed`, with a security rationale comment explaining the threat model. - `test/client_migration.rs`: Update `migration_allowed_on_partially_funded_status` and `migration_allowed_on_funded_status` tests to assert `InvalidStatusTransition` on funded states, and fix the refunded contract test to use `register_client_with_token` + `StellarAssetClient::mint` so `deposit_funds` has sufficient token balance. - `test/mod.rs`: Temporarily unwire `test_finalization_bug` module that depends on a non-existent `test::lifecycle` module, unblocking test compilation. - Formatting fixes in `amount_validation.rs`, `milestone_transitions.rs`, and `test_finalization_bug.rs` via `cargo fmt`. Security analysis: - Client migration is now only permitted when the contract is in `Created` status (no funds deposited). - This prevents the attack vector where a malicious client deposits funds, migrates to an accomplice address, and the accomplice exercises cancellation/refund rights to drain escrowed funds. - All existing terminal-state guards (`Completed`, `Cancelled`, `Refunded`, `Disputed`) remain intact. Closes Talenttrust#1344 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
|
@divysam Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
13 tasks
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
This PR closes #1344 by blocking client migration (beneficiary changes) once an escrow contract holds deposited funds. Previously,
propose_client_migrationandaccept_client_migrationallowed changing the client address even when the contract was inPartiallyFundedorFundedstatus, creating a critical security vulnerability.Security Problem
The client address on an escrow contract controls refund and cancellation rights. If a malicious client could migrate their identity after depositing funds, the attack vector would be:
Fundedstatus).propose_client_migrationto transfer the client role to an accomplice.accept_client_migration, becoming the new on-chain client.This is a privilege-transfer attack: the original client moves cancellation rights to an accomplice after escrowed funds are present, breaking the trust model that the client who funded the contract is the one who controls its lifecycle.
Fix
Added
PartiallyFundedandFundedto the blocked statuses inrequire_migration_allowedinmigration.rs. Client migration is now only permitted when the contract is inCreatedstatus (no funds deposited), which is the only safe window for identity changes.Status guard matrix (before → after)
CreatedPartiallyFundedFundedCompletedCancelledRefundedDisputedChanges
Core security fix
contracts/escrow/src/migration.rs: AddedContractStatus::PartiallyFundedandContractStatus::Fundedto thematches!guard inrequire_migration_allowed, with a detailed security rationale comment explaining the threat model.Test updates
contracts/escrow/src/test/client_migration.rs:migration_allowed_on_partially_funded_status→migration_blocked_on_partially_funded_status; now assertsInvalidStatusTransitionwhen migration is attempted on aPartiallyFundedcontract.migration_allowed_on_funded_status→migration_blocked_on_funded_status; now assertsInvalidStatusTransitionwhen migration is attempted on aFundedcontract.migration_blocked_on_refunded_contractto useregister_client_with_token+StellarAssetClient::mintsodeposit_fundshas sufficient token balance (pre-existing test had zero-balance issue).set_escrow_statusto inject status directly, avoiding the need for a settlement token while still validating the guard.Pre-existing fixes (required for test compilation)
contracts/escrow/src/test/mod.rs: Commented outmod test_finalization_bugwhich references a non-existenttest::lifecyclemodule, blocking all test compilation.contracts/escrow/src/amount_validation.rs: Removed trailing whitespace (cargo fmt).contracts/escrow/src/milestone_transitions.rs: Reformatted chained method call and removed duplicate blank lines (cargo fmt).contracts/escrow/src/test/test_finalization_bug.rs: Reformattedassert_eq!macros (cargo fmt).Test Results
All client migration tests pass:
CI checks:
cargo fmt --all -- —check— passescargo clippy --workspace --all-targets— passes (zero warnings)cargo test -p escrow --lib -- client_migration— 22 passed, 0 failedSecurity Considerations
propose_client_migration_impl, so there is no way to circumvent the status check.current_client.require_auth()still runs, ensuring only the legitimate client can attempt migration.require_no_role_overlapstill runs, preventing the new client from being the freelancer, arbiter, or the contract itself.PENDING_MIGRATION_TTL_LEDGERS.Createdstatus can still migrate. Only contracts with deposited funds are affected.Related Issues