Matic

CertiKFiles named in the report

CertiK reviewed Polygon (Matic) on 19 Apr 2021: 15 findings, 1 critical; 14 marked fixed, 1 open.

1 critical finding, fixed
Open the reportOpen Polygon’s security record

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings15

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

SeverityOpenAcknowledgedFixed
Critical001
High001
Medium000
Low1012
CriticalRepeated exitFixed

RootChainManager.sol lines 250-255 the exitHash is determined by three factors, one of which is inputDataRLPList[8], the branch mask, i.e. the path in the receipt merkle patricia trie from the root to the corresponding burning transaction receipt. The path is in bytes and translated to hex by _getNibbleArray() in MerklePatriciaProof.sol. There are 2 cases depending whether the path in hex has odd or even length. In case on line 150 we accept every beginning nibble except 1,3 and erase the first two nibble in the hex array, which means two arrays 2055 and 4055 would produce the same _getNibbleArray() to bypass `verify`, but they produce different exitHash so one can exit more than once.

HighReplay attack between child chain and root chainFixed

Matic wants to enable users to send transactions to matic network without changing the network in their wallet so the chainId is the same for both child chain and main chain. This opens an attack vector when a user wants to send a transaction only to the child chain, then the attacker can submit the signed transaction to the other chain against that user’s will. The requires the same nonce, which can happen, and the same contract address on both chains to have an exploitable function, for example when the two contracts are deployed from the same address.

Low`isList()` verificationFixed

The function `numItems()` calculates the number of elements in an `RLPItem` representing a list, so it should check whether the input indeed represents a list. For example it would return the length of a string. On the other hand adding a `require` check is not necessary and would only cost more gas, since the only place this function is used is in `toList()` and the aforementioned condition is already checked. The exhibit is here just for completeness in case the `RLPReader.sol` library is expanded and the function `numItems()` is used in additional functions.

Low`require` error messageFixed

`require` can be used to check for conditions and throw an exception if the condition is not met, in which case the error message provided by the developer will appear. This is why a very descriptive error message is needed.

LowDepositor roleFixed

In the constructors of `ChildToken` contracts the depositor role is assigned to the contract’s creator. The depositor is an important role as it is the only address that is authorized to deposit the tokens from root contract to child contract. From the natspec it is evident that only the `ChildChainManager` contract should possess this role and this contract does not deploy the `ChildToken` contracts so one would needs some transactions to pass over the depositor rights.

LowExclusion of empty bytes inputFixed

In several functions of `RLPReader` library we check that `item.len` is not zero. Indeed any RLP encoding (even of empty string or empty array) is non-empty, this means we should check this condition in the function `toRlpItem()` to exclude this case before hand.

LowIncorrect encoding of value “false”Fixed

According to RLP encoding specification the special value “false” is encoded as “0x80”, whereas in current implementation of the function “toBoolean” it is “0x00”.

LowInteger underflowFixed

The subtraction `blockNumber - startBlock` is unsafe and can cause integer underflow, but we believe this cannot be exploited in any way as it would certainly cause the Merkle proof verification to fail.

LowInterface structureFixed

The IChildToken interface contains only the deposit function and is inherited in every Child Token contract. Every Child Token contains an additional withdraw function which is essential because it enables token withdrawal from the child chain to the main chain so we believe this function belongs to the general pattern as well, i.e. IChildToken interface.

LowMultiple lookups from storageFixed

The value in storage `childToRootToken[childToken]` is looked up twice in exit function. Each lookup costs 200 gas each. It would be better to assign this value to a memory variable, because both memory assignment and look up cost 3 gas each.

Show 4 more
LowNon unique uint encodingFixed

The functions `toUint()` and `toUintStrict()` only take `RLPItem` representing uint as input. To get the data bytes only the length of the payload offset is calculated, whereas the content of this prefix is not considered, which means invalid `RLPItem` with prefixes of incorrect length or short list would still get through.

LowRedundant return statementFixed

The default return value is false so the return statements on lines 107 and 102 are not needed and the else case on line 101 can be omitted.

LowUnlocked compiler versionFixed

An unlocked compiler version in the source code of the contract permits the user to compile it at or above a particular version. This, in turn, leads to differences in the generated bytecode between compilations due to differing compiler version numbers. This can lead to an ambiguity when debugging as compiler specific bugs may occur in the codebase that would be hard to identify over a span of multiple compiler versions rather than a specific one.

LowUnnecessary if clauseFixed

Checking in the function `numItems()` whether `item.len == 0` to return zero is not needed since if `item.len == 0` then it does not encode a list, because the RLP encoding of an empty list is `0xC0`. Moreover the function `numItems()` is only used in `toList()` and right before calling `numItems()` the condition `isList()` is checked which excludes the possibility of an empty item.

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

  • contracts/child/ChildToken/ChildERC20.sol
  • contracts/child/ChildChainManager/ChildChainManager.sol
  • contracts/root/TokenPredicates/ITokenPredicate.sol
  • contracts/Migrations.sol
  • contracts/root/TokenPredicates/EtherPredicate.sol
  • contracts/root/RootToken/DummyERC721.sol
  • contracts/common/ContextMixin.sol
  • contracts/common/AccessControlMixin.sol
  • contracts/root/TokenPredicates/ERC721PredicateProxy.sol
  • contracts/root/TokenPredicates/ERC721Predicate.sol
  • contracts/root/TokenPredicates/ERC20Predicate.sol
  • contracts/root/RootToken/DummyMintableERC721.sol
  • contracts/root/MockCheckpointManager.sol
  • contracts/root/RootChainManager/RootChainManager.sol
  • contracts/common/Proxy/UpgradableProxy.sol
  • contracts/child/ChildToken/ChildERC1155.sol
  • contracts/common/NetworkAgnostic.sol
  • contracts/common/Initializable.sol
  • contracts/child/ChildToken/MaticWETH.sol
  • contracts/root/TokenPredicates/MintableERC721PredicateProxy.sol
  • contracts/root/StateSender/DummyStateSender.sol
  • contracts/test/ProxyTestImplStorageLayoutChange.sol
  • contracts/common/Proxy/Proxy.sol
  • contracts/lib/RLPReader.sol
  • contracts/child/ChildChainManager/ChildChainManagerProxy.sol
  • contracts/common/Proxy/IERCProxy.sol
  • contracts/root/StateSender/IStateSender.sol
  • contracts/root/TokenPredicates/MintableERC721Predicate.sol
  • contracts/child/ChildToken/ChildMintableERC721.sol
  • contracts/root/RootToken/DummyERC20.sol
  • contracts/child/ChildChainManager/IChildChainManager.sol
  • contracts/lib/Merkle.sol
  • contracts/root/TokenPredicates/EtherPredicateProxy.sol
  • contracts/root/RootToken/DummyERC1155.sol
  • contracts/lib/MerklePatriciaProof.sol
  • contracts/child/ChildToken/ChildERC721.sol
  • contracts/root/TokenPredicates/ERC1155Predicate.sol
  • contracts/root/RootToken/IMintableERC721.sol
  • contracts/test/ProxyTestImpl.sol
  • contracts/root/RootChainManager/IRootChainManager.sol
  • contracts/root/TokenPredicates/ERC1155PredicateProxy.sol
  • contracts/child/ChildToken/IChildToken.sol
  • contracts/root/TokenPredicates/ERC20PredicateProxy.sol
  • contracts/root/RootChainManager/RootChainManagerProxy.sol
  • contracts/common/EIP712Base.sol
  • contracts/root/ICheckpointManager.sol

Part of Polygon’s security record

Polygon
Audits12 audits by 6 firmsLast audit May 2025, by ChainSecurity.
Critical findingsNo open critical findingsAcross the 12 reports, 6 critical findings were reported. Each is marked fixed by the firm that reported it.
Open Polygon’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