FoundrySolidityLayer 2
7.25 ETH
Submission Details
Impact: medium
Likelihood: high

The locked scope can differ from the live Agreement

Author Revealed upon completion

Root + Impact

ConfidencePool commits to a snapshot of the Agreement's scope when it is set. However, the Agreement's scope is mutable. When scope gets locked, it doesn't verify that the current scope is indeed a valid one.

Description

The getScopeAccounts() function is presented as a "binding audit trail" but the agreement owner can make it inconsistent with the live Agreement without any pool interaction or event. This can happen through Agreement functions. The Agreement contract implements addAccounts/removeAccounts which are callable by the owner of the Agreement. This is the same owner of the ConfidencePool.

function removeAccounts(string memory caip2ChainId, string[] memory accountAddresses) external onlyOwner {
// ...
for (uint256 i; i < accountAddresses.length; ++i) {
uint256 idx = _findAccountIndex(caip2ChainId, accountAddresses[i]);
uint256 lastIdx = s_accounts[caip2ChainId].length - 1;
if (idx != lastIdx) {
s_accounts[caip2ChainId][idx] = s_accounts[caip2ChainId][lastIdx];
}
s_accounts[caip2ChainId].pop();
// Maintain BattleChain scope cache
if (isBattleChain) {
_removeFromBattleChainScope(accountAddresses[i]);
}
emit AccountRemoved(caip2ChainId, accountAddresses[i]);
}
}

When the scope gets locked, it is not verified that the contract is in scope for the Agreement also:

function _observePoolState() internal returns (IAttackRegistry.ContractState state) {
state = _getAgreementState();
if (
!scopeLocked && state != IAttackRegistry.ContractState.NOT_DEPLOYED
&& state != IAttackRegistry.ContractState.NEW_DEPLOYMENT
) {
scopeLocked = true;
emit ScopeLocked(block.timestamp);
}
// ...
}

It is possible that an contract gets removed from the Agreement's scope, but remains in the ConfidencePool's scope.

Risk

Likelihood:

Agreement owners/sponsors can always do this.

Impact:

The scope of the ConfidencePool mismatches the underlying Agreement's scope and is unclear to the attackers looking to claim the rewards.

Proof of Concept

Recommended Mitigation

When locking the scope, consider going through the accounts array and verifying them by calling the Agreement's isContractInScope(...) function.

Support

FAQs

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

Give us feedback!