Kontos

CertiKFiles named in the report

CertiK reviewed Kontos on 12 Dec 2023: 28 findings, 0 critical; 9 marked fixed, 2 acknowledged, 17 open.

No open critical findings
Open the reportOpen Kontos’s security record

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings28

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

SeverityOpenAcknowledgedFixed
Critical000
High020
Medium702
Low1007
MediumDeviation from an Important Design Goals of AccouOpen

The creation of new SmartAccount (in the form of a `BeaconProxy`) uses the `create` opcode instead of the `create2` opcode. This deviates from a key design goal of account abstraction. According to EIP4337 (https://eips.ethereum.org/EIPS/eip-4337#first-time-account-creation): "The factory is expected to use CREATE2 (not CREATE) to create the wallet, so that the order of creation of wallets doesn’t interfere with the generated addresses." Also, the `createSmartAccount()` function should return the wallet account address even if it has already been created, so the use of the `require` statement in line 51 is incompatible with EIP4337. Separately, according to EIP4337, signature verification should take place at the account level instead of in the `EntryPoint` contract. Based on https://eips.ethereum.org/EIPS/eip-4337#specification: The account MUST validate the caller is a trusted EntryPoint. If the account does not support signature aggregation, it MUST validate the signature is a valid signature of the userOpHash, and SHOULD return SIG_VALIDATION_FAILED (and not revert) on signature mismatch. Any other error should revert. An account that works with aggregated signature, should return its signature aggregator address in the “sigAuthorizer” return value of validateUserOp.

MediumLack of Protection of the Initialize FunctionsOpen

In the `SmartAccountFactory` contract, the `initialize()`, `initBeacon()`, and `initEntryPoint()` functions can be called by anyone. A malicious user could potentially front run the call to these functions and set malicious `beacon`, `entryPoint`, and `kontosLightNode` addresses. In the `EntryPoint` contract, the `initGenesisBrokerAccount()` function can be called by anyone. A malicious user could potentially front run the call to this function and set malicious `broker` addresses.

MediumMissing Signature Verification in SmartAccountOpen

The `isValidSignature()` function does not perform any signature verification and returns the truthy value for any input value. This deviates from a key goal of account abstraction, which is to allow users to use smart contract wallets containing arbitrary verification logic (reference: https://eips.ethereum.org/EIPS/eip-4337#motivation).

MediumMissing Validity Check on `_pk`Open

The `updatePubKey()` function updates the SmartAccount's public keys. There's no check that the new `_pk` is valid and corresponds to a point on the chosen elliptical curve. The lack of validation could result in invalid public keys being set for the SmartAccount, which means no signature validation can be successful afterwards.

MediumPrepayment of Funds and Gas Refund IssuesOpen

The account abstraction workflow includes the prepayment of gas and the refund of unused gas fee. The prepayment of gas fee should be from the user/user's smart account (or user directed PayMaster in the original EIP4337 design) to the bundler which calls the `handleOps()` function and incurs gas cost. However, in line 177 of the `EntryPoint` contract, the prepayment workflow transfers the asset from the `payer`, which is the `broker` in line 128, to the `accountProxy` which is the user's smart account address. This is not consistent with the EIP4337 design. If the intention here is that the `broker` will subsidize users to execute their transactions, then there should be economic incentive for the broker to do so, and such logic is not included in the in-scope smart contracts. Furthermore, while the `actualGasCost` is measured in line 189, there is no actual gas refund mechanism. In EIP4337, the intended design is that the difference between the prepayment amount and the `actualGasCost` will be refunded to the user or user designated paymaster in the form of increased deposit.

MediumUnclear Usage of Variables and Missing FunctionalOpen

The `SmartAccount` contract contains several variables with unclear usage. The existence of several variables and the lack of usage indicate that certain important functions are missing in the contract, such as replay protection. The `_kontosAddress` and `_kontosLightNode` variables are initialized or contain a default value, but is not used within the contract. The `_eoaOwner` is never initialized, which makes the `require` statement in line 98 always fail. THe `_slot` and `_usedProofs` variables are never used. The `_nonce` variable is updated in line 115 but there is no check that the `_nonce` has not bee used previously. The lack of usage of `_usedProofs` and `_nonce` indicate missing replay protection. In the `EntryPoint` contract, the `strandedAssets` variable in line 22 is declared but never used.

MediumVariable Usage Before Setting ValueOpen

The variable `_eoaOwner` is never set and defaults to the zero address. This makes the `executeBatchByEOAOwner()` function uncallable due to the `require` statement in line 98, and breaks a key functionality of the `SmartAccount` contract.

LowDuplicate VariableOpen

In the `SmartAccountBeacon` contract, the value of `target` always equals `implementation()`, and is therefore duplicative.

LowInconsistency Between `startUpgrade()` and `canceOpen

The `startUpgrade()` function takes in an array of `_indexes`, and the `cancelUpgrade()` function takes in a single `_index`. However, even if a single `_index` is cancelled, the global `upgradeStatus` is set to `Idle` in line 81, which would cause the `startPreparation()` function to revert due to the check in line 90. In other words, canceling one `_index` essentially prevents all `_indexes` from being upgraded.

LowLocked Blockchain Native TokensOpen

The contract has payable functions, making it able to receive native tokens. However, it does not have a function to withdraw the funds, which can lead to permanently locked tokens within the contract.

Show 7 more
LowMissing Inheritance of `BaseProxy`Open

The `initUpgradeGateKeeper()` function in the `DeployFactory` contract indicates that the `upgradeGateKeeper` contract should be a `BaseProxy` contract: ```solidity=67 upgradeGateKeeperProxy = BaseProxy(payable(deployedAddress)); ``` However, the `upgradeGateKeeper` contract does not inherit `BaseProxy`: ```solidity=9 contract UpgradeGateKeeper is UpgradeEvents, IProxy, UpgradeableOwnable ```

LowMissing Logic in the `addUpgradeable()` FunctionOpen

The `addUpgradable()` function in the `DeployFactory` contract adds a contract to be upgraded by the `UpgradeGateKeeper` contract. There is no check that the `_index` already has a corresponding proxy to be upgraded, and there's no check that the `UpgradeGateKeeper` contract is the `master` of the `_proxy`. The implication is that a contract that is already in the upgrade process could be overwritten, or the `finishUpgrade()` function would revert due to the lack of `master` role in line 109 of the `UpgradeGateKeeper` contract.

LowNew Smart Account Creation and Update of Public KOpen

In the `SmartAccountFactory` contract, the `createSmartAccount()` function is used to create new smart account. Due to the check in line 51, each `_nameAddr` can only have one smart account. ```solidity=50 _requireFromEntryPoint(); require(address(accounts[_nameAddr]) == address(0), "account exists"); ``` In the `EntryPoint` contract, the call to the `createSmartAccount()` function is in line 229. Note that the first function argument comes from an arbitrary user input, and is not dependent on the `_caller` address in line 217, which is the `msg.sender` in line 212. Given that `kontosLightNode` is out of scope, we'd like to understand if the kontos proof verification in line 204 ensures that the given `proofData.nameAddress` has signed the transaction being submitted. If not, a malicious user could create smart account for other user addresses and set the public key of the smart account, and deny the other users from creating their own smart accounts. ```solidity=229 aaAccount = accountFactory.createSmartAccount{gas: _proofTask.callGasLimit}(proofData.nameAddress, abi.encode(proofData.pk)); ``` Furthermore, if `hasAccount` is `true`, a malicious user could also update the `pk` of other users' existing smart account, due to the lack of constraint in the code block below ```solidity=224 if (hasAccount) { ISmartAccount account = accountFactory.getSmartAccount(proofData.nameAddress); aaAccount = address(account); account.updatePubKey{gas: _proofTask.callGasLimit}(proofData.pk); ```

LowSome managed contracts might not contain the `upgOpen

In the `finishUpgrade()` function, line 109 calls the `upgradeTarget()` function of the specific managed contract. This assumes that the managed contract contains the `upgradeTarget()` function. Note that in multiple upgradeable contracts in the code base, an `upgrade()` function is included instead. ```solidity=109 managedContracts[index].upgradeTarget(nextTargets[index], targetsUpgradeParameters[i]); ```

LowThird-Party and Out-of-Scope Dependency UsageOpen

The `FTConnector` contract is serving as the underlying entity to interact with one or more third party protocols or out of scope contracts, such as `lightNode`, `ConnectorHub`, `TokenFactory`, etc.. The scope of the audit treats them as black boxes and assumes their functional correctness. However, in the real world, third parties and out of scope contracts can be compromised and this may lead to lost or stolen assets. The `EntryPoint` contract delegates signature verification to the `sigVerifier` contract in line 124, and `kontosLightNode` in line 204. The `sigVerifier` and `kontosLightNode` contracts are out of scope, and are treated as blackboxes and assumed to be functionally correct. Importantly, because the `SmartAccount` contract does not perform signature verification, it is assumed that the `sigVerifier` correctly verifies all signatures included in the `sigInfos` individually. If such an assumption is broken, then the `EntryPoint` contract could be used to trigger unauthorized transactions on any user's Smart Account, which would be the most severe security breach of the project.

LowUnused ValueOpen

The smart contract contains one or more values that are not used, which can lead to unnecessary complexity and reduced maintainability. --- ```solidity=70 (address sender, uint256 sourceChainId, uint256 targetChainId, address connector, bytes memory connectedInfo) = abi.decode(proofTask.data, (address, uint256, uint256, address, bytes)); ``` - The variable `sourceChainId` is never used after this assignment. Instead, `_ftConnectorEvent.sourceChainId` is used in line 75.

LowUser-Defined GettersOpen

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

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Repository and files the report names (7)

  • contracts/aa/contracts/EntryPoint.sol
  • contracts/aa/contracts/SmartAccountFactory.sol
  • contracts/aa/contracts/SmartAccount.sol
  • contracts/aa/contracts/UpgradeGateKeeper.sol
  • contracts/light/contracts/connector/erc20/FTConnector.sol
  • contracts/aa/contracts/DeployFactory.sol
  • contracts/aa/contracts/SmartAccountBeacon.sol

Part of Kontos’s security record

Kontos
Audits1 audit by 1 firmLast audit Dec 2023, by CertiK.
Critical findingsNo open critical findingsIn 1 report.
Open Kontos’s security record

Security firm

CertiK

1,044 projects reviewed · 1,375 reports · latest May 2025

See CertiK’s audits

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