Platform: Code4rena
Start Date: 18/10/2022
Pot Size: $75,000 USDC
Total HM: 27
Participants: 144
Period: 7 days
Judge: gzeon
Total Solo HM: 13
Id: 170
League: ETH
Rank: 4/144
Findings: 4
Award: $4,660.40
π Selected for report: 1
π Solo Findings: 1
1952.9001 USDC - $1,952.90
Operators maliciously slashed
A user can create a malicious token that when called by anyone other than themselves and the bridge use an extreme amount of gas. They create a bridge request with a gas limit higher than the block limit. If an operator tries to call execute they will always run out of gas. Meanwhile the malicious user can call the token for very little gas. The malicious user calls the request to slash the operator
Manual Review
Ensure gas limit is not higher than destination block gas limit
#0 - Minh-Trng
2022-10-25T20:45:27Z
a low level call will retain some gas for the parent https://eips.ethereum.org/EIPS/eip-150 so the rest of the code should still be able to execute
#1 - gzeoneth
2022-10-28T08:56:44Z
If the gasLimit is above block/tx gas limit, this will always revert and no one can execute the job and no slashing can occur.
Also attacker need to pay gasPrice * gasLimit
upfront which can be huge if the gasLimit is set to very high.
#2 - gzeoneth
2022-10-31T12:31:53Z
Can be a duplicate of #364
#3 - 0xA5DF
2022-10-31T12:52:16Z
#364 makes the attack cheaper, but even if #364 was fixed, the attack would still be possible, and as I've shown at #414 it can cost a few bucks to do it on Polygon and Avalanche.
#4 - gzeoneth
2022-11-19T16:16:52Z
I don't think slashing is possible, the block gas limit issue is a dupe of #414
168.7306 USDC - $168.73
Users tokens are still burned at source chain with no way to recover them
try HolographOperatorInterface(address(this)).nonRevertingBridgeCall{value: msg.value}( msg.sender, bridgeInRequestPayload ) { /// @dev do nothing } catch { _failedJobs[hash] = true; emit FailedOperatorJob(hash); }
When a bridging call fails, nothing is done on the destination chain. When sending the message from the source chain their tokens work burned. Since the destination call failed, no tokens were minted on the destination chain. This means their source tokens have been burned and they never received any tokens on the destination chain, leaving them with no tokens.
Manual Review
Create a function allowing users to create a message back to the source chain for failed transactions and a function that allows them to remint on source chain.
#0 - gzeoneth
2022-10-31T13:17:48Z
Duplicate of #102
#1 - ACC01ADE
2022-11-09T15:03:07Z
This will be properly implemented in the next update.
π Selected for report: 0x52
2538.7702 USDC - $2,538.77
bidShares returned are incorrect leading to incorrect royalties
function isValidBidShares(BidShares memory bidShares) public pure override returns (bool) { return bidShares.creator.value.add(bidShares.owner.value).add( bidShares.prevOwner.value ) == uint256(100).mul(Decimal.BASE); }
Above you can see the Zora market lines that validate bidShares, which shows that Zora market bidShare.values should be percentages written out to 18 decimals. However PA1D#bidSharesForToken sets the bidShares.creator.value to the raw basis points set by the owner, which is many order of magnitudes different than expected.
Manual Review
To return the proper value, basis points returned need to be adjusted. Convert from basis points to percentage by dividing by 10 ** 2 (100) then scale to 18 decimals. The final result it to multiple the basis point by 10 ** (18 - 2) or 10 ** 16:
function bidSharesForToken(uint256 tokenId) public view returns (ZoraBidShares memory bidShares) { // this information is outside of the scope of our bidShares.prevOwner.value = 0; bidShares.owner.value = 0; if (_getReceiver(tokenId) == address(0)) { - bidShares.creator.value = _getDefaultBp(); + bidShares.creator.value = _getDefaultBp() * (10 ** 16); } else { - bidShares.creator.value = _getBp(tokenId); + bidShares.creator.value = _getBp(tokenId) * (10 ** 16); } return bidShares; }
#0 - trust1995
2022-10-30T20:24:48Z
Nice find!
#1 - alexanderattar
2022-11-08T21:04:33Z
Good catch! We'll implement the suggested solution.
π Selected for report: Rolezn
Also found by: 0x1f8b, 0x52, 0x5rings, 0xNazgul, 0xSmartContract, 0xZaharina, 0xhunter, 0xzh, 8olidity, Amithuddar, Aymen0909, B2, Bnke0x0, Chom, Deivitto, Diana, Diraco, Dravee, Franfran, JC, Jeiwan, Josiah, JrNet, Jujic, KingNFT, KoKo, Lambda, Margaret, Migue, Ocean_Sky, PaludoX0, Picodes, Rahoz, RaoulSchaffranek, RaymondFam, RedOneN, ReyAdmirado, Shinchan, Tagir2003, Trust, Waze, Yiko, __141345__, a12jmx, adriro, ajtra, arcoun, aysha, ballx, bin2chen, bobirichman, brgltd, bulej93, catchup, catwhiskeys, caventa, cccz, cdahlheimer, ch0bu, chaduke, chrisdior4, cloudjunky, cryptostellar5, cryptphi, csanuragjain, cylzxje, d3e4, delfin454000, djxploit, durianSausage, erictee, fatherOfBlocks, francoHacker, gianganhnguyen, gogo, hansfriese, i_got_hacked, ignacio, imare, karanctf, kv, leosathya, louhk, lukris02, lyncurion, m_Rassska, malinariy, martin, mcwildy, mics, minhtrng, nicobevi, oyc_109, pashov, peanuts, pedr02b2, peiw, rbserver, ret2basic, rotcivegaf, rvierdiiev, ryshaw, sakman, sakshamguruji, saneryee, securerodd, seyni, sikorico, svskaushik, teawaterwire, tnevler, w0Lfrum
0 USDC - $0.00
Unexpected reverts or portion of ETH permanently stuck in contract
uint256 gasCost = (23300 * length) + length; uint256 balance = address(this).balance; require(balance - gasCost > 10000, "PA1D: Not enough ETH to transfer");
When calculating gasCost, it is accidentally calculated using 23300 instead of 2300, which is the actual stipend for an ETH transfer. This can lead to unexpected reverts since gas costs is calculated incorrectly.
Manual Review
Fix gas cost calculations by using the proper stipend for transfer:
- uint256 gasCost = (23300 * length) + length; + uint256 gasCost = (2300 * length) + length; uint256 balance = address(this).balance; require(balance - gasCost > 10000, "PA1D: Not enough ETH to transfer");
#0 - gzeoneth
2022-10-28T09:32:28Z
unsure if this is an intended behavior 21000 + 2300 = 23300
and also low risk
#1 - gzeoneth
2022-10-28T09:35:55Z
Also #106 mentioned gasPrice should be considered.
#2 - alexanderattar
2022-11-08T21:18:24Z
The code mentioned will be refactored based on this and other similar issues raised by wardens
#3 - gzeoneth
2022-11-21T07:13:46Z
As QA report