Quantstamp reviewed StakeStone (StakeStone Tokenized Vault) on 14 Oct 2025: 8 findings, 0 critical; 7 marked fixed, 1 open.
Report hosted on certificate.quantstamp.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 0 |
| Medium | 0 | 0 | 0 |
| Low | 1 | 0 | 7 |
The `removeUnderlyingAsset` function iterates through the entire `underlyingAssets` array without bounds checking, creating potential denial-of-service conditions. ```solidity uint256 length = underlyingAssets.length; uint256 i; for (i; i < length; i++) { if (underlyingAssets[i] == _asset) { underlyingAssets[i] = underlyingAssets[length - 1]; underlyingAssets.pop(); break; } } ``` If the array becomes very large, this function will run out of gas and become unusable.
In the `OracleRegistry` contract, the functions `getCutOffPrice()`, `getCutOffPrices()`, and `onlyGetCutOffPrices()` calculate a timestamp from `cutOffPriceUpdateAt` and then return `prices[_token][updatedAt]`. However, if no price was ever recorded for that (token, updatedAt) pair, for example, if the token was added after the cut-off update or removed before it then the mapping will return the default zero value.
In the `ParamRegistry` contract, the `setPriceUpdateInterval()` function enforces only a minimum bound but no maximum bound. Therefore, a privileged actor with the `D0_TIMELOCK_ROLE` can set the `_priceUpdateInterval` to an arbitrarily high value. This results in a denial-of-service scenario where all calls to `OracleRegistry.updatePrices` revert with `Errors.PriceUpdateTooFrequent()`. Additionally, consumers of prices that enforce freshness checks will eventually revert with `Errors.PriceValidityExpired()` since the maximum validity duration is capped at 7 days.
In the `Token` contract constructor, the `_admin` parameter is directly assigned the `DEFAULT_ADMIN_ROLE` via `_grantRole`. However, there is no validation to prevent `_admin` from being the zero address. If the contract is deployed with a zero address for the admin then all administrative access is lost permanently. This misconfiguration would prevent assignment of the `MINTER_ROLE` and block all future role management actions, effectively bricking minting functionality and governance control.
During creation of the `OracleRegistry` contract, the initial token oracles are checked against the stablecoin tolerance recorded in the `ParamRegistry` contract. However, this check is missing for oracles that are added or updated after contract initialization using the `updateTokenOracle()` and `addTokenOracle()` functions.
In the `WithdrawController` contract, the `addWithdrawalAsset()` function allows new assets to be added as withdrawal options. However, there is no validation to prevent the vault share token from being added as a withdrawal asset. If this occurs, users could attempt to redeem shares into the vault token itself, which undermines the intended design of the system and may cause incorrect accounting or unexpected behavior.
In the `OracleRegistry` contract the `addTokenOracle()` function (and also in the constructor) do not prevent the `vaultToken` from being added to the list of registered tokens. In `updatePrices()`, the contract first updates the vault token price using `_vaultTokenPrice` and enforces exchange-rate deviation checks. However, since it then iterates over `tokens` and calls `peek(token)` for each, this would overwrite the vault token’s price if it appears in the list. Since `peek()` only enforces stablecoin tolerance checks, the stricter exchange-rate validations for the vault token can be bypassed. This introduces a risk of misconfiguration where the vault token’s price can be set without proper safety checks, undermining the integrity of the system’s pricing logic.
The report names a repository or files. Open the report to see its scope.
236 projects reviewed · 332 reports · latest Oct 2026
See Quantstamp’s auditsSomething 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