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

Unverified attacker address in `flagOutcome()` 

Author Revealed upon completion

Root + Impact

flagOutcome() accepts a caller-supplied attacker address and records it without cross-referencing an on-chain source of truth. The only consistency check performed is against the contract's state in the Attack Registry not against the identity of the account that triggered that state.

Description

The flagOutcome() function is access-controlled by the moderator only, this means the function can only be called by the defaultModerator address. The moderator provides the function parameters "newOutcome", "goodFaith", "attacker".

In the event of a "good-faith corrupted", the moderator submits the address of the attacker, the attack registry is consulted to guarantee the outcome flagged by the moderator is consistent with the Attack registry's state.

The flagOutcome logic includes sanity checks that prioritizes the consistency of outcome flag with other parameters prodivided.

if (newOutcome == PoolStates.Outcome.SURVIVED) {
if (goodFaith_ || attacker_ != address(0)) {
revert InvalidGoodFaithParams(); //<== reverts incase an address was provided
// when the pool actually survived
}
if (state != IAttackRegistry.ContractState.PRODUCTION && state != IAttackRegistry.ContractState.CORRUPTED) {
revert InvalidOutcome();
} else if (newOutcome == PoolStates.Outcome.CORRUPTED) {
if (!goodFaith_) {
if (attacker_ != address(0)) revert InvalidGoodFaithParams();// <==
} else {
if (attacker_ == address(0)) revert InvalidGoodFaithParams();// <==
}// both blocks guarantees a consistent parameter was submitted in the event of corrupted pool
if (state != IAttackRegistry.ContractState.CORRUPTED) revert InvalidOutcome();

The pool also confirms the contract is in corrupted state on the actual registry, but nothing ensures the identity of the address the moderator names as the attacker.

The design document acknowledges the moderator as the only source of truth for outcome classification. However, the same trust is implicitly extended to attacker identity.

The pool design posits only on a mitigation against an unavailable moderator but never factors a compromised one. While the likelihood of a compromise can be low, the recent day-to-day exploits is slowly making it a fundamental reality.

A compromised moderator can name any address as the attacker. The bounty claim downstream trusts that registration completely

WIthout safety guard to guarantee real attacker identity, a compromised moderator awaiting the right condition of a real attacker to corrupt the contract, let the attackModerator mark "corrupt"on the attack registry, then follows it by submitting a different address as the attacker, since there are no identity-check to confirm the identity of the real attacker, the real attacker's address is never registered; their bounty claim permanently fails.

A design that accounts for moderator unavailability, state inconsistency with outcome parameters submited, should equally account for attacker's identity in the event of a moderator compromise.

Risk Likelihood: Low

  • the moderator submitted "attacker" address is not checked for it's validity in the flagOutcome() function logic.

  • In the event of a compromised moderator, a non-consistent address can be submitted in place of the real attacker.

Impact: Bounty funds are redirectable to any address the moderator chooses, with no on-chain evidence of tampering.

  • The legitimate attacker loses their entire bounty.

Recommended Mitigation

  • An identity verification of the real attacker and the submitted attacker address.

Support

FAQs

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

Give us feedback!