Tadle

Tadle
DeFiFoundry
27,750 USDC
View results
Submission Details
Severity: low
Valid

Unauthorized access to `approve` function can lead to unauthorized token approvals (`CapitalPool::approve`)

Summary

Vulnerability Detail

The CapitalPool contract is designed to manage capital within the system, including the approval of token spending for the token manager. The approve() function is intended to allow the token manager to set unlimited allowance for specific tokens. However, the current implementation lacks access control, allowing any address to call this function and potentially compromise the system's token management.

The approve() function retrieves the token manager's address from the tadleFactory contract using the relatedContracts() method with the TOKEN_MANAGER identifier. It then calls the approve method on the specified token contract, setting the allowance to the maximum possible value (type(uint256).max) for the token manager.

The issue lies in the absence of access control for the approve() function. Despite the NatSpec comment stating

@notice only can be called by token manager

there is no implementation to enforce this restriction. As a result, any external actor can call this function and approve unlimited spending of any token for the token manager, potentially leading to unauthorized token movements and financial losses.

function approve(address tokenAddr) external {
address tokenManager = tadleFactory.relatedContracts(
RelatedContractLibraries.TOKEN_MANAGER
);
(bool success, ) = tokenAddr.call(
abi.encodeWithSelector(
APPROVE_SELECTOR,
tokenManager,
type(uint256).max
)
);
if (!success) {
revert ApproveFailed();
}
}

Impact

Any address can call the approve() function, leading to unauthorized token approvals. This could result in unauthorized parties gaining control over token allowances, potentially draining tokens from the contract or causing other unintended financial consequences.

Proof of Concept

  1. An attacker identifies the CapitalPool contract address.

  2. The attacker calls the approve() function with the address of a valuable token contract (e.g., USDC, DAI, or any other ERC20 token).

  3. The function executes without any access control checks:

    • It retrieves the token manager's address from tadleFactory.

    • It calls the approve function on the specified token contract, setting an unlimited allowance for the token manager.

  4. The transaction succeeds, and now the token manager has an unlimited allowance for the specified token, potentially allowing unauthorized token movements.

Tools Used

Manual review

Recommendation

Implement proper access control to ensure that only the token manager can call the approve() function. This can be achieved by adding a modifier to check the caller's identity. Here's the recommended fix:

+ modifier onlyTokenManager() {
+ address tokenManager = tadleFactory.relatedContracts(
+ RelatedContractLibraries.TOKEN_MANAGER
+ );
+ require(msg.sender == tokenManager, "Caller is not the token manager");
+ _;
+ }
- function approve(address tokenAddr) external {
+ function approve(address tokenAddr) external onlyTokenManager {
address tokenManager = tadleFactory.relatedContracts(
RelatedContractLibraries.TOKEN_MANAGER
);
(bool success, ) = tokenAddr.call(
abi.encodeWithSelector(
APPROVE_SELECTOR,
tokenManager,
type(uint256).max
)
);
if (!success) {
revert ApproveFailed();
}
}
Updates

Lead Judging Commences

0xnevi Lead Judge 12 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-CapitalPool-approve-missing-access-control

This is at most low severity, even though giving max approvals shouldn't be permisionless, the respective tokenManager address is retrieved from the TadleFactory contract whereby the trusted guardian role is responsible for deploying such contracts as seen [here](https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/factory/TadleFactory.sol#L68). Since the user still has to go through the PreMarkets/DeliveryPlace contracts to perform market actions, this max approval cannot be exploited.

Support

FAQs

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