As of 30 Oct 2026, StakeStone has 4 audit reports by 1 security firm on Trustblock; the latest is by Quantstamp, dated 14 Oct 2025. Those reports list no open critical findings.
Record last updated . It holds audits and findings, contracts and incidents up to Oct 2026. Trustblock does not review code.
Newest first
| Audit | Security firm | Date | Scope | Critical findings | Report |
|---|---|---|---|---|---|
| StakeStone Tokenized Vault | Security firm: Quantstamp | Date: | Scope: Not recorded (see the report) | No open critical findings | Open · certificate.quantstamp.com |
| StakeStone Vault | Security firm: Quantstamp | Date: | Scope: Files named in the report | No open critical findings | Open · certificate.quantstamp.com |
| StakeStone StoneBTC and Vault | Security firm: Quantstamp | Date: | Scope: Files named in the report | No open critical findings | Open · certificate.quantstamp.com |
| StakeStone | Security firm: Quantstamp | Date: | Scope: Repository at commit d34a1ec | No open critical findings | Open · certificate.quantstamp.com |
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 0 |
| Medium | 1 | 2 | 5 |
| Low | 1 | 14 | 12 |
The `OracleConfigurator` contract allows the `ORACLE_MANAGER_ROLE` to update oracles for tokens, but there is no validation to ensure that the price data returned by these oracles has the expected decimal precision (e.g., 18 decimals). If an oracle provides price data with different precision, it could lead to incorrect calculations for LP amount in `AssetVault`.
Open the reportThe `StoneBTCVault` assumes that different wrapped BTC tokens maintain an exchange rate of 1:1. However, if any asset depegs, an attacker can drain the asset pool of value. This effect is aggravated since there are no delays between staking and unstaking. Such an attack is profitable if one asset is worth more than another minus deposit and withdraw fees. At present, WBTC, FBTC, and BTCB are expected to be used to back StoneBTC. However, WBTC in particular is not a safe asset, one reason being the delay for unwrapping<sup>[\[1\]](https://flagship.fyi/outposts/market-insights/wbtcs-recent-depeg-and-what-you-need-to-know-to-protect-yourself/)</sup>. Furthermore, due to the current restructuring<sup>[\[2\]](https://cointelegraph.com/news/defi-protocol-threshold-proposes-bitcoin-wrapper-merger-wbtc)</sup> of the WBTC token, it may become even less stable in the future. Token-specific considerations aside primary concern is the ability of users to leverage this vault as a 1:1 exchange platform, possibly using flash loans to exploit any depegged asset. This could result in the entire vault being drained of the more valuable BTC assets, with the less valuable tokens remaining, leading to a significant loss in value.
Open the reportThe `ASSET_MANAGEMENT_ROLE` can call `AssetVault.withdrawFromVault()` and `AssetVault.repayVault()` to transfer the deposited underlying tokens to asset managers and accrue yield. However, there is no restriction to how much of the reserves can be transferred, as the contract allows withdrawing the entire underlying token balance. We would like to note that the protocol maintaining solvency relies on the asset managers used by the StakeStone team. These asset managers are outside the scope of this audit.
Open the reportThe `removeUnderlyingToken()` function ensures that the contract's balance for a specific token is zero before removing it from the token list. However, since it relies on the `IERC20.balanceOf()` function, an attacker can disrupt this function by donating a very small amount of the token to the contract. This will cause the balance check to fail, preventing the token from being removed.
Open the reportThe `queueWithdrawal()` function allows anyone to enqueue a withdrawal request for any amount, regardless of their actual holdings of LP tokens. This leads to fragmentation of the withdrawal queue and can later disrupt the operations of the `processWithdrawals()` and `cancelWithdrawals()` functions. Although it is possible to simply ignore these fake requests while calling these functions, this would still make management of the queue harder.
Open the reportDuring the very first deposit to the vault, a malicious actor could front-run legitimate deposits and donate additional funds to inflate the LP token price. This manipulation may prevent subsequent depositors from receiving the correct amount of LP tokens, effectively reducing their share. Without the Proof of Reserve (PoR) oracle implementation within the scope, we cannot assess whether this inflation attack is feasible. However, this is a known vulnerability in typical vault designs if not properly addressed.
Open the reportThe `processWithdrawals()` function always pays users the `minReceiveAmount` specified at the time of their withdrawal request, regardless of the actual value of their LP tokens at the time of withdrawal. During periods of high market volatility, significant price fluctuations can occur between the time a withdrawal is requested and when it is processed. As a result, users may receive less than the fair value of their LP tokens, effectively losing money and making the protocol appear unfair. While the naming of `minReceiveAmount` might suggest it is intended solely as slippage protection, the client has explicitly stated that it is meant to function as a limit order. The current implementation allows withdrawal processors to pocket any excess value if the LP tokens are worth more at the time of withdrawal. This design incentivizes processors to fulfill withdrawals when they can profit the most from the price difference, potentially at the expense of users. This is a concern if the vault contains assets with varying volatility. For example, if the `AssetVault` holds both `USDC` and `wBTC`, and a user requests a USDC withdrawal, an increase in BTC's value will raise the overall LP token price. Consequently, the user may receive less in USDC during withdrawal because the `minReceiveAmount` was set based on a lower LP token valuation.
Open the reportThe `Proposal` contract allows `StoneBTC` holders to vote on protocol decisions for the `StoneBTCVault` and either support or reject the proposals made by the `PROPOSE_ROLE`. However, the `EXECUTE_ROLE` has a veto right on any passed proposal in that the role can decide to never execute the proposal.
Open the reportThe `StoneBTCVault.removeSupportedTokens()` function includes a check that reverts if `ERC20(_token).balanceOf(address(this)) != 0`. However, there are a few risks: 1. Not everyone may withdraw the token to be deprecated. 2. Someone might accidentally transfer tokens to the contract without using the `deposit()` function, leading to a balance mismatch between the minted stoneBTC tokens and their collateral tokens. 3. An attacker could front-run and repeatedly transfer small amounts (dust) of tokens to prevent the removal from taking place. On the other hand, `StoneBTCVault` allows depositing one token and withdrawing another. As a result, the operating team, if desired, can withdraw the token they plan to remove support for, perform the exchange, and re-deposit another token to clean up the remaining balance. With this in mind, the first risk can be mitigated, and the second risk can also be addressed, as long as there is at least one supported token that is not planned for removal. However, the third risk remains, although the attacker's incentive is low.
Open the reportIn the `Proposal` contract, the `getProposals()` and `retrieveAllToken()` functions both loop through all proposals. Since proposal data is never removed, the size of the `proposals` variable will continuously grow, potentially leading to the risk of breaching the block gas limit. If the block gas limit is exceeded, these functions may no longer be accessible. However, the impact is likely very low, as these functions are not directly used by any contracts within the scope of this audit and are likely only used by off-chain components.
Open the reportThe `Proposal` contract allows users to vote their stoneBTC for only one poll at a time. Only after the vote is closed can the user retrieve the tokens they used and allocate them to another vote. At the same time, it is possible for the `PROPOSE_ROLE` to create several polls at a time, effectively diluting the voting power across these polls.
Open the reportThe `notAtSameBlock` modifier can be bypassed or is missing for the following functions: 1. For `deposit()`, the modifier can be bypassed through calls to the payable `receive()` function. 2. For `withdraw()` and `instantWithdraw()`, the modifier can be passed through calls to the `clear()` function. 3. In `EigenLSTRestaking`, the `instantWithdraw()` function is not protected by the `notAtSameBlock` modifier, allowing multiple withdrawals and deposits within the same block, which in all other strategies is otherwise the case.
Open the reportWhile it is expected that some privileged roles are needed to operate the protocol, some of the roles can override the powers of the governance and what has been approved by voters. 1. The `REVOKE_ROLE` can revoke a proposal at any time by calling `revokePeoposal()`, allowing them to reject a proposal even when it has been approved by the voters and reached its deadline. 2. While the function `addStrategy()` may only be added via successfully voted proposals, the contract owner may overturn any such added strategies by calling `clearStrategy()` and/or `destroyStrategy()`. 3. The voters are dependent on the `EXECUTOR_ROLE` executing any approved proposals. Should the `EXECUTOR_ROLE` become absent or compromised, the voters would not be able to enact proposals.
Open the reportThe function `_depositFor()` compares the price obtained from the call to `currentSharePrice()` with that of the previous round to adjust for the best of both. The same comparison is not performed in`rollToNextRound()` while calculating `amountToWithdraw`, which may not be desirable.
Open the reportThe Strategy contracts do not currently implement `Strategy.getPendingValue()`. Instead, the pending value is included in `getInvestedValue()`, which makes a call to `checkPendingAssets()`. While this doesn't currently cause accounting problems, it doesn't use the abstractions in place and could result in unexpected behavior when integrating with outside contracts.
Open the report`StrategyController.forceWithdraw()` makes a call to `Strategy(strategy).instantWithdraw(withAmount)`. This function is expected to withdraw whatever funds possible and not revert (as opposed to `StrategyController._withdrawFromStrategy()` calling `Strategy(_strategy).withdraw(_amount)`). However, none of the current implementations of `Strategy.instantWithdraw()` correctly gather the requested funds. * `NativeLendingETHStrategy.instantWithdraw()`: Leaves potential funds in the LP token. * `SymbioticDepositWstETHStrategy.instantWithdraw()`: Is unable to syncronously withdraw additional ETH as it needs to submit withdrawal requests from Lido. * `EigenLSTRestaking.instantWithdraw()`: Is unable to syncronously withdraw additional ETH as it needs to submit withdrawal requests from Lido. All three of these functions will revert if the amount withdrawn exceeds the amount of ETH in the contract. With the current usages, this could prevent some users from being able to call `StoneVault.instantWithdraw()`. Additionally, it is possible for the implementations of `Strategy.withdraw()` to revert as well. This could result in blocking calls to `StrategyController._rebase()` until the admin makes the ETH available for each of the strategies. This will in turn prevent calls to `StoneVault.rollToNextRound()`.
Open the reportThe reports name a repository or files. Open a report to see its scope.
Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.
Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.
<head><script src="https://widget.trustblock.run/project-widget.min.js" defer></script></head><body><divdata-tb-project-widgetdata-tb-project-slug="stonebtc"></div></body>
Paste the code where the label should appear. It uses no API credit and updates by itself.
Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.
Tell us