KonnektVPN - Audit

CertiKFiles named in the report

CertiK reviewed KonnektVPN (KonnektVPN - Audit) on 5 Mar 2024: 17 findings, 0 critical; 15 marked fixed, 2 open.

No open critical findings
Open KonnektVPN’s security record

The original report was removed from its address (seen 14 Oct 2026).

Trustblock does not review code.

Findings17

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

SeverityOpenAcknowledgedFixed
Critical000
High101
Medium003
Low1011
HighInitial Token DistributionFixed

200000000000000000000000000 of the `KPN` tokens are sent to the contract deployer when deploying the contract. This could be a centralization risk as the anonymous deployer can distribute tokens without obtaining the consensus of the community. Any compromise to the deployer account that holds undistributed tokens may allow the attacker to steal and sell tokens on the market, resulting in severe damage to the project.

MediumInconsistency DecimalFixed

According to L32-L60, the decimals of the rewards are 18. The rewards are paid using USDT. But the decimal of the USDT is 6. The inconsistency may lead to the project's loss. ```solidity=32 uint256 public tier1mon6 = 750 * (10**18); uint256 public tier1mon12 = 1800 * (10**18); uint256 public tier1mon24 = 4500 * (10**18); // TIER 2 uint256 public tier2mon6 = 1500 * (10**18); uint256 public tier2mon12 = 3500 * (10**18); uint256 public tier2mon24 = 8000 * (10**18); // TIER 3 uint256 public tier3mon6 = 4200 * (10**18); uint256 public tier3mon12 = 9000 * (10**18); uint256 public tier3mon24 = 21000 * (10**18); // TIER 4 uint256 public tier4mon6 = 8000 * (10**18); uint256 public tier4mon12 = 17000 * (10**18); uint256 public tier4mon24 = 37000 * (10**18); // TIER 5 uint256 public tier5mon6 = 13500 * (10**18); uint256 public tier5mon12 = 28500 * (10**18); uint256 public tier5mon24 = 58500 * (10**18); // TIER 6 uint256 public tier6mon6 = 25000 * (10**18); uint256 public tier6mon12 = 50000 * (10**18); uint256 public tier6mon24 = 112500 * (10**18); ``` ```solidity=209 function _payUSDT(address _target, uint rewardAmount) internal { IERC20(USDT).transfer(_target, rewardAmount); emit RewardsPaid(_target, rewardAmount); } ```

MediumPotential DOS AttackFixed

The issue lies within the `claimTokens` function where the `KPNToken` is an `ERC777` token. ```solidity=49 function claimTokens() public{ require(owner == msg.sender, "Claiming ERC20: Only contract owner can call function"); require(whiteList.length > 0, "Claiming ERC20: No addresses on whitelist"); uint256 totalSendAmount = _calculateTotalClaim(); require(KPNToken.balanceOf(address(this)) >= totalSendAmount, "Claiming ERC20: Contract Balance Too Low"); for(uint i = 0; i < whiteList.length; i++){ uint256 sendAmount = whiteList[i].amount; address target = whiteList[i].target; whiteList[i].amount = 0; KPNToken.transfer(target, sendAmount); } emit BulkTokenClaim(totalSendAmount, block.timestamp); } ``` If the user is a malicious contract that either lacks a `tokensReceived()` function or explicitly rejects the saleTokens, this will lead to the entire transaction being reverted. This means that users will be unable to receive the claimed tokens - a situation known as a denial of service (DoS) attack.

MediumPotential Unable to Claim the Locked Token Due toFixed

If there isn't sufficient USDT available in the `LockTokens`, users are unable to directly reclaim their locked `KPN`. There are two ways of withdrawing `KPN` from the contract: `cancelStake` and `withdrawLocked`. The `cancelStake` is using to withdraw locked token before the `lock` expired. ```solidity=172 function cancelStake() public { require(block.timestamp < lockedBalances[msg.sender].lockTime + lockedBalances[msg.sender].timestamp, "ERC20: Cannot Cancel Completed Stake"); ``` The `withdrawLocked` function is utilized to retrieve locked tokens once the `lock` period has ended. However, should there be insufficient USDT available to cover the rewards, the transaction will fail, preventing users from withdrawing their tokens. Additionally, once the `lock` period is over, users are unable to withdraw their tokens by using the `cancelStake` function. Therefore, the sole option for users wanting to withdraw their tokens, in the event that the contract lacks sufficient USDT, is to place a new stake and then cancel this recent stake. ```solidity=189 function withdrawLocked() public { require(block.timestamp > lockedBalances[msg.sender].lockTime + lockedBalances[msg.sender].timestamp, "ERC20: Time Lock not complete"); require(lockedBalances[msg.sender].amount > 0, "ERC20: No Funds Locked"); uint256 tokenAmount = lockedBalances[msg.sender].amount; // gets local copy of variable to save on gas cost require(KPN.balanceOf(address(this)) >= tokenAmount, "ERC20: Contract Balance Too Low"); LockAmount memory lockStruct = lockedBalances[msg.sender]; totalLockedTokens -= tokenAmount; // deletes the staking struct delete lockedBalances[msg.sender]; // approves and transfers kpn balance from this contract KPN.approve(address(this), tokenAmount); KPN.transferFrom(address(this), msg.sender, tokenAmount); _payUSDT(msg.sender, lockStruct.rewardAmount); emit TokensWithdrawn(msg.sender, block.timestamp); } ```

LowIncompatibility with Deflationary TokensFixed

When transferring deflationary ERC20 tokens, the input amount may not be equal to the received amount due to the charged transaction fee. For example, if a user sends 100 deflationary tokens (with a 10% transaction fee), only 90 tokens actually arrived to the contract. However, a failure to discount such fees may allow the same user to withdraw 100 tokens from the contract, which causes the contract to lose 10 tokens in such a transaction. Reference: https://thoreum-finance.medium.com/what-exploit-happened-today-for-gocerberus-and-garuda-also-for-lokum-ybear-piggy-caramelswap-3943ee23a39f

LowMissing Zero Address ValidationFixed

Addresses are not validated before assignment or external calls, potentially allowing the use of zero addresses and leading to unexpected behavior or vulnerabilities. For example, transferring tokens to a zero address can result in a permanent loss of those tokens. ```solidity=83 USDT = rewardsToken; ``` - `rewardsToken` is not zero-checked before being used. --- ```solidity=271 USDT = _usdt; ``` - `_usdt` is not zero-checked before being used. --- ```solidity=17 KPNToken = IERC20(kpnToken); ``` - `KPNToken` is not zero-checked before being used.

LowRedundant ComparisonsFixed

Comparisons that are always true or always false may be incorrect or unnecessary. ```solidity=90 require(amount >= 0, "ERC20: Cannot send 0 tokens"); ```

LowSource of Reward TokenFixed

In contract `LockTokens`, the reward token is the `USDT` token, but it is only initialized with an uncertain address and the actual implementation is unknown. In the function `withdrawLocked()` which the users use to retrieve the reward tokens, the `USDT` token is transferred to the retriever from the current contract. However, we do not find the code that mints or transfers the `USDT` token to the current contract.

LowState Variable Should Be Declared ConstantFixed

State variables that never change should be declared as `constant` to save gas. ```solidity=15 uint256 public maxSupply = 8000000000000000000000000000; ``` - `maxSupply` should be declared `constant`. --- ```solidity=16 uint256 public tier1Cutoff = 750000 * (10**18); ``` - `tier1Cutoff` should be declared `constant`. --- ```solidity=17 uint256 public tier2Cutoff = 1250000 * (10**18); ``` - `tier2Cutoff` should be declared `constant`. --- ```solidity=18 uint256 public tier3Cutoff = 3000000 * (10**18); ``` - `tier3Cutoff` should be declared `constant`. --- ```solidity=19 uint256 public tier4Cutoff = 5000000 * (10**18); ``` - `tier4Cutoff` should be declared `constant`. --- ```solidity=20 uint256 public tier5Cutoff = 7500000 * (10**18); ``` - `tier5Cutoff` should be declared `constant`. --- ```solidity=21 uint256 public tier6Cutoff = 12500000 * (10**18); ``` - `tier6Cutoff` should be declared `constant`. --- ```solidity=24 uint256 public locktime1 = 180 days; ``` - `locktime1` should be declared `constant`. --- ```solidity=25 uint256 public locktime2 = 365 days; ``` - `locktime2` should be declared `constant`. --- ```solidity=26 uint256 public locktime3 = 730 days; ``` - `locktime3` should be declared `constant`.

LowThe list of `whitelistedAddresses` could potentiaFixed

In the `addToWhitelist()` function, if the `claimableTokens[newTarget]` is equal to 0, then `newTarget` will be added to the `whitelistedAddresses`. ```solidity=54 if (claimableTokens[newTarget] == 0) { whitelistedAddresses.push(newTarget); } ``` After a user claims their tokens via the `claimTokens()` function, the `claimableTokens[msg.sender]` will be reset to 0. ```solidity=63 claimableTokens[msg.sender] = 0; // Prevent Reentrancy ``` If the `addToWhitelist` function is invoked and the `newTarget` is the address of a user who has previously called `claimTokens`, then the address will be added to `whitelistedAddresses` once more. This could lead to duplicate entries in `whitelistedAddresses`.

Show 5 more
LowToo Many DigitsFixed

Literals with many digits are difficult to read and review.

LowUnchecked ERC-20 `transfer()`/`transferFrom()` CaFixed

The return values of the `transfer()` and `transferFrom()` calls in the smart contract are not checked. Some ERC-20 tokens' transfer functions return no values, while others return a bool value, they should be handled with care. If a function returns `false` instead of reverting upon failure, an unchecked failed transfer could be mistakenly considered successful in the contract. ```solidity=42 KPNToken.transfer(target, sendAmount); ``` --- ```solidity=53 KPNToken.transfer(target, amount); ``` --- ```solidity=79 KPNToken.transfer(addressList[i].target, addressList[i].amount); ``` --- ```solidity=98 KPN.transfer(msg.sender, refund); ``` --- ```solidity=110 KPN.transferFrom(msg.sender, address(this), lockAmount); ``` --- ```solidity=122 KPN.transferFrom(msg.sender, address(this), lockAmount); ``` --- ```solidity=132 KPN.transferFrom(msg.sender, address(this), lockAmount); ``` --- ```solidity=143 KPN.transferFrom(msg.sender, address(this), lockAmount); ``` --- ```solidity=154 KPN.transferFrom(msg.sender, address(this), lockAmount); ``` --- ```solidity=165 KPN.transferFrom(msg.sender, address(this), amount); ``` --- ```solidity=202 KPN.transferFrom(address(this), msg.sender, tokenAmount); ``` --- ```solidity=211 IERC20(USDT).transfer(_target, rewardAmount); ```

LowUnused Return ValueFixed

The smart contract does not check or store the return value of an external call in a local or state variable, which may introduce vulnerabilities due to the unhandled outcome. ```solidity=201 KPN.approve(address(this), tokenAmount); ```

LowUsing `transferFrom` is unnecessaryFixed

There is no need to use `approve` and `transferFrom` to transfer tokens from the contract to the `msg.sender`. ```solidity=201 KPN.approve(address(this), tokenAmount); KPN.transferFrom(address(this), msg.sender, tokenAmount); ```

LowVariables That Could Be Declared as ImmutableFixed

The linked variables assigned in the constructor can be declared as `immutable`. Immutable state variables can be assigned during contract creation but will remain constant throughout the lifetime of a deployed contract. A big advantage of immutable variables is that reading them is significantly cheaper than reading from regular state variables since they will not be stored in storage.

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 (3)

  • ClaimTokens.sol
  • KPNToken.sol
  • LockTokens.sol

Part of KonnektVPN’s security record

KonnektVPN
Audits2 audits by 2 firmsLast audit May 2024, by Cyberscope.
Critical findings2 open critical findingsReported in “KonnektVPN” by Cyberscope, May 2024. Not marked fixed in that report.
Open KonnektVPN’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