As of 3 Nov 2026, PerionXP has 1 audit report on Trustblock, by CertiK, dated 31 May 2023. That report lists no open critical findings.
Record last updated . It holds audits and findings, contracts and incidents up to Nov 2026. Trustblock does not review code.
Newest first
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 1 | 0 | 0 |
| Medium | 0 | 0 | 0 |
| Low | 2 | 0 | 6 |
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 a storage gap, the variable in **child contract** might be overwritten by the upgraded base contract if new variables are added to the base contract. Lack of Storage can lead to unexpected behavior during the upgrading of the base contract `TimeLockPool`. ```solidity=1 // SPDX-License-Identifier: MIT pragma solidity 0.8.7; import "./TimeLockPool.sol"; contract TimeLockNonTransferablePool is TimeLockPool { function initialize( string memory _name, string memory _symbol, address _depositToken, address _rewardToken, address _escrowPool, uint256 _escrowPortion, uint256 _escrowDuration, uint256 _maxBonus, uint256 _maxLockDuration, uint _endDate ) public initializer { __TimeLockPool_init(_name, _symbol, _depositToken, _rewardToken, _escrowPool, _escrowPortion, _escrowDuration, _maxBonus, _maxLockDuration, _endDate); } // disable transfers function _transfer(address _from, address _to, uint256 _amount) internal override { revert("NON_TRANSFERABLE"); } } ``` The auditors wish to inform the team that while there is currently no vulnerability, it may appear in the future if a developer introduces variable parameters inside the `TimeLockNonTransferablePool` contract.
Open the report`delegatecall()` is used inside a loop in a payable function. If the called function uses `msg.value`, the incoming payment may be processed multiple times unexpectedly. ```solidity=35 function batch(bytes[] calldata calls, bool revertOnFail) external payable { for (uint256 i = 0; i < calls.length; i++) { (bool success, bytes memory result) = address(this).delegatecall(calls[i]); if (!success && revertOnFail) { revert(_getRevertMsg(result)); } } } ``` This usage can be dangerous as the implementation contract can change in the future. Especially in the case of *double spending* issues.
Open the reportIn the function `extendLock()`, users can extend their lock period on their deposits. However, in the following scenarios, there's possibility that users may fail to extend their deposit locks.
Open the reportThe `TimeLockNonTransferablePool` contract does not protect its initializer function `initialize()`, which makes it vulnerable and permits an attacker to take control of the logic contract and perform privileged operations that could either destroy the proxy. ```solidity=6 contract TimeLockNonTransferablePool is TimeLockPool { ``` - `TimeLockNonTransferablePool` is an upgradeable contract that does not protect its initializer. ```solidity=7 function initialize() ``` - `initialize` is an unprotected initializer function. If the team does not deploy the transparent proxy and the implementation in the same transaction, it leaves an opportunity for an attacker to carry out a "front-run" attack. This would allow the attacker to call the `initialize()` function on the implementation before the team and claim ownership of the contract, potentially enabling them to perform privileged operations and steal ownership. A potential scenario has been described below. The auditors are requesting information regarding the process of deploying contracts and asking if that will be executed within the same transaction?
Open the reportAccording to the design of the `TimeLockPool.sol`, users can deposit tokens and gain "share tokens", which determines how many reward tokens can be received. The reward is distributed by the project that calls `distributeRewards()`, and holding more share tokens means gaining more reward tokens in this round. This design could cause some more profitable strategies to deposit tokens into the pool. For example, whales may gain the most reward for a short locking time. A whale may maintain a small number of tokens deposited in the pool and call `increaseLock()` to increase the deposit dramatically to gain more shares every time when rewards are going to distribute. This can be achieved by front running. As the `increaseLock()` function does not update the end time of the locking, the whale can leave the pool in a short locking period, thus gaining most of the reward in this round.
Open the reportThe `unit` state variable is never used in the codebase. ```solidity=25 uint256 public unit; ```
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="perion"></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