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

AttackRegistry pointer rotation can make Agreement scope-sync revert, indirectly blocking pre-lock pool scope maintenance

Author Revealed upon completion

Root + Impact

Description

Agreement scope updates on BattleChain (addAccounts / removeAccounts) synchronously call AttackRegistry:

// Agreement.sol
function _syncRegisterContract(address contractAddress) internal {
address attackRegistryAddr = _getAttackRegistry(); // from registry pointer
IAttackRegistry(attackRegistryAddr).registerContractForExistingAgreement(contractAddress);
}

_getAttackRegistry() reads BattleChainSafeHarborRegistry.getAttackRegistry(), so a valid DAO pointer rotation immediately changes the downstream sync target.

If the new AttackRegistry does not recognize legacy agreements under its current factory mapping, registerContractForExistingAgreement reverts InvalidAgreement(msg.sender), causing Agreement.addAccounts/removeAccounts to revert.

That blocks Agreement owner scope maintenance and can indirectly block ConfidencePool pre-lock scope alignment (setPoolScope) because new intended accounts cannot be made valid in Agreement scope first.

Risk

Likelihood:

  • AttackRegistry pointer rotations are valid protocol operations.

  • Migration windows with mixed legacy agreements/factory mappings are realistic.

Impact:

  • DoS of Agreement BattleChain scope updates for affected agreements.

  • Indirect operational DoS of pre-lock pool scope maintenance/alignment.

Proof of Concept

// 1) Agreement A exists and is used by a pool; registry R initially points to AR1
// 2) DAO updates R.setAttackRegistry(AR2)
// 3) AR2 does not recognize A via its current agreementFactory mapping
// 4) A.owner calls addAccounts(...) to extend BattleChain scope
// 5) Agreement._syncRegisterContract -> AR2.registerContractForExistingAgreement(...)
// reverts InvalidAgreement(A)
// 6) addAccounts(...) reverts, so Agreement scope cannot be updated
// 7) Pool sponsor cannot include the new intended account in setPoolScope pre-lock,
// because IAgreement.isContractInScope(account) remains false

Recommended Mitigation

During AttackRegistry rotations, enforce migration compatibility before switching pointers:

  1. Ensure the new AttackRegistry's agreement-factory recognition includes legacy agreements, and

  2. Perform/verify agreement migration checks before setAttackRegistry takes effect.

This preserves Agreement scope-sync liveness and avoids downstream pool-scope maintenance failures.

Support

FAQs

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

Give us feedback!