DeFiHardhatFoundry
250,000 USDC
View results
Submission Details
Severity: low
Invalid

lack of ``length`` checking on ``permitDeposits`` function

Summary

Unlike other functions that have array parameters and perform length checking, the permitDeposit function does not perform array length checking.

And enrootDeposits function also does not perform array length checking

Vulnerability Details

function permitDeposits(
address owner,
address spender,
address[] calldata tokens,
uint256[] calldata values,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external payable fundsSafu noNetFlow noSupplyChange nonReentrant {
LibSiloPermit.permits(owner, spender, tokens, values, deadline, v, r, s);
for (uint256 i; i < tokens.length; ++i) {
LibSiloPermit._approveDeposit(owner, spender, tokens[i], values[i]);
}
}
////////// LibSiloPermit.sol
function permits(
address owner,
address spender,
address[] memory tokens,
uint256[] memory values,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
require(block.timestamp <= deadline, "Silo: permit expired deadline");
bytes32 structHash = keccak256(
abi.encode(
DEPOSITS_PERMIT_TYPEHASH,
owner,
spender,
keccak256(abi.encodePacked(tokens)),
keccak256(abi.encodePacked(values)),
_useNonce(owner),
deadline
)
);
bytes32 hash = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(hash, v, r, s);
require(signer == owner, "Silo: permit invalid signature");
}
function _approveDeposit(
address account,
address spender,
address token,
uint256 amount
) internal {
AppStorage storage s = LibAppStorage.diamondStorage();
s.accts[account].depositAllowances[spender][token] = amount;
emit DepositApproval(account, spender, token, amount);
}

Look at these functions, there is no check that tokens.length and values.length must be equal.

As a result, values.length can be larger than tokens.length

POC

  • Paste this code on ``siloToken.test.js

it("difference length success but unexpected", async function () {
const nonce = await beanstalk.connect(user).depositPermitNonces(user.address);
const signature = await signSiloDepositTokensPermit(
user,
user.address,
user2.address,
[siloToken.address, siloToken2.address],
["1000", "1000", "500"],
nonce
);
this.result = await beanstalk
.connect(user)
.permitDeposits(
signature.owner,
signature.spender,
signature.tokens,
signature.values,
signature.deadline,
signature.split.v,
signature.split.r,
signature.split.s
);
const allowanceSiloToken = await beanstalk
.connect(user).depositAllowance(user.address, user2.address, siloToken.address);
const allowanceSiloToken2 = await beanstalk
.connect(user).depositAllowance(user.address, user2.address, siloToken2.address);
console.log('allowance silo token:', allowanceSiloToken);
console.log('allowance silo token2:', allowanceSiloToken2);
});

Impact

no funds are lost, but the impact is unexpected of purpose function.

Tools Used

Manual

Recommendations

require(tokens.length == values.length, "unexpected length")
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.