Proposal execution can be DOSed with return bombs when calling untrusted execution contracts
`GovPool::execute` does not check for return bombs when executing a low-level call. A return bomb is a large bytes array that expands the memory so much that any attempt to execute the transaction will lead to an `out-of-gas` exception.\\nThis can create potentially risky outcomes for the DAO. One possible outcome is "single sided" execution, ie. "actionsFor" can be executed when voting is successful while "actionsAgainst" can be DOSed when voting fails.\\nA clever proposal creator can design a proposal in such a way that only `actionsFor` can be executed and any attempts to execute `actionsAgainst` will be permanently DOS'ed (refer POC contract). T\\nThis is possible because the `GovPoolExecute::execute` does a low level call on potentially untrusted `executor` assigned to a specific action.\\n```\\n   function execute(\\n        mapping(uint256 => IGovPool.Proposal) storage proposals,\\n        uint256 proposalId\\n    ) external {\\n        // rest of code. // code\\n\\n        for (uint256 i; i < actionsLength; i++) {\\n>            (bool status, bytes memory returnedData) = actions[i].executor.call{\\n                value: actions[i].value\\n            }(actions[i].data); //@audit returnedData could expand memory and cause out-of-gas exception\\n\\n            require(status, returnedData.getRevertMsg());\\n        }\\n   }\\n```\\n
Consider using `ExcessivelySafeCall` while calling untrusted contracts to avoid return bombs.
Voting actions can be manipulated by a creator causing two potential issues:\\nProposal actions can never be executed even after successful voting\\nOne-sided execution where some actions can be executed while others can be DOSed\\nProof of Concept: Consider the following malicious proposal action executor contract. Note that when the proposal passes (isVotesFor = true), the `vote()` function returns empty bytes and when the proposal fails (isVotesFor = false), the same function returns a huge bytes array, effectively causing an "out-of-gas" exception to any caller.\\n```\\ncontract MaliciousProposalActionExecutor is IProposalValidator{\\n\\n    function validate(IGovPool.ProposalAction[] calldata actions) external view override returns (bool valid){\\n     valid = true;\\n    }\\n\\n    function vote(\\n        uint256 proposalId,\\n        bool isVoteFor,\\n        uint256 voteAmount,\\n        uint256[] calldata voteNftIds\\n    ) external returns(bytes memory result){\\n\\n if(isVoteFor){\\n  // @audit implement actions for successful vote\\n         return ""; // 0 bytes\\n        }\\n else{\\n  // @audit implement actions for failed vote\\n\\n  // Create a large bytes array\\n                assembly{\\n                     revert(0, 1_000_000)\\n              }\\n }\\n\\n   }\\n}\\n```\\n
```\\n   function execute(\\n        mapping(uint256 => IGovPool.Proposal) storage proposals,\\n        uint256 proposalId\\n    ) external {\\n        // rest of code. // code\\n\\n        for (uint256 i; i < actionsLength; i++) {\\n>            (bool status, bytes memory returnedData) = actions[i].executor.call{\\n                value: actions[i].value\\n            }(actions[i].data); //@audit returnedData could expand memory and cause out-of-gas exception\\n\\n            require(status, returnedData.getRevertMsg());\\n        }\\n   }\\n```\\n