Repository navigation
security: Fix yield sniping, decrease cap, and zero-assets vulnerabil… - #1071
Merged
Abidoyesimze merged 1 commit intoOct 20, 2026
Conversation
…ities (Neurowealth#975 Neurowealth#974 Neurowealth#973) - Set default MinHoldingPeriod to 120 ledgers to prevent yield sniping (Neurowealth#975) - Move max_decrease_bps to owner-configured storage with default 1000 bps (Neurowealth#974) - Reject deposits when TotalShares > 0 && TotalAssets == 0 (Neurowealth#973) - Add comprehensive tests for all three fixes - Update SECURITY.md with threat documentation
|
@Immex171 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! 🚀 |
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.
Security Fixes: Yield Sniping, Decrease Cap, and Zero-Assets Protection
This PR addresses three critical security vulnerabilities in the NeuroWealth Vault contract:
Changes
1. Yield Sniping Protection (#975)
Problem: Yield reaches the share price only when the agent calls
update_total_assets, which can raise TotalAssets by any amount up to the real balance in one step. With MinHoldingPeriod defaulting to 0, anyone watching the mempool or the agent's schedule could deposit just before the update and withdraw right after, capturing yield accrued over a period they were not invested.Solution:
MinHoldingPeriodto 120 ledgers (~10 minutes) ininitialize()set_min_holding_periodif neededFiles modified:
neurowealth-vault/contracts/vault/src/lib.rs: Added default MinHoldingPeriod in initialize2. Decrease Cap Configuration (#974)
Problem:
update_total_assets(agent, new_total, allow_decrease, max_decrease_bps)capped a loss report atmax(max_decrease_bps, 100)bps of the old total. The cap was a caller-supplied argument, so the caller could pass 10_000 and report a 100% loss in one call. The only safeguard was the owner co-sign requirement.Solution:
DataKey::MaxDecreaseBpsfor owner-configured storageset_max_decrease_bps()andget_max_decrease_bps()functionsupdate_total_assets()to read from storage and ignore caller-supplied argument_to indicate it's unusedFiles modified:
neurowealth-vault/contracts/vault/src/lib.rs: Added MaxDecreaseBps storage key, setter/getter, updated update_total_assetsneurowealth-vault/contracts/vault/src/types.rs: Added MaxDecreaseBps variant3. Zero-Assets-With-Shares Protection (#973)
Problem:
convert_to_shares_internalused a bootstrap 1:1 rate whentotal_shares == 0 || total_assets == 0. If shares were outstanding but assets were zero (e.g., after a full loss report, or dust shares remaining after rounding), a new depositor would getamountshares while existing holders, whose shares were worth nothing, would immediately own a pro-rata slice of the new deposit.Solution:
VaultError::DepositRejectedZeroAssetsWithSharesconvert_to_shares_internal()to reject deposits whentotal_shares > 0 && total_assets == 0Files modified:
neurowealth-vault/contracts/vault/src/errors.rs: Added DepositRejectedZeroAssetsWithShares errorneurowealth-vault/contracts/vault/src/lib.rs: Added check in convert_to_shares_internal4. Documentation
SECURITY.md Updates:
Each section documents the threat, mitigation, and impact.
5. Tests
Added comprehensive test coverage for all three fixes:
test_zero_assets_with_shares.rs: Tests for deposit rejection when TotalShares > 0 && TotalAssets == 0test_stored_decrease_cap.rs: Tests for owner-configured decrease captest_default_holding_period.rs: Tests for default MinHoldingPeriodAll test modules registered in
tests/mod.rs.Testing
Run the new tests:
Security Impact
Backward Compatibility
set_min_holding_periodwithout upgradeChecklist
Closes #975, Closes #974, Closes #973