Haven1 security record

Ethereumhaven1.orgX

As of 30 Oct 2026, Haven1 has 2 audit reports by 1 security firm on Trustblock; the latest is by CertiK, dated 4 Mar 2025. Those reports list no open critical findings.

Critical findings
No open critical findings
Across the 2 reports, 4 critical findings were reported. Each is marked fixed by the firm that reported it. See the findings
Open the latest report
Your label, live
Get the label for your site

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

Audits2

Newest first

AuditSecurity firmDateScopeCritical findingsReport
Haven1 - Permission ManagerSecurity firm: CertiKDate: Scope: Files named in the report4 critical findings, fixedOpen · skynet.certik.com
Haven1 - audit hSwapSecurity firm: CertiKDate: Scope: Files named in the reportNo open critical findingsOpen · skynet.certik.com

Findings32

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

SeverityOpenAcknowledgedFixed
Critical004
High101
Medium102
Low11012
Critical"NONE" Role Grants Unrestricted Network Admin PrHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

The issue occurs when the `permissionsInterface.setPolicy("_nwAdminOrg", "NONE", "_oAdminRole")` function is called, which assigns the `"NONE"` role to the `_nwAdminRole`. This leads to unintended behavior in the system, as the role `"NONE"` is effectively treated as a valid role, bypassing proper access control mechanisms. Specifically, when calling `permissionsInterface.isNetworkAdmin(address(0xDEADBEEF))`, it incorrectly returns **true**, granting network admin privileges to any address assigned the `"NONE"` role. This allows unauthorized users to gain network admin status, undermining the security model of the application. The issue is caused by improper handling of the `"NONE"` role, which should not grant administrative privileges.

Open the report
CriticalImproper Assignment of "NONE" Role Bypasses AdminHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

The issue arises because the role `"NONE"` is being assigned through the function `permissionsInterface.addNewRole("NONE","_orgId",3,true,true)`, which inadvertently bypasses the intended role-based permission checks. When the `"NONE"` role is assigned, it causes the function `permissionsInterface.isOrgAdmin(address(0xDEADBEEF),"_orgId")` to always return true for the given address (e.g., `0xDEADBEEF`). This could allow unauthorized users or addresses to gain admin privileges, effectively bypassing the access control mechanism and potentially compromising the system's security. The issue is caused by the improper handling of the `"NONE"` role, leading to unintended behavior in the role validation logic.

Open the report
CriticalLack Of Access ControlHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

The smart contract suffers from a lack of access control, allowing any user to invoke sensitive functions such as: - `init()` - `setPolicy()` - `addAdminNode()` - `addAdminAccount()` - `updateNetworkBootStatus()` These functions are critical for managing admin nodes, accounts, and policies, and their unrestricted accessibility poses severe security risks. An attacker could exploit this flaw to gain unauthorized privileges, disrupt the system, or compromise its integrity, potentially resulting in financial losses, operational failures, and reputational damage.

Open the report
CriticalZero Address (0x0) Incorrectly Recognized as OrgHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

The issue lies in using the zero address (**0x0**) in the `permissionsInterface.isOrgAdmin(address(0x0), "_orgId")` function call. The problem occurs because the function incorrectly treats the zero address as a valid organization admin. This is unintended behavior, as the zero address should never be considered a legitimate admin. The use of **0x0** in this context bypasses proper validation and can potentially grant unauthorized access, leading to security risks in the system. The function should include checks to prevent the zero address from being mistakenly recognized as an admin.

Open the report
HighUninitialized `nodeIdToIndex` Mapping Causes `getHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

The issue with the `getNodeDetails()` function is that it relies on the nodeIdToIndex mapping, which is never initialized. Specifically, the check if `nodeIdToIndex[keccak256(abi.encode(_enodeId))] == 0` always returns **true** because the `nodeIdToIndex` mapping contains no entries, and thus the default value for any uninitialized key is **0**. As a result, the function fails to perform its intended logic and effectively becomes broken or useless

Open the report
MediumInconsistent Handling of active Flag and `votingSHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

The issue arises from inconsistent handling of the active flag and the `votingStatus` mapping. ```sol=179 for (uint256 i = 0; i < orgVoterList[id].voterList.length; i++) { if (orgVoterList[id].voterList[i].active) { orgVoterList[id].votingStatus[id][ orgVoterList[id].voterList[i].vAccount ] = false; } } ``` When the voting item is initialized the `votingStatus` of each `active` voter is reset to `false`. However, when the inactive voter is activated via `addVoter()`, its `votingStatus` is not updated and can still be `true`. This leads to inconsistency.

Open the report
MediumMisprint in Code Allows Bypass of Protection to AHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

The issue lies in the incorrect usage of `keccak256(abi.encode(abi.encode(_roleId)))` instead of the intended `keccak256(abi.encode(_roleId))` in the protection check. This misprint causes the condition to fail in certain scenarios, as the double `abi.encode()` results in incorrect hashing. As a result, the function fails to properly prevent the assignment of the "orgAdminRole", allowing unauthorized role assignments.

Open the report
LowEvent Not IndexedHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

If an event is not indexed in a smart contract, it means that the event's parameters are not tagged with the `indexed` keyword. This has implications for how the event data can be searched and filtered when looking through blockchain logs. Without indexing, the event will still emit the data as part of the transaction log, but users won't be able to query for these events using the parameters. They'll have to retrieve the entire set of logs and manually sift through them to find events with the specific data. This can be less efficient and more time-consuming, especially on a blockchain with a high volume of transactions and events.

Open the report
LowInefficient Memory ParameterHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

One or more parameters with `memory` data location are never modified in their functions and those functions are never called internally within the contract. Thus, their data location can be changed to `calldata` to avoid the gas consumption copying from calldata to memory. ```solidity=295 function approveNode( ``` `approveNode` has memory location parameters: `_enodeId`, `_ip`, `_orgId`. ```solidity=150 function addSubOrg( ``` `addSubOrg` has memory location parameters: `_pOrgId`, `_orgId`, `_enodeId`, `_ip`. ```solidity=674 function startBlacklistedNodeRecovery( ``` `startBlacklistedNodeRecovery` has memory location parameters: `_orgId`, `_enodeId`, `_ip`. ```solidity=301 function approveOrg( ``` `approveOrg` has memory location parameters: `_orgId`, `_enodeId`, `_ip`. ```solidity=599 function addNode( ``` `addNode` has memory location parameters: `_orgId`, `_enodeId`, `_ip`. ```solidity=123 function approveOrg( ``` `approveOrg` has memory location parameters: `_orgId`, `_enodeId`, `_ip`. ```solidity=254 function addNode( ``` `addNode` has memory location parameters: `_enodeId`, `_ip`, `_orgId`. ```solidity=70 function addRole( ``` `addRole` has memory location parameters: `_roleId`, `_orgId`. ```solidity=337 function updateNodeStatus( ``` `updateNodeStatus` has memory location parameters: `_orgId`, `_enodeId`, `_ip`. ```solidity=267 function addOrg( ``` `addOrg` has memory location parameters: `_orgId`, `_enodeId`, `_ip`. ```solidity=348 function checkOrgActive(string memory _orgId) public view returns (bool) { ``` `checkOrgActive` has memory location parameters: `_orgId`. ```solidity=234 function addAdminNode( ``` `addAdminNode` has memory location parameters: `_enodeId`, `_ip`, `_orgId`. ```solidity=797 function assignAccountRole( ``` `assignAccountRole` has memory location parameters: `_orgId`, `_roleId`. ```solidity=463 function connectionAllowed( ``` `connectionAllowed` has memory location parameters: `_enodeId`, `_ip`. ```solidity=306 function addNode( ``` `addNode` has memory location parameters: `_orgId`, `_enodeId`, `_ip`. ```solidity=96 function addOrg( ``` `addOrg` has memory location parameters: `_orgId`, `_enodeId`, `_ip`. ```solidity=363 function startBlacklistedNodeRecovery( ``` `startBlacklistedNodeRecovery` has memory location parameters: `_orgId`, `_enodeId`, `_ip`. ```solidity=387 function approveBlacklistedNodeRecovery( ``` `approveBlacklistedNodeRecovery` has memory location parameters: `_orgId`, `_enodeId`, `_ip`. ```solidity=274 function addOrgNode( ``` `addOrgNode` has memory location parameters: `_enodeId`, `_ip`, `_orgId`. ```solidity=630 function updateNodeStatus( ``` `updateNodeStatus` has memory location parameters: `_orgId`, `_enodeId`, `_ip`. ```solidity=706 function approveBlacklistedNodeRecovery( ``` `approveBlacklistedNodeRecovery` has memory location parameters: `_orgId`, `_enodeId`, `_ip`. ```solidity=58 function addAdminNode( ``` `addAdminNode` has memory location parameters: `_enodeId`, `_ip`. ```solidity=344 function updateNodeStatus( ``` `updateNodeStatus` has memory location parameters: `_enodeId`, `_ip`, `_orgId`.

Open the report
LowMisplaced SPDX license identifierHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

An SPDX (Software Package Data Exchange) license identifier is a standardized short-form identifier for software licenses. These identifiers are used to communicate the licensing components of software packages in a concise, consistent, and machine-readable manner. Placing the SPDX license identifier on the first line of a file is a best practice because it enhances visibility, ensures consistency, supports tool compatibility, and aids in standardizing license documentation across codebases. However, in the file, the SPDX license identifier is misplaced, thus the best practice is not followed. For more references: 1. [SPDX Official Website](https://spdx.org) 2. [GitHub Licensing a Repository Help Page**](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/licensing-a-repository) 3. [Open Source Initiative (OSI)](https://opensource.org/licenses/MIT) 4. [SPDX License List](https://spdx.org/licenses/)

Open the report
Show 9 more
LowMissing Zero Address ValidationHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

The cited address input is missing a check that it is not `address(0)`.

Open the report
LowPossible Loss Of the Data Due to Indexed DynamicHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

When attempting to index dynamic data types like `string`, `bytes`, `array`, or `struct` in Solidity, they don't get stored in their original form. Instead, the Ethereum log system stores the `Keccak-256` hash of these data types. While this approach ensures efficiency and cost-effectiveness, developers must be aware of it to correctly use and interpret logs, and they cannot retrieve the original string from its hash alone.

Open the report
LowRedundant Boolean Check in Return StatementHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

In the provided Solidity function, there is a redundant `boolean` check for `OrgIndex[keccak256(abi.encodePacked(_orgId))] != 0`. This condition is already evaluated earlier in the function, where it returns `false` if `OrgIndex[keccak256(abi.encodePacked(_orgId))] == 0`. Since the function would exit early in such cases, repeating this check in the return statement is unnecessary. This redundancy increases gas consumption and complicates the code without adding any functional value. Removing the repeated check can improve both efficiency and code readability.

Open the report
LowRedundant Code ComponentsHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

The linked statements do not affect the functionality of the codebase and appear to be either leftovers from test code or older functionality.

Open the report
LowState Variable Should Be Declared ConstantHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

State variable that never change should be declared as `constant` to save gas. ```solidity=27 uint256 private fullAccess = 3; ``` - `fullAccess` should be declared `constant`.

Open the report
LowUnused state variableHaven1 - Permission Manager · CertiK · 4 Mar 2025Fixed

Some state variables are not used in the codebase. This can lead to incomplete functionality or potential vulnerabilities if these variables are expected to be utilized. - Variable `networkBoot` in `OrgManager` is never used in `OrgManager`. - Variable `adminOrgId` in `OrgManager` is never used in `OrgManager`. - Variable `permUpgradable` in `PermissionsInterface` is never used in `PermissionsInterface`.

Open the report
LowH1 fee only charged once in `UniversalRouter` MulHaven1 - audit hSwap · CertiK · 26 Feb 2025Fixed

In the current implementation of `UniversalRouter`, the contract charges the fee once per transaction upon encountering the first swap command (V3_SWAP_EXACT_OUT or V3_SWAP_EXACT_IN), then exits the loop with break. This means if multiple swap commands are present in a single transaction , only the first swap will trigger a fee. Subsequent swaps in the same transaction will not pay additional fees. ```solidity=68 for (uint256 commandIndex = 0; commandIndex < numCommands; ) { bytes1 commandType = commands[commandIndex]; uint256 command = uint8(commandType & Commands.COMMAND_TYPE_MASK); if (command == Commands.V3_SWAP_EXACT_OUT || command == Commands.V3_SWAP_EXACT_IN) { _payH1Fee(); break; } unchecked { commandIndex++; } } ``` If the intended design is to collect only one fee per transaction, then the current logic is correct. If the contract should collect fees for each swap command, the logic should be adjusted.

Open the report
LowPotential Storage Slot Collision in Upgradeable CHaven1 - audit hSwap · CertiK · 26 Feb 2025Fixed

The contract uses a custom storage slot for `H1NativeBaseStorage`. Using a custom storage slot is typically safe for non-upgradeable deployments, as it ensures the contract writes to a unique location unlikely to overlap with other storage variables. However, in an upgradeable proxy setup, future contract upgrades or modules may introduce new variables that use or overlap with this same slot. ```solidity bytes32 private constant H1NATIVE_STORAGE = 0x8e7ec97a86b55b46cf58cbcd08faba09d3e8d3aec4d6bf8802477f1aa7a4c700; ... function _getH1NativeStorage() private pure returns (H1NativeBaseStorage storage $) { assembly { $.slot := H1NATIVE_STORAGE } } ``` If the contract (or a child contract) is later upgraded and new variables or inherited contracts introduce different storage layouts, it could overwrite or corrupt the existing state stored in `H1NATIVE_STORAGE`. Such collisions may cause unpredictable behavior or loss of state.

Open the report
LowUsage of Foundry's ConsoleHaven1 - audit hSwap · CertiK · 26 Feb 2025Fixed

The current contract code includes references to the `console` contract from Foundry. It is important to note that the `console` contract is exclusively intended for development and testing purposes, providing developers with debugging capabilities throughout the testing phase. ```solidity=61 function createPool( address tokenA, address tokenB, uint24 fee ) external override noDelegateCall returns (address pool) { console.log('createPool - 1'); require(tokenA != tokenB); console.log('createPool - 2'); (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); console.log('createPool - 3'); require(token0 != address(0)); console.log('createPool - 4'); int24 tickSpacing = feeAmountTickSpacing[fee]; console.log('createPool - 5'); require(tickSpacing != 0); console.log('createPool - 6'); require(getPool[token0][token1][fee] == address(0)); console.log('createPool - 7'); pool = deploy(address(this), token0, token1, fee, tickSpacing); console.log('createPool - 8'); getPool[token0][token1][fee] = pool; console.log('createPool - 9'); // populate mapping in the reverse direction, deliberate choice to avoid the cost of comparing addresses getPool[token1][token0][fee] = pool; console.log('createPool - 10 pool: ', pool); emit PoolCreated(token0, token1, fee, tickSpacing, pool); } ``` While the `console` code may be commented out and thus inactive, its presence within the contract codebase can still negatively impact the overall tidiness and cleanliness of the contract. Comments intended for developers' understanding and debugging purposes should not be present in the final production-ready version of the smart contract.

Open the report

Contracts

No deployed address is recorded for these audits.

The reports name a repository or files. Open a report to see its scope.

The repositories and 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="haven1"
></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