The Unseen security record

Ethereum, Polygon (POS)playunseen.comXGitHub

As of 3 Nov 2026, The Unseen has 1 audit report on Trustblock, by CertiK, dated 5 Aug 2024. That report lists 1 open critical finding.

Critical findings
1 open critical finding
Reported in “Unseen - Audit” by CertiK, Aug 2024. Not marked fixed in that report. See the findings
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.

Audits1

Newest first

AuditSecurity firmDateScopeCritical findingsReport
Unseen - AuditSecurity firm: CertiKDate: Scope: Files named in the report1 open critical findingOriginal removed

Findings21

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

SeverityOpenAcknowledgedFixed
Critical101
High201
Medium000
Low2014
CriticalUser Asset Can Be Taken Over By Another User's AuUnseen - Audit · CertiK · 5 Aug 2024Fixed

The `ProxyRegistry` contract plays an important role in the `TheGenerates` contract. Specifically, in the `MarketsPreapproved` contract (which is inherited by `TheGenerates` contract), the `isApprovedForAll()` function returns `true` if the `operator` is a proxy for the user. Subsequently, the `isAuthorized` modifier defined in the `ERC4907A` contract would pass for the user's `tokenId`, which means that the proxy can control the NFT corresponding to the `tokenId`. The proxy is recorded in the `ProxyRegistry` contract, specifically the `proxies` mapping. The intended behavior is that a user can only set its own proxy, and not any other user's proxy, so a user can control the NFT either directly or via its proxy. However, the `transferAccessTo()` function in the `ProxyRegistry` contract is capable of updating the `proxies[to]` mapping, and the access control in the `ProxyRegistry` and `AuthenticatedProxy` contracts is insufficient. This enables user Bob to change the `proxies[Alice]` to his own proxy, and subsequently takes control of any `tokenId` that Alice owns via Bob's proxy. Note that in the `AuthenticatedProxy` contract, the `transferProxyOwnership()` function enables the proxy owner to transfer the ownership to a new owner, and update the mapping in the registry. However, the `AuthenticatedProxy` contract also contains a `proxy()` function and a `proxyAssert()` function that can also call the `transferAccessTo()` function of the Registry, but does NOT change the `owner` variable. This allows Bob to retain ownership of his proxy, while updating the `proxies[Alice]` value in the `ProxyRegistry` contract. A proof of concept test case is added to the `exchange.registry.spec.ts` file to demonstrate the above. This vulnerability impacts all other contracts that utilize the registry and proxy contracts, including `TheGenerates` and `UnseenExchange`. For `TheGenerates`, a malicious user could effectively take control of another user's NFT. For `UnseenExchange`, the ability to manipulate the `proxy` address in line 356 of the `ExchangeCore` contract allows a malicious user to brick legitimate atomic match transactions.

Open the report
HighInit Function Can Be Called Multiple TimesUnseen - Audit · CertiK · 5 Aug 2024Fixed

The `init` function is supposed to be called by the contract owner only one time, as the comment in line 116 indicates. However, the check in line 120 does not prevent the function from being called more than once. As a result, the owner can change the `tokenId` and add new minters at will. This represents a significant risk to the token holders, as a new minter can mint a large amount of tokens and also arbitrarily burn tokens from other addresses. ```solidity=113 /** * @notice Initialize the bridge parmas. * * This can only be called by the contract owner and one time. */ function init(bytes32 tokenId_, address tokenManager) external onlyOwner { if (tokenId_ == bytes32(0)) revert TokenIdZero(); if (tokenId_ == tokenId) revert TokenIdIsAlreadySet(); tokenId = tokenId_; _addMinter(tokenManager); } ```

Open the report
Low`Executor` Used Instead of `Maker` in Order ValidUnseen - Audit · CertiK · 5 Aug 2024Fixed

The `validateOrderAuthorization()` function is intended to "validate if maker signed the order hash" (comment in line 173). However, in line 459 and 471, the `executor` address is passed in to the function instead. If the `maker` and `executor` are different addresses, this represents the inconsistency between the intended design and the actual behavior of the code.

Open the report
LowEIP4906 Not Strictly FollowedUnseen - Audit · CertiK · 5 Aug 2024Fixed

According to EIP 4906 (https://eips.ethereum.org/EIPS/eip-4906), The `supportsInterface` method MUST return `true` when called with `0x49064906`. The `VestingLockup` contract inherits `IERC4906` but the `supportsInterface` method is not updated to conform to the EIP 4906 standard.

Open the report
LowERC721 Tokens May Be Minted To A Contract That CaUnseen - Audit · CertiK · 5 Aug 2024Fixed

When the owner creates a new schedule either via `createSchedule()` or `createMultiSchedules()`, there is no check that the `params.recipient` can handle the received ERC721. If `params.recipient` is a smart contract that cannot handle the ERC721, the corresponding vesting schedule could be unwithdrawable.

Open the report
LowFunctions With `_` as Name Prefix Are Not `privatUnseen - Audit · CertiK · 5 Aug 2024Fixed

Functions with names starting with `_` should be declared as `private`/`internal`.

Open the report
LowLack of Zero Address Validation of `ecrecover()`Unseen - Audit · CertiK · 5 Aug 2024Fixed

The `ecrecover()` function can return the zero address (0x0000000000000000000000000000000000000000) if the signature was invalid or the message was malformed. When the smart contract does not check the output of `ecrecover()` and assumes it is always a valid address, vulnerability may arise.

Open the report
LowMissing Emit EventsUnseen - Audit · CertiK · 5 Aug 2024Fixed

It is important to emit events for sensitive actions, particularly those that can be executed by centralized roles or administrators. This ensures transparency and enables tracking of critical changes, which is essential for security and trust in the system. Missing event logs can indeed result in a lack of visibility and potential information loss.

Open the report
LowMissing Error MessagesUnseen - Audit · CertiK · 5 Aug 2024Fixed

The **require** can be used to check for conditions and throw an exception if the condition is not met. It is better to provide a string message containing details about the error that will be passed back to the caller.

Open the report
LowNo Upper Limit for `feeNumerator`Unseen - Audit · CertiK · 5 Aug 2024Fixed

The function `setDefaultRoyalty` receives the `feeNumerator` is used for royalty payment. In the marketplaces which support EIP-2981, `salePrice * ( feeNumerator/10000 `) will be sent to the royalty recipient. But there's no upper limit for `feeNumerator` when setting the default royalty and it can be as high as 100%.

Open the report
Show 6 more
LowPotential Memory Overwriting on `guardedArrayReplUnseen - Audit · CertiK · 5 Aug 2024Fixed

In the library `ArrayUtils`, there is a function `guardedArrayReplace()` that is used to replace bytes in an array with bytes in another array, guarded by a bitmask. This function should process the array in two steps: quotient and remainder. The local variable `words` is used to separate the two steps, and it is calculated by `array.length / 0x20`. The first quotient step works well following this calculation. However, the later remainder case also uses this value to determine if there is a set of leftover bytes by checking `words != 0`. Since `words` holds the quotient, the remainder is not properly handled, causing issues when the function processes the `words != 0` condition. This bug can lead to arbitrary storage writes. If `array.length` is exactly divisible by `0x20`, the copying happens correctly within the loop. In other cases, the function enters the flawed logic and attempts to copy an extra word beyond the array bounds, leading to out-of-bounds access. This incorrect logic can be exploited to overwrite memory at the end of the target array, potentially affecting any unknown memory area.

Open the report
LowPublic Drop Start Time and End Time Cannot Be theUnseen - Audit · CertiK · 5 Aug 2024Fixed

The `_checkActive()` function would revert if `startTime == endTime`, which indicates that the `startTime` and `endTime` of any mint (Public, AllowList, or Signed) cannot be the same. However, in the `updatePublicDrop()` function, the check in line 568 - 573 allows `publicDrop.startTime == publicDrop.endTime`, which is inconsistent with the minting logic. This means that it is possible to set public drop parameters that is guaranteed to fail when users attempt to mint.

Open the report
LowRemaining Native Tokens may not be Refunded to UsUnseen - Audit · CertiK · 5 Aug 2024Fixed

When a contract function accepts native tokens and executes a `.call()` or similar function that also forwards native tokens, it's important to check for and refund any remaining balance. This is because some of the supplied value may not be used during the call execution due to gas constraints, a revert in the called contract, or simply because not all the value was needed. If this remaining balance is not refunded, it will be locked in the contract.

Open the report
LowTypos in CommentsUnseen - Audit · CertiK · 5 Aug 2024Fixed

There are several typos in the contracts, please see the locations above, where the words with typos are listed: - targer - implemenation

Open the report
LowUse `.call()` Instead Of `.send()` Or `.transfer(Unseen - Audit · CertiK · 5 Aug 2024Fixed

The `.send()` function intends to transfer an ETH amount with a fixed amount of 2300 gas. This function is not equipped to handle changes in the underlying `.send()` and `.transfer()` functions which may supply different amounts of gas in the future. Additionally, if the recipient implements a fallback function containing some sort of logic, this may inevitably revert, meaning the vault and owner of the contract will never be able to call certain sensitive functions. Reference: [Solidity: Sending Ether (transfer, send, call)](https://solidity-by-example.org/sending-ether/)

Open the report
LowVariables That Could Be Declared as `constant`Unseen - Audit · CertiK · 5 Aug 2024Fixed

The linked variables could be declared as constant since these state variables are never modified. Compared to regular state variables, the gas costs of constant variables are much lower.

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="unseen"
></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