Polygon Lack Of Balance Check Bugfix Review — $2.2m Bounty

Immunefi
Immunefi
Published in
5 min readDec 29, 2021

Summary

Whitehat Leon Spacewalker reported a critical vulnerability in Polygon on December 3. The vulnerability consisted of a lack of balance/allowance check in the transfer function of Polygon’s MRC20 contract and would have allowed an attacker to steal all ~9,276,584,332 MATIC (as of December 5, the date of the fix) from that contract. Following the report from Leon Spacewalker, Polygon immediately sprang into action to fix the bug. Immunefi assisted in investigating blockchain activity, validating the fix, and advising the hardfork operation.

While Polygon was developing and implementing the fix, a second hacker, who we will refer to as Whitehat2, submitted a report on December 4 referencing the same vulnerability. Polygon decided to make a one-time exception and rewarded Whitehat2 with 500,000 MATIC.

Additionally, a blackhat–or a set of blackhats–managed to steal 801,601 MATIC tokens using the same exploit before the fix was implemented. The Polygon team submitted the fix on December 5.

Polygon is paying out a bounty of $2.2m in stablecoins to Leon Spacewalker and 500,000 MATIC to Whitehat2, which according to current market value is worth $1,262,711. The $2.2m exceeds the maximum value of Polygon’s critical bounty in recognition of the severity of the vulnerability.

It is an extraordinary validation of the importance of big bug bounties in DeFi.

In the grand scheme of things, and looking ahead at the future of DeFi, this won’t be the last case where a severe vulnerability is found. As more funds pile into DeFi at record rates, more projects will also have critical exploits buried in their code. It is inevitable. The only difference is whether these future projects take comprehensive security measures and do everything they can to protect their code. And the most important way to protect live code is with a gigantic bug bounty.

Polygon’s blogpost of the vulnerability can be read here.

Now, onto a discussion about the technical details of the vulnerability itself.

Vulnerability Analysis

The MATIC token is the main token of the Polygon ecosystem. It’s like Ether, but for the Polygon Network. The main difference between Ether and MATIC is in how MATIC is constructed. The MATIC token is used in the Polygon ecosystem for a number of functions, including voting on Polygon Improvement Proposals (PIPs), contributing to security through staking, and paying gas costs. You can, of course, use the native currency of the Polygon network as a digital currency.

The most interesting thing about the MATIC token is its standard. It is the native gas-paying asset of the Polygon network, but it is also a contract deployed on Polygon. This contract is the MRC20 contract. The MRC20 standard is used mainly for the possibility of transferring MATIC gaslessly, which with Ether, is impossible to do so. When sending Ether, you’re making a transaction that a wallet needs to sign.

Gasless MATIC transfers are facilitated by the transferWithSig() function. The user who owns the tokens signs a bundle of parameters including the operator, amount, nonce, and expiration. The signature can be later passed to the MRC20 contract by the operator to perform a transfer on behalf of the token owner. This is gasless for the token owner because the operator pays for the gas.

We first verify that the signing hash (called dataHash in the contract) has not already been used. This prevents replay attacks. After the hash is verified, we extract the token owner’s address using ecrecovery and pass that to the _transferFrom() function.

Smart contracts on Ethereum have access to the built-in ECDSA signature verification algorithm through ecrecover. This built-in function lets you verify the integrity of the signature over the hashed data and returns the signer’s public key. ecrecovery is a wrapper function on top of the standard ecrecover, that lets you pass a packed signature without the need to separate V, R, and S.

But the bug in the token could have allowed an attacker to mint an arbitrary number of tokens from the MRC20 contract. That means all of the 9,276,584,332 in MATIC value could have been stolen.

The main issue is that _transferFrom will call the _transfer function directly without checking whether the from has enough balance. And we can call the transferWithSig() without a valid signature, thanks to the lack of a check to see if ecrecovery returns the zero address.

The function takes the balances of from and to address and passes that to the _transfer() which also has the same issue. It doesn’t check that the sender has enough balance.

That can lead to a situation where anybody can craft such a transaction and mint an arbitrary number of tokens from the genesis contract. How?

Here’s a step-by-step guide:

  1. Create a byte string of length anything other than 65. Due to the check in ecrecovery, if a packed signature does not have length 65, it will return the zero address. This means we don’t need a valid signature to proceed with the attack.
  2. amount passed to the function can be any amount, but we can use the full balance of the MRC20 contract
  3. to address will be an attacker address
  4. After from is recovered from the invalid signature (this is the zero address because we passed an invalid signature), _transferFrom() is called
  5. As the balances are not checked for the from and to, contract makes a _transfer() call
  6. _transfer() only checks if the recipient isn’t the MRC20 contract itself and transfers all the amount to the attacker from the MRC20 contract
  7. Enjoy the profit of all the MATIC tokens

Vulnerability Fix

Polygon removed the transferWithSig function. The fix is available here.

Acknowledgements

We’d like to thank the Polygon team for quickly fixing the bug and providing a generous payout to Leon Spacewalker and Whitehat2.

If you’d like to start bug hunting, we got you. Check out the Web3 Security Library, and start earning rewards on Immunefi — the leading bug bounty platform for web3 with the world’s biggest payouts.

To report additional vulnerabilities, please see Polygon’s bug bounty program with Immunefi.

--

--

Immunefi
Immunefi

Immunefi is the premier bug bounty platform for smart contracts, where hackers review code, disclose vulnerabilities, get paid, and make crypto safer.