
Mystic Finance RWA Security Review — Second June 2025 Review
Second June review of stPlumeMinter and frxETH, focused on rewards accounting and concurrent withdrawal availability.
Kann Audits / Security Review
Manifest FinanceReview of access management, sanctions controls, price-oracle, staking-vault, and USH token contracts.
Executive summary
Review of access management, sanctions controls, price-oracle, staking-vault, and USH token contracts.
This page reflects only the scope and review context disclosed in the published report. Fields the report does not provide are omitted rather than inferred; the PDF remains the source of record for issue detail and limitations.
Security is contextual. This report does not guarantee that the protocol is free from vulnerabilities. It applies to the review context documented in the report.
Scope & record
/src/authmanager/AuthManager.sol/src/authmanager/AuthManagerStorage.sol/src/chainalysis/MockChainalysisOracle.sol/src/chainalysis/SanctionsList.sol/src/chainalysis/SanctionsListStorage.sol/src/oracle/USHPriceOracle.sol/src/oracle/USHPriceOracleStorage.sol/src/sush/AdminControl.sol/src/sush/Silo.sol/src/sush/StakedUSH.sol/src/sush/StakedUSHBase.sol/src/ush/USAToken.sol/src/ush/USHToken.sol/src/ush/USHTokenStorage.solFindings overview
The counts below are transcribed from the published report. Status and issue detail remain subject to that report’s exact terminology.
The report summary records one Medium finding. Its detailed entry is headed Medium but also contains the line ‘Severity: High risk.’ Aggregate counts on this page follow the report summary table.
Published findings
Findings below are reproduced from the complete Kann Audits security review. View the full PDF for complete scope, methodology, assumptions, and audit context.
4.1.1
The StakedUSH vault is vulnerable to zero share deposits when USH tokens are sent directly to the contract. Because the vault calculates shares based on totalSupply and totalAssets, a direct token transfer increases totalAssets without increasing totalSupply. As a result, legitimate depositor will receive 0 shares for a positive deposit, breaking fair share distribution and potentially locking user funds. The sUSH vault calculates shares using the formula: shares = (assets * (totalSupply + decimalsOffset)) / (totalAssets + 1) If a user directly transfers USH to the vault contract (bypassing deposit()), the vault’s totalAssets increases while totalSupply remains 0. When the next user calls deposit(), the formula becomes: (assets * (0 + 0)) / (totalAssets + 1) = 0 Thus, the user receives 0 shares (REVERTS), even though they tried depositing a positive amount of assets.
Fixed 4.2 High
4.2.1
The deposit flow does not fully enforce the FULL_RESTRICTED_STAKER_ROLE check. When a user with FULL restriction calls deposit(assets, receiver), the restriction logic fails to prevent the operation, allowing restricted users to bypass intended compliance rules. Deposit flow: deposit(ERC4626 logic) -> _deposit(override) where checks if both addresses have SOFT_RESTRICTED_STAKER_ROLE if true reverts then logic goes to _deposit(ERC4626) function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal virtual { SafeERC20.safeTransferFrom(IERC20(asset()), caller, address(this), assets); _mint(receiver, shares); emit Deposit(caller, receiver, assets, shares); } Where _mint is called.
function _mint(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(address(0), account, value); } See how _mint sets first parameter for _update to be address 0. and since we have _update override it goes to function _update(address from, address to, uint256 value) internal override { if (hasRole(FULL_RESTRICTED_STAKER_ROLE, from) && to != address(0)) { revert OperationNotAllowed(); } if (hasRole(FULL_RESTRICTED_STAKER_ROLE, to)) { revert OperationNotAllowed(); } super._update(from, to, value); } Where it fails to check if the msg.sender is restricted role
Fixed 4.3 Medium
4.3.1
In StakedUshBase.sol, which imports and inherits AdminControl, the constructor calls: _grantRole(DEFAULT_ADMIN_ROLE, _owner); This sets the default admin role to _owner. However, the contract does not initialize the _currentDefaultAdmin variable, leaving it as address(0). Consequently, in a scenario where the current default admin attempts to transfer the admin role by calling transferAdmin, followed by _pendingDefaultAdmin executing acceptAdmin, the _grantRole override logic executes: _revokeRole(DEFAULT_ADMIN_ROLE, _currentDefaultAdmin); Since _currentDefaultAdmin is address(0), the call to _revokeRole effectively does nothing. The function then proceeds to grant the role to the new admin via: super._grantRole(role, account); The net effect is that both the original _owner and the new admin retain the DEFAULT_ADMIN_ROLE, resulting in two admins instead of a proper transfer. Thisissuearisesfromthelackofproperinitializationof_currentDefaultAdminduringcontractdeployment and highlights a gap in the role transfer logic that lead to unintended multi-admin privileges.
Fixed
4.4 Low
4.4.1
USHToken gates approve() with whenNotPaused, but inherits permit() from Solmate without overriding. While paused, anyone can still set/refresh allowances via permit, pre-arming drains that execute the instant the token is unpaused.
4.4.2
USHToken.burn(from, amount) calls _checkAuthTransfer(from, address(0)). If from has since become banned/sanctioned (via AuthManager), checkSanctioned/checkBanned will revert. This prevents the protocol (holder of BURNER_ROLE) from programmatically burning balances from blocked accounts a common compliance/control action.
Fixed 4.5 Informational
4.5.1
The view function chainalysissOracleEnabled() returns true when the oracle is unset (i.e., disabled), andfalsewhentheoracleisactuallyconfigured. Thisbehaviorcontradictsthefunction name, which suggests it should return true when the oracle is enabled.
Fix logic: function chainalysisOracleEnabled() public view returns (bool) { return KycManagerStorageLib.getV1().chainalysisOracle != address(0); }
Methodology
Kann Audits reports describe independent researcher review followed by collaborative analysis of findings and attack paths. The standard review foundation includes:
Audit team
Final assessment
All six reported findings were marked fixed.
The assessment applies only to the review context and limitations documented in the published report. Missing details are not inferred, and later changes require separate analysis.
Start a conversation
Share the system, fixed scope, and target date. Build enough time into the plan for review, remediation, and verification.