Hashflow security record

BNB Chain, Ethereumhashflow.comX

As of 3 Nov 2026, Hashflow has 4 audit reports by 3 security firms on Trustblock; the latest is by Quantstamp, dated 22 Mar 2023. Those reports list no open critical findings. It also holds 2 deployed contracts on 2 chains and 1 incident (latest 13 Jun 2023).

Critical findings
No open critical findings
Across 4 reports.
Incident
Incident 13 Jun 2023
Source: De.Fi incident database. No audit on Trustblock is dated after it. See the incident
Open the latest report
Your label, live
Get the label for your site

Record last updated . It holds audits, findings and contracts up to Nov 2026, and incidents up to Oct 2026. Trustblock does not review code.

Audits4

Newest first

AuditSecurity firmDateScopeCritical findingsReport
Hashflow HashverseSecurity firm: QuantstampDate: Scope: Files named in the reportNo open critical findingsOpen · certificate.quantstamp.com
Hashflow TokenSecurity firm: HashExDate: Scope: 2 addresses on Ethereum and BNB ChainNo open critical findingsOpen · hashex.org
Hashflow TokenSecurity firm: HashExDate: Scope: 1 address on EthereumNo open critical findingsOpen · IPFS
Hashflow-Audit3Security firm: CertiKDate: Scope: Files named in the reportNo open critical findingsOpen · skynet.certik.com

Findings31

Statuses are the security firm’s own, from each report.

SeverityOpenAcknowledgedFixed
Critical000
High011
Medium001
Low3520
HighParticipating in Quests with Tokens that Do Not Preserve Amount on Transfer May Lead to Improper AccountingHashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

When a user deposits tokens into a quest, they do so using a struct, `TokenDeposit`, that includes the address of the token and the amount that will go into `safeTransferFrom()`. Moreover, the amount of tokens that a user is allowed to trade with in a quest depends on the `portfolioTokenBalances`, which is increased by the `TokenDeposit` amount when depositing tokens via `_depositTokens()`. As a result, if the `transferFrom` function does not act strictly via the input amount when changing balances (for example, in the case of deflationary tokens), then users may be able to trade with more tokens than actually reached the contract when depositing them, as other users may have deposited funds ahead of them. Consequently, the users who trade later may be unable to trade with the full amount of what they deposited. `potfolioTokenBalances` is also used when determining how much users are able to withdraw. Hence, if the amount of a token in the contract is lower than the cumulative amount recorded in `portfolioTokenBalances`, some users will be unable to withdraw in accordance with their rightful proportion of the total funds in the contract.

Open the report
MediumItems Can Be Bridged to Inactive ChainHashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

Users can bridge their items between chains by calling `wormholeBridgeOut()` in `RenovaItem` and `RenovaItemSatellite`. The user chooses the destination Wormhole chain ID with `dstWormholeChainId`. If the user passes the chain ID for a chain that does not have a `RenovaItemSatellite` contract deployed, the item is essentially lost as the item is burnt on the source chain during the bridging. There are no relevant checks to ensure that the destination chain is configured for bridging Renova items.

Open the report
Low`XChainBridgeOut` Event Emitted with Incorrect `hashverseItemId`Hashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

When bridging a Renova item to another chain, the user calls `wormholeBridgeOut()` on the source chain. After the item is burnt on the source chain, the line `delete _hashverseItemIds[tokenId];` deletes the Hashverse item ID associated with the token ID. However, after deleting the Hashverse item ID from the mapping, the event `XChainBridgeOut` calls `_hashverseItemIds[tokenId]` again to get the associated Hashverse ID. Therefore, the emitted Hashverse item ID will always be `0`.

Open the report
LowA Singular Merkle Tree Cannot Reward a User Multiple TimesHashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

In `mintItem()`, minted items are tracked using the `rootId` and `tokenOwner` address. If a `rootId` happens to reward a user multiple times, every call to `mintItem()` after the first one will fail.

Open the report
LowCannot Create Quests without ItemsHashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

When creating quests, the maximum number of items is assigned to `_maxItemsPerPlayer`. In `_loadItems()`, if `_maxItemsPerPlayer` is set to zero, then the maximum number of items is `type(uint256).max`. Therefore, the smallest maximum number of items a quest can have is one.

Open the report
LowCode Reuse May Lead to Wormhole Replay Attack Due to VAA Hash Not Being Marked as ProcessedHashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

One attack vector that must be accounted for when implementing cross-chain functionality is that of replay attacks. It is possible for someone to design a system implementing Wormhole that allows a VAA coming from some chain to be transmitted more than once on the destination chain, as the Wormhole core layer contract does not prevent this. Therefore, it is the responsibility of the system designer to determine whether this is a desirable trait and, if not, to implement a countermeasure. In the case of Hashverse, there are two possible cross-chain messages to consider with respect to this issue. The first message is cross-chain minting of avatars. Any address is able to mint an avatar NFT; this NFT is soulbound (the transfer function is disabled) and the first minting must be on Ethereum Mainnet. It also cannot be burned. Subsequently, users can use the `RenovaAvatar.wormholeMintSend()` function to mint this avatar NFT on another chain and to the same address as it belonged to on Ethereum Mainnet. Attempting to replay the emitted VAA would accomplish nothing as the previously cross-chain minted NFT would still be at the same address, causing the attempt at replaying the VAA to revert. The second message is cross-chain transferring of items. Items are NFTs that can only be initially minted on Ethereum Mainnet. These mints are controlled -- they either require the minting user to be directly authorized by the NFT contract owner, or they must be minted through the command deck, either directly by the admin of the command deck, or a process involving Merkle trees controlled by the admin of the command deck. Once minted, an item can be sent to another chain by use of the `RenovaItem.wormholeBridgeOut()` function -- this burns the item on the source chain and emits a VAA that when received on the destination chain will mint the item with the same `tokenId`. To prevent replaying of the VAA, each VAA is sent with a nonce associated with the item and that increases every time the item is sent to another chain. Hence, attempting to replay the VAA would only result in execution being reverted. Therefore, there are overall no concerns about cross-chain replay attacks in the current project. However, the `WormholeBaseUpgradeable` contract is an abstract contract that developers may want to reuse in other projects. It is important to note that, in general, this contract does not prevent replaying VAAs in the `_wormholeReceive()` function.

Open the report
LowDenial of Service for Quests when `_maxPlayers` Is SmallHashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

Users can enter a quest as long as it is before the start time and the maximum number of players has not been reached. Once a user has entered a quest, `numRegisteredPlayers` is incremented. If `_maxPlayers` is small, a malicious actor could quickly register effectively inactive players until the maximum number of players is met. This would cause the malicious actor to be the only active player in the quest and deny other users the ability to play. Additionally, when entering a quest, `numRegisteredPlayersPerFaction` is incremented for the faction the user selected. If a quest is designed to have opposing factions compete against each other, a malicious actor could quickly register inactive players for the opposing faction to increase the malicious actor's chances of winning.

Open the report
LowGreedy ContractHashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

A greedy contract is a contract that can receive ether which can never be redeemed. `RenovaItemBase.wormholeBridgeOut()` is a payable function which means that users can send ETH to the contract using this function; however, at no point does this contract use any ETH in its functions, nor is there any means to withdraw ETH from the contract. Notably, ETH would ordinarily be used for interacting with Wormhole via `publishMessage()`.

Open the report
LowIncorrect Event Emission for `updateHashflowRouter()`Hashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

The ordering of the parameters to the event `UpdateHashflowRouter` in `updateHashflowRouter()` is incorrect, as it currently suggests that we are updating the Hashflow router from the new router to the old one, based on the documentation of the event in the interface.

Open the report
LowMissing Input ValidationHashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

It is important to validate inputs, even if they only come from trusted addresses, to avoid human error. Specifically, in the following functions arguments of type `address` may be initialized with value `0x0`: * `RenovaCommandDeckBase.updateRenovaItem()`: `_renovaItem` * `RenovaCommandDeckBase.updateRenovaAvatar()`: `_renovaAvatar` * `RenovaCommandDeckBase.updateHashflowRouter()`: `_hashflowRouter` * `RenovaAvatarBase.__RenovaAvatarBase_init()`: `_renovaCommandDeck`

Open the report
Show 10 more
LowPotential Locked Funds Due to Positive SlippageHashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

The `require` statement in `RenovaQuest.trade()#L335` checks that `balanceBefore + quoteTokenAmount <= balanceAfter`. If the trade has positive slippage, say the user receives more tokens than quoted, then the extra funds will be locked in the account. In [Hashflow's documentation](https://docs.hashflow.com/hashflow/), it is claimed that the trading platform provides zero-slippage trade, so this should not happen. If this is indeed the case, we should enforce strict equality instead, namely `balanceBefore + quoteTokenAmount == balanceAfter`.

Open the report
LowSolidity Version `0.8.13` Is BuggedHashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

Solidity versions `0.8.13` and `0.8.14` [contain important bugs](https://blog.soliditylang.org/2022/06/15/solidity-0.8.15-release-announcement/), that if exploited, could result in serious issues. These bugs were fixed in `0.8.15`.

Open the report
LowTrapped Items when the Item Address Is Updated During Active QuestsHashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

The Hashflow team retains the ability to update `renovaItem` by calling `RenovaCommandDeckBase.updateRenovaItem()`. If the Renova item contract is updated while a user has loaded their items into a quest, the user will not be able to unload their items once the quest is complete. This is due to `RenovaQuest.unloadAllItems()` calling `RenovaCommandDeckBase.renovaItem()` to get the Renova item address, which is then used to transfer the items back to the user.

Open the report
LowUnable to Pay Wormhole Fee During `publishMessage()`Hashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

In order to use Wormhole, the user must first cause the emission of a Verifiable Action Approval (VAA) by callling the `publishMessage()` function of the Wormhole core layer [implementation contract](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Implementation.sol) . In order for this call to succeed, the call's `msg.value` field must be equal to `messageFee()`, a variable of the implementation contract. In `WormholeBaseUpgradeable`, there is a call to `publishMessage()`, but it is always with `msg.value` set to zero. Currently, `messageFee()` returns zero. However, in the future, it is possible for Wormhole to increase this fee, causing all attempts to call `publishMessage()` through `WormholeBaseUpgradeable` to revert, and hence preventing any attempts at cross-chain minting of avatars and cross-chain transferring of items.

Open the report
LowUnchecked Return Value During ERC20 ApprovalHashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

In `trade()`, the function makes an ERC20 approval but does not check the return value. As a result, if the `approve()` function returns false, this may go entirely unnoticed depending on the implementation behind `IHashflowRouter`.

Open the report
LowUpgradeable Contracts Should Include Constructors with `_disableInitializers()`Hashflow Hashverse · Quantstamp · 22 Mar 2023Fixed

The implementation contract behind a proxy can be initialized by any address. This is not a security problem in the sense that it impacts the system directly, as the attacker will not be able to cause any contract to self-destruct or modify any values in the proxy contracts. However, taking ownership of implementation contracts can open other attack vectors, like social engineering or phishing attacks.

Open the report
LowInconsistency Between Comment and CodeHashflow-Audit3 · CertiK · 19 Sep 2022Fixed

There is an inconsistency between code and comment on L654. The comments for multi-hop trades is incorrectly placed in the single-hop trade code block.

Open the report
LowInefficient Conditional StatementHashflow-Audit3 · CertiK · 19 Sep 2022Fixed

Comparison `percentWithdrawLimit >= 0`, that is always true, may be unnecessary. ```solidity=119 require( percentWithdrawLimit >= 0 && percentWithdrawLimit <= 100, 'HashflowGovernance: Number should be a percentage.' ); ```

Open the report
LowLack of Storage Gap in Upgradeable ContractHashflow-Audit3 · CertiK · 19 Sep 2022Fixed

For upgradeable contracts, there must be a storage gap to "allow developers to freely add new state variables in the future without compromising the storage compatibility with existing deployments". Otherwise, it may be very difficult to write new implementation code. Without storage gap, the variable in the child contract might be overwritten by the upgraded base contract if new variables are added to the base contract. Refer to https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable

Open the report
LowMissing Pool Authority Check in RFQt Cross ChainHashflow-Audit3 · CertiK · 19 Sep 2022Fixed

In contract `HashflowRouter`, function `tradeXChain()` proceeds without using `_isPoolAuthorized()` function to confirm if the quote.pool is allowed, whereas this check is carried out in RFQm process.

Open the report
Show 2 more
LowTypos in Comments and Error MessagesHashflow-Audit3 · CertiK · 19 Sep 2022Fixed

Several typos were found in the comments of different files.

Open the report
LowUser-Defined GettersHashflow-Audit3 · CertiK · 19 Sep 2022Fixed

The linked functions are equivalent to the compiler-generated getter functions for the respective variables.

Open the report

Incidents1

Attached through a shared contract address. Our incident data ends in Oct 2026.

Incident

Incident,

Source: De.Fi incident database.

Audits before it
4.
Audits since
None on Trustblock.

Contracts2

AddressChainSource code
0xb3999f658c0391d94a37f7ff328f3fec942bcadcChain: BNB ChainSource code: Verified source
0xb3999f658c0391d94a37f7ff328f3fec942bcadcChain: EthereumSource code: Verified source

All 2 addresses and the files the reports name

Show this on your site

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.

Content

Facts

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.

Fixed as
Language

Style

Layout
Theme
Accent
Corners

Format

Size
Date
Embed as
HTML
<head>
<script src="https://widget.trustblock.run/project-widget.min.js" defer></script>
</head>
<body>
<div
data-tb-project-widget
data-tb-project-slug="hashflow"
></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