Kann Audits / Security Review

Mystic Finance

Mystic Finance RWA Security Review — Second June 2025 Review

Second June review of stPlumeMinter and frxETH, focused on rewards accounting and concurrent withdrawal availability.

PlumeSolidityLiquid stakingJune 12, 2025
Audit period
June 12, 2025
Researchers
1 listed
Scope
2 scoped paths
Technologies
Solidity, Liquid staking
Findings
2 documented

Executive summary

What was reviewed

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

Engagement dossier

Researchers
Kann
Audited commit
2e6d7e59def340c63f98808b19c9650d8f63917b
Technologies
Solidity, Liquid staking
Chain / ecosystem
Plume
Category
RWA

Files and paths in scope

  • /src/stPlumeMinter.sol
  • /src/frxETH.sol

Findings overview

Severity distribution

The counts below are transcribed from the published report. Status and issue detail remain subject to that report’s exact terminology.

FINDINGS02Documented in the published report
Critical: 1Medium: 1
SeverityCount
Critical1
High0
Medium1
Low0
Informational0

Published findings

Findings

Findings below are reproduced from the complete Kann Audits security review. View the full PDF for complete scope, methodology, assumptions, and audit context.

Critical

1 finding
4.1.1

Miscalculation in rewards will give too much rewards to users

Critical
Description

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.

Resolution

Fixed 4.2 Medium Risk

Medium

1 finding
4.2.1

DoS Vulnerability in withdraw() Due to Overcommitment of currentWithheldETH in Concurrent unstake() Calls

Medium
Description

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

How Kann Audits reviews code

Kann Audits reports describe independent researcher review followed by collaborative analysis of findings and attack paths. The standard review foundation includes:

  1. 01Architecture and trust-boundary analysis
  2. 02Independent manual review
  3. 03State-transition and invariant analysis
  4. 04Access-control and integration review
  5. 05Adversarial testing and attack-path analysis
  6. 06Fix verification and regression review

Audit team

Researchers listed in the report

Kann

Final assessment

Documented outcome

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

Planning your next release?

Share the system, fixed scope, and target date. Build enough time into the plan for review, remediation, and verification.