
Mystic Finance RWA Security Review — June 2025
Review of stPlumeMinter and frxETH withdrawal, validator-deposit, rewards, and governance-withdrawal logic.
Kann Audits / Security Review
Mystic FinanceSecond June review of stPlumeMinter and frxETH, focused on rewards accounting and concurrent withdrawal availability.
Executive summary
Second June review of stPlumeMinter and frxETH, focused on rewards accounting and concurrent withdrawal availability.
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/stPlumeMinter.sol/src/frxETH.solFindings overview
The counts below are transcribed from the published report. Status and issue detail remain subject to that report’s exact terminology.
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
In syncRewards, the rewards are calculated by substracting the last rewards to the total yield. This is inaccurate because total yield keep increasing, and last rewards are just the last amount rewarded. This means that over time, rewards will become much more inflated than their actual values, giving away too many yield to the users. The first users to withdraw will effectively steal from others.
Proof of Concept Let’s assume that we get 10 ether of rewards per cycle, for simplicity. The key parts of function syncRewards work as follow: Cycle 1: yieldEth has increased to 10 ether. lastRewardAmount is 0 (first run). uint256 nextRewards = yieldEth - lastRewardAmount uint256 nextRewards = 10 ether - 0 = 10 ether lastRewardAmount is set to nextRewards, 10 ether. Cycle 2: yieldEth has increased to 20 ether. lastRewardAmount is 10. uint256 nextRewards = 20 ether - 10 ether = 10 ether lastRewardAmount is set to nextRewards, 10 ether. Cycle 3, where things start to break: yieldEth has increased to 30 ether. lastRewardAmount is 10. uint256 nextRewards = 30 ether - 10 ether = 20 ether Next rewards are calculated as twice the normal amount.
Fixed 4.2 Medium Risk
4.2.1
The protocol maintains a global variable currentWithheldETH to represent the amount ofETHreservedforuserwithdrawalsaftertheycallunstake(). However, thisvariableisonlydecreased
when withdraw() is called — not when unstake() is made. This creates a critical race condition: multiple users can initiate unstake() relying on the same currentWithheldETH balance, leading to overcommitment. If one user completes the withdrawal first, the remaining users are blocked from withdrawing, resulting in a denial of service (DoS). Example Scenario Initial State: currentWithheldETH = 10 ETH Alice calls unstake(10 ETH) → succeeds (as 10 ETH is available) Bob calls unstake(8 ETH) → also succeeds (still sees 10 ETH as available) Both transactions pass the currentWithheldETH >= amount check, since the variable hasn’t been decremented yet. Alice calls withdraw() first: Receives 10 ETH currentWithheldETH becomes 0 Bob then calls withdraw(): Fails, as there is no remaining currentWithheldETH Additionally, Bob cannot call unstake() again due to the presence of an active withdrawal request If no one deposits or triggers a stake rebalance before Bob’s cooldown period ends, Bob is temporary locked out of his funds until admin calls unstakeGov() or rebalance happens.
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
Both 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.