As of 25 Oct 2026, Secured Finance has 2 audit reports by 1 security firm on Trustblock; the latest is by Quantstamp, dated 29 Mar 2024. 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 |
|---|---|---|---|---|---|
| Secured Finance - Diff Audit | Security firm: Quantstamp | Date: | Scope: Repository at commit f1c6276 | No open critical findings | Open · certificate.quantstamp.com |
| Secured Finance | Security firm: Quantstamp | Date: | Scope: Repository at commit 92f4e85 | 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 | 4 |
| Medium | 1 | 3 | 8 |
| Low | 4 | 19 | 20 |
Administrators of the Secured Finance protocol can modify a set of parameters that can lead to liquidations and market instability: 1. `TokenVaultStorage.slot().collateralCurrencies` set is queried when calculating the available collateral of users. This set can be modified by the owner of `TokenVault`, calling `TokenVault.updateCurrency()`. If this administrator removes a currency from the set, this currency will not be used in the collateral calculation, and it will be worth zero (in user positions and deposited funds), potentially leading to a cascade of user liquidations. 2. Updating haircut values can uncover the positions of some users. 3. If the contract `ReserveFund` is not paused and the liquidated user is insolvent, `ReserveFund` can cover in some conditions a portion of the amount transferred to the liquidator. If replicable, this process could lead to draining funds from the contract `ReserveFund`. This is expected to be protected by the Circuit Breaker and minimum debt price modules, and rapid liquidation executions. Protocol operators should be careful when updating the threshold and minimum debt price values. Still, adding more tests of that specific process would help to make sure it is not possible to execute this scenario, by considering several edge cases and extreme conditions.
Open the reportIn case of an emergency, a termination mechanism can be executed by the owner of the contract `LendingMarketController` to cease the operations of the protocol. Once executed, this operation cannot be reverted. For each active currency, the last aggregated price returned by the oracle is stored in the mapping `marketTerminationPrices`. Then, users can force a settlement of all their lending and borrowing positions via the function `executeEmergencySettlement()`. However, if the emergency is caused by incorrect prices returned by the oracle, these prices will be recorded as reference prices and it would negatively impact the settlement phase as the coverage calculation would provide incorrect values.
Open the reportThe modifier `onlyAcceptedContracts()` is used by several contracts to restrict some of their operations to a list of addresses identified by their associated name registered in the mapping of the contract `AddressResolver`. This mapping can be updated by the owner of this contract. As a result, if the owner's address is compromised or if it becomes malicious, an authorized address corresponding to an accepted contract could be replaced by a malicious address which would get the right to execute restricted operations. The likelihood is low but the negative impact for the protocol would be high.
Open the reportUsers can become close to being liquidated if they have ZC bonds that are used as collateral and convert their maximum balance of the withdrawable amount. In this extreme case, a liquidation can happen in the next block if a slight update of the price happens.
Open the reportWhen a user calls a function that uses permit signatures to approve the tokens for deposit, the signature parameters can be pulled from the the mempool and used to approve the token directly. Since the permit signature uses nonce protection, the original function call would fail if someone else used the signature first. This affects all functions that use `permit()` to approve tokens before transferring them.
Open the reportThe functions `LendingMarketUserLogic._getWithdrawableAmount()` and `FundManagementLogic.calculateFunds()` apply haircuts to values, which are stored in the `CurrencyController` contract. However, all the currencies in the deployed contract at `0x7dca6b6BF30cd28ADe83e86e21e82e3F852bF2DC` (address taken from the [docs](https://docs.secured.finance/technical-guide/deployed-contracts)) have zero values as their haircuts. This may lead to unwanted consequences when risk management is required while valuing user assets.
Open the reportIn addition to the roles described in the previous audit report, the owner can create new ZCTokens.
Open the reportThe new version of the codebase brings two additional functions letting users deposit tokens to the contract using permission signatures (ERC2612). However, not all tokens support this feature. Worse, few ERC20 tokens such as WETH can offer a `fallback()` function that will lead to any attempt to execute the function `permit()` on this contract to silently fail (concept of phantom functions). Even if right now, no concrete impact was found since only `msg.sender` can originate a signature that will transfer tokens from its address, silent failures should be avoided.
Open the reportThe `OrderBookLogic` contract contains two functions that invoke the `initialize()` function on orderbook instances, `createOrderBook()`, which is called when the protocol owner attempts to create a new orderbook in an existing market, and `executeAutoRoll()`, which auto-rolls the current maturity to the next one. When the owner calls `createOrderBook()`, they specify a maturity, an opening date, and a pre-opening date, and the initialization function sets those values to the passed maturity's entry in the `isReady()` mapping. After a while, when `executeAutoRoll()` is called by `LendingMarketOperationLogic.rotateOrderBooks()`, the following parameters are passed to it, among others: - `_newMaturity`, which is the result of `calculateNextMaturity()`. This will be used as the key to the `isReady` mapping. - `_openingDate`, which is the maturity date of the newly opened orderbook. This will be set as the next orderbook's opening date. The function also initializes the pre-opening date of the orderbook to `_openingDate - OrderBookLib.PRE_ORDER_BASE_PERIOD`. As a result, the opening date and pre-opening date are recalculated for every orderbook, which renders the initial setup useless.
Open the reportThe owner of the contracts inheriting from OpenZeppelin's `Ownable` can call `transferOwnership()` to transfer the ownership to a new address. If an uncontrollable address is accidentally provided as the new owner address then the contract will no longer have an active owner, and functions with the `onlyOwner` modifier can no longer be executed. The following critical roles are not transferred following a two-step pattern: * the role `proxyAdmin` in the function `ProxyController.changeProxyAdmins()`; * the role `owner` in the contracts inheriting the contract `Ownable`; If the role is transferred to an address owned by no one, the role can be considered to be lost.
Open the reportThe `remove()` function performs a `delete self.nodes[cursor]` call towards its execution's end. The `nodes` mapping maps `uint256` values to `Node` struct values, which in turn contain a mapping `orders` that keeps track of orders under such values. Deletion in this fashion will result in the `Node` struct's instance having its values reset to their defaults, except for the `orders` mapping which will keep its contents intact. This may result in unwanted situations where a node is removed and its orders remain.
Open the reportThe `removeCurrency()` function only removes the supplied `_ccy` value from the `currencies` mapping, however the `haircuts`, `priceFeeds`, and `decimalsCaches` entries for the given currency are not cleared.
Open the reportThe following functions are called but the calling functions ignore the values returned without explicit justification: 1. `LendingMarketController.cleanUpFunds()` in `TokenVault._withdraw()`; 2. `GenesisValueVault.executeForcedReset()` in `FundManagementLogic._resetFundsPerCurrency()`; 3. `LiquidationLogic._transferCollateral()` in `LiquidationLogic.executeLiquidation()`; 4. `LiquidationLogic._transferCollateral()` in `LiquidationLogic.executeForcedRepayment()`; 5. `LiquidationLogic._transferPositionsPerMaturity()` in `LiquidationLogic.executeLiquidation()`; 6. `TokenVault.transferFrom()` in `LiquidationLogic.executeForcedRepayment()`; If not intended, it can result in unexpected behavior of the system. If intended, it makes it harder for an external observer to understand why returned values are ignored.
Open the reportIn `Contracts.sol`, as the names of the contracts are used as `bytes32` keys in a mapping, using a string with a representation exceeding `bytes32` could break the assumption that the same key only refers to one contract name.
Open the reportIf the owner renounces their ownership, all ownable contracts will be left without an owner. Consequently, any function guarded by the `onlyOwner` modifier will no longer be able to be executed.
Open the reportThe `executeLiquidation()` function performs a heavy logic to liquidate a position. The function calls other lengthy and gas-intensive functions such as `FundManagementLogic.cleanUpFunds()` and `TokenVault.getLiquidationAmount()`, which may result in failed liquidations due to insufficient gas usage.
Open the reportThe `executeLiquidation()` and `executeForcedRepayment()` functions both perform external function calls on user-supplied addresses. This allows for the possibility of reentrancy vulnerabilities.
Open the reportThese are the privileged operations identified during the audit: <br> #### AddressResolver - Owner can: - Renounce ownership - Transfer ownership (maybe to uncontrolled address) - Update the mapping between contract names and the address of the associated contract used by the protocol <br> #### BeaconProxyController - Owner can: - Renounce ownership - Transfer ownership (maybe to uncontrolled address) - Update the implementation contract to an arbitrary contract for the contracts: - LendingMarket - FutureValueVault - AcceptedContracts can: - Deploy FutureValueVault contracts. - Deploy LendingMarket contracts. <br> #### CurrencyController - Owner can: - Renounce ownership - Transfer ownership (maybe to uncontrolled address) - Add a new currency (or override the parameters of an existing one) with the following parameters: number of decimals, haircut value, list of price feeds and heartbeat value. - Remove a currency - Update the haircut value of an existing currency - Update or remove the price feeds list of an existing currency <br> #### FutureValueVault - Accepted Contracts can: - Increase the balance of a user - Decrease the balance of a user - Transfer tokens from a user - Reset all amount of a user if there is an amount in a past maturity - Set the initial total supply - Force the reset of the future value of a user <br> #### GenesisValueVault - Accepted Contracts can: - Initialize currency settings - Trigger the update of the initial compound factor - Execute an AutoRoll - Update genesis value with future value - Update genesis value with residual amount - Transfer tokens from a user - Cleanup the balance of a user per maturity - Force the reset of the genesis value of a user <br> #### LendingMarket - Accepted Contracts can: - Create an order book - Execute an autoRoll - Cancel an order - Execute an order - Execute a preorder - Unwind a position - Execute the itayose call - Update the order fee rates - Update the Circuit breaker limit range - Pause the contract - Unpause the contract <br> #### LendingMarketController - Owner can: - Renounce ownership - Transfer ownership (maybe to uncontrolled address) - Update the order fee rates of a given currency - Update the Circuit breaker limit range of a given currency - Initialize a lending market - Create an order book - Trigger an emergency termination to stop the protocol - Update the minimum debt unit price - Operator can: - Pause a lending market - Unpause a lending market - Renounce its role - DefaultAdmin can: - Grant DefaultAdmin role to an address - Revoke DefaultAdmin role from an address - Renounce its role - Grant Operator role to an address - Revoke Operator role from an address - Update the admin role of a role, which means which roles can manage (grant/revoke) other roles. <br> #### ProxyController - Owner can: - Renounce ownership - Transfer ownership (maybe to uncontrolled address) - Update in a batch the admin of a set of proxies deployed by this contract to an arbitrary new admin. - Update the implementation contract to an arbitrary contract and provide initialization data for the contracts: - AddressResolver - BeaconProxyController - TokenVault - CurrencyController - GenesisValueVault - LendingMarketController - ReserveFund - For each contract: - a UpgradeableProxy is deployed if none was deployed until now for this given contract. - If the new contract contains: - a self.destruct instruction, existing proxy contracts could self-destruct. - a function to transfer all funds to an arbitrary address, existing proxy contracts could be drained. <br> #### ReserveFund - Owner can: - Renounce ownership - Transfer ownership (maybe to uncontrolled address) - Execute a transaction (or a batch) via arbitrary call to arbitrary addresses with arbitrary payloads. It includes sending to an arbitrary address tokens owned by the `ReserveFund` contract. - Deposit tokens to the token vault - Withdraw tokens held by ReserveFund from the token vault <br> #### TokenVault - Owner can: - Renounce ownership - Transfer ownership (maybe to uncontrolled address) - Register a currency to be accepted as a collateral - Unregister a currency to be accepted as a collateral - Accepted Contracts can: - Trigger a deposit of collateral from any user that approved that contract to do so - Add a deposit amount for a user - Remove a deposit amount for a user - Force the reset of the deposit amount of a user - Transfer tokens from a user - Operator can: - Pause the token vault - Unpause the token vault - Renounce its role - DefaultAdmin can: - Grant DefaultAdmin role to
Open the reportSome ERC20 tokens can change the balance of accounts outside of transfer methods. These tokens are commonly referred to as rebasing tokens. Since the protocol only ensures that an expected amount of tokens is received after a transfer, tokens that change the balance through other methods will disrupt internal accounting. Here are some tokens that can also affect the protocol operation: - Tokens that can be paused - Tokens with allowlist/blocklist - Tokens that can be upgraded
Open the reportThe price feeds associated with a currency `C` can temporarily not update their price. In this case, this will be detected via the function `CurrencyController._getAggregatedLastPrice()` which will raise an error `StalePriceFeed`. This would make all flows involving getting a price for `C` revert. However, any other flow will still work, including the ones involving getting prices of other currencies.
Open the reportThe following functions let a transaction execute normally even if it does not result in a state modification, resulting in gas spent when it was not needed: 1. In the function `ProxyController.changeProxyAdmins()` if the list `destinations` is empty 2. In the functions `ReserveFund.pause()` and `ReserveFund.unpause()` 3. In the function `CurrencyController.removeCurrency()` if the removed currency does not exist
Open the reportMost of the contracts within the Secured Finance protocol are upgradeable, implementing the EIP-1967 storage slots in transparent and beacon proxy patterns. While this is not a vulnerability, users should be aware that the behavior of the protocol could drastically change if the contracts are upgraded. **Furthermore, new vulnerabilities not present during the audit could be introduced in upgraded versions of the contract, including the transfer of funds or transfer tokens that were allowed to the protocol.** This audit does not guarantee the behavior of future contracts that may be upgraded.
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="secured-finance"></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