ConfidencePool emits OutcomeFlagged with the attacker parameter unindexed. The sibling event
AttackerBountyClaimed indexes the identical semantic field (the whitehat's address). The presence
of indexed attacker on the sibling event shows that filtering logs by a specific whitehat's
address is an intended, functional use case in this protocol — yet it is not supported on
OutcomeFlagged, which is the event emitted at flag time, the first on-chain point at which a
whitehat is named (ConfidencePool.sol:378, the good-faith CORRUPTED path where a real attacker
address is passed).
Because attacker sits in the log data rather than the topics, off-chain consumers — indexers,
subgraphs, dashboards, or a whitehat's own tracking scripts — cannot filter OutcomeFlagged by
attacker address via eth_getLogs. They must instead ABI-decode the data of every OutcomeFlagged
log, or poll pool.attacker() on each pool. OutcomeFlagged uses only 1 of its 3 available indexed
slots, so this is an inconsistency with a zero-cost fix, not a slot-budget tradeoff.
Likelihood:
Every good-faith CORRUPTED resolution emits OutcomeFlagged with a real named attacker (ConfidencePool.sol:378). Any whitehat or indexer that discovers designations by log-filtering is affected on every such resolution.
Impact:
Off-chain discoverability only — no funds are at risk and there is no on-chain effect. The attacker address is present in the event data; it is simply not in the filterable topics.
A whitehat or indexer tracking designations must decode the data of every OutcomeFlagged log, or poll attacker() per pool, rather than filtering directly by their address. Across many pools this adds proportional scanning/polling overhead to off-chain infrastructure.
The asymmetry with AttackerBountyClaimed (which indexes attacker) indicates attacker-address
log-tracking is a recognized functional requirement that was applied inconsistently — the filterable path exists for the bounty-claimed event but not for the earlier flag event.
This PoC uses vm.recordLogs() to capture the raw event topics from two emissions on a legitimately resolved pool. It asserts that OutcomeFlagged produces only two topics — the event signature and the indexed moderator — so the attacker address sits in the non-filterable data; whereas the sibling AttackerBountyClaimed produces two topics including the indexed attacker, directly filterable. The passing test confirms the indexing asymmetry at the log level, not just from the interface declaration: a named whitehat cannot eth_getLogs-filter OutcomeFlagged by their own address, while the same address is filterable on the bounty event.
Adding indexed to the attacker parameter places it in the log topics, making OutcomeFlagged filterable by attacker address — matching how AttackerBountyClaimed already indexes the identical field. This uses the second of the event's three available indexed slots, has no gas or storage impact on contract state, and resolves the inconsistency so a named whitehat can discover their designation by log filter at flag time rather than decoding every pool's logs or polling attacker() per pool.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.