# 29073 - \[SC - Insight] excuteTransaction in timelock contract will una...

Submitted on Mar 6th 2024 at 15:16:49 UTC by @Kenzo for [Boost | Puffer Finance](https://immunefi.com/bounty/pufferfinance-boost/)

Report ID: #29073

Report type: Smart Contract

Report severity: Insight

Target: <https://etherscan.io/address/0x3C28B7c7Ba1A1f55c9Ce66b263B33B204f2126eA#code>

Impacts:

* Contract fails to deliver promised returns, but doesn't lose value
* Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)

## Description

## Vulnerability Details

The function `timelock::executeTransaction` Executes a transaction after the delay period for Operations Multisig and Community multisig can execute transactions without any delay. Expected behavior is that the function should revert if the call to the target contract fails. If the target contract with no contract code added or yet to be deployed is set as input of `timelock::executeTransaction`, the function won't revert which is not ideal behavior of the function. Similar issue was found with OZ: <https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3874>

```solidity
    function executeTransaction(address target, bytes calldata callData, uint256 operationId)
        external
        returns (bool success, bytes memory returnData)
    {
        // Community Multisig can do things without any delay
        if (msg.sender == COMMUNITY_MULTISIG) {
            return _executeTransaction(target, callData);
        }

        // Operations multisig needs to queue it and then execute after a delay
        if (msg.sender != OPERATIONS_MULTISIG) {
            revert Unauthorized();
        }

        bytes32 txHash = keccak256(abi.encode(target, callData, operationId));
        uint256 lockedUntil = queue[txHash];

        // slither-disable-next-line incorrect-equality
        if (lockedUntil == 0) {
            revert InvalidTransaction(txHash);
        }

        if (block.timestamp < lockedUntil) {
            revert Locked(txHash, lockedUntil);
        }

        queue[txHash] = 0;
        (success, returnData) = _executeTransaction(target, callData);

        emit TransactionExecuted(txHash, target, callData, operationId);

        return (success, returnData);
    }
```

## Impact Details

1. Transactions with contracts that are yet to deploy like new tokens whose address can be predetermined at risk while interacting with this contract.
2. `timelock::executeTransaction` will execute invalid transaction successfully instead of failing on non-existent contract.
3. Funds can be lost in some scenario.

## Risk Breakdown

Low Severity as the function is being controlled by the `OPERATIONS_MULTISIG` and `COMMUNITY_MULTISIG`.

## Recommendation

Consider adding contract existence check on `timelock.executeTransaction`.

POC is attached.

## Proof of concept

The POC can be run by placing the following code in `PufferTest.integration.t.sol` and running this command: `forge test --mt test_call_to_unknown_contract -vv`

```solidity
function test_call_to_unknown_contract() public {
        vm.startPrank(timelock.OPERATIONS_MULTISIG());
        address target = makeAddr("UnknownContract");

        bytes memory callData = abi.encodeCall(Timelock.setDelay, (15 days));

        assertTrue(timelock.delay() != 15 days, "initial delay");

        uint256 operationId = 1234;

        bytes32 txHash = timelock.queueTransaction(target, callData, operationId);
        
        console2.log("Transaction added to the queue:");
        console2.logBytes32(txHash);

        uint256 lockedUntil = block.timestamp + timelock.delay();
        

        vm.warp(lockedUntil + 1);
        
        try timelock.executeTransaction(target, callData, operationId) {
             console.log("Transaction successful despite non existent contract.");
        }
        catch {
             console.log("Transaction unsuccessful.");
        }
    }
```

Output:

```
[PASS] test_call_to_unknown_contract() (gas: 41202)
Logs:
  Transaction added to the queue:
  0x49df1e329caafa22eef3d051ceb862da04b4bf32c005264307826245abfea259
  Transaction successful despite non existent contract.

Test result: ok. 1 passed; 0 failed; finished in 8.45ms
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://reports.immunefi.com/puffer-finance/29073-sc-insight-excutetransaction-in-timelock-contract-will-una....md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
