Papr contest - 0x52's results

NFT Lending Powered by Uniswap v3.

General Information

Platform: Code4rena

Start Date: 16/12/2022

Pot Size: $60,500 USDC

Total HM: 12

Participants: 58

Period: 5 days

Judge: Trust

Total Solo HM: 4

Id: 196

League: ETH

Backed Protocol

Findings Distribution

Researcher Performance

Rank: 17/58

Findings: 3

Award: $476.06

QA:
grade-b

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: HollaDieWaldfee

Also found by: 0x52, bin2chen, evan

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
sponsor confirmed
edited-by-warden
duplicate-187

Awards

399.1233 USDC - $399.12

External Links

Lines of code

https://github.com/with-backed/papr/blob/9528f2711ff0c1522076b9f93fba13f88d5bd5e6/src/PaprController.sol#L208-L232

Vulnerability details

Impact

PaprController#buyAndReduceDebt double charges msg.sender if msg.sender != account. This leads to either loss of funds or the inability to reduce debt for other users

Proof of Concept

(uint256 amountOut, uint256 amountIn) = UniswapHelpers.swap( pool, account, //@audit account is the recipient of the swap token0IsUnderlying, params.amount, params.minOut, params.sqrtPriceLimitX96, abi.encode(msg.sender) //@audit msg.sender is payer ); if (hasFee) { underlying.transfer(params.swapFeeTo, amountIn * params.swapFeeBips / BIPS_ONE); } //@audit papr is burned from msg.sender even though the papr was sent to account _reduceDebt({account: account, asset: collateralAsset, burnFrom: msg.sender, amount: amountOut});

UniswapHelpers.swap sends the papr obtained from the swap to account. Later when reducing the debt of account it burns papr from msg.sender rather than account. This has two outcomes when a user is paying off debt for another user. The transaction will either revert because msg.sender doesn't have enough papr to burn or msg.sender will be double charged. First they will be charge underlying when swapping then they will be charged again when the papr is burned from them in the _reduceDebt subcall.

Tools Used

Manual Review

The swap output should be sent to msg.sender rather than account:

(uint256 amountOut, uint256 amountIn) = UniswapHelpers.swap( pool, - account, + msg.sender, token0IsUnderlying, params.amount, params.minOut, params.sqrtPriceLimitX96, abi.encode(msg.sender) );

#0 - trust1995

2022-12-25T13:17:59Z

Would like sponsor to weigh in, is this intended functionality of buyAndReduceDebt()?

#1 - c4-judge

2022-12-25T13:18:12Z

trust1995 marked the issue as primary issue

#2 - c4-judge

2022-12-25T13:18:27Z

trust1995 marked the issue as satisfactory

#3 - c4-judge

2022-12-25T16:20:00Z

trust1995 changed the severity to 2 (Med Risk)

#4 - c4-sponsor

2023-01-03T18:49:34Z

wilsoncusack marked the issue as sponsor confirmed

#5 - wilsoncusack

2023-01-03T18:50:30Z

This is intended functionality but agree would be better as is suggested.

#6 - C4-Staff

2023-01-10T22:34:28Z

JeeberC4 marked the issue as duplicate of #187

Findings Information

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
duplicate-196

Awards

33.3998 USDC - $33.40

External Links

Lines of code

https://github.com/with-backed/papr/blob/9528f2711ff0c1522076b9f93fba13f88d5bd5e6/src/PaprController.sol#L208-L232

Vulnerability details

Impact

PaprController#buyAndReduceDebt will either revert or steal underlying from contract when the swap has a fee

Proof of Concept

if (hasFee) { underlying.transfer(params.swapFeeTo, amountIn * params.swapFeeBips / BIPS_ONE); }

If there is a swap fee for PaprController#buyAndReduceDebt it will attempt to transfer the fee from the contract. This leads to one of two issues:

  1. If paprController doesn't have any enough underlying then the call will always revert breaking the function
  2. If it has enough then it will steal underlying from the contract by forcing the contract to pay the swap fees for the user

Tools Used

Manual Review

PaprController already handles the underlying transfer for the swap via uniswapV3SwapCallback which means the user has already approved PaprController to transfer underlying. Use safeTransferFrom instead:

if (hasFee) { - underlying.transfer(params.swapFeeTo, amountIn * params.swapFeeBips / BIPS_ONE); + underlying.safeTransferFrom(msg.sender, params.swapFeeTo, amountIn * params.swapFeeBips / BIPS_ONE); }

#0 - c4-judge

2022-12-25T13:19:02Z

trust1995 marked the issue as duplicate of #20

#1 - c4-judge

2022-12-25T13:19:10Z

trust1995 marked the issue as satisfactory

#2 - c4-judge

2022-12-25T17:29:41Z

trust1995 changed the severity to 2 (Med Risk)

#3 - C4-Staff

2023-01-10T22:32:21Z

JeeberC4 marked the issue as duplicate of #196

Awards

43.5439 USDC - $43.54

Labels

bug
downgraded by judge
grade-b
QA (Quality Assurance)
Q-12

External Links

Lines of code

https://github.com/with-backed/papr/blob/9528f2711ff0c1522076b9f93fba13f88d5bd5e6/src/PaprController.sol#L109-L135

Vulnerability details

Impact

Users are unable to withdraw there collateral without an oracle signature even if they have no debt

Proof of Concept

Under every circumstance in which a user removes collateral from the contract they must provide an oracle signed price for the NFT. This includes users with no debt. Also the oracle is immutable so it can't be replaced. In the event that the oracle become unrecoverable, all user collateral will become permanently stuck in the contract.

Tools Used

Manual Review

Bypass the oracle check if a user doesn't have any debt and is removing their collateral. Since the user carries no debt, there is no reason to check the price

#0 - trust1995

2022-12-25T13:29:51Z

Good recommendation but cannot award more than L as trust in system oracle is assumed.

#1 - c4-judge

2022-12-25T13:30:01Z

trust1995 changed the severity to QA (Quality Assurance)

#2 - c4-judge

2022-12-25T17:22:18Z

trust1995 marked the issue as grade-b

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter