Skip to content

feat(torn): proposal-target verification — flag malicious/look-alike execution targets #2005

Description

@Zeugh-eth

Feature Request

User story

As an Anticapture user (delegate / security researcher) watching Tornado Cash, I want each on-chain proposal's execution target automatically checked for source-verification and look-alike-address risk, so a malicious proposal like Proposal 67 (2026-06-25) is surfaced in the UI/feed before it can pass — instead of relying on manual decompilation.

Context

  • Proposal 67 pointed execute()'s delegatecall at an unverified look-alike contract0x5efda50f22d34f27… vs the real governor 0x5efda50f22d34F26…, differing only from the 16th hex char — to seize governance over a ~$23M treasury. It was caught manually by L2BEAT / P. Caversaccio via missing code verification + decompilation.
  • Today (PR feat: integrate tornado cash #2002) we index the target but don't analyze it: TORNClient.alreadySupportCalldataReview() === false. Background + roadmap in apps/indexer/src/indexer/torn/RESEARCH.md (PR docs(torn): DAO anatomy, tech funnel & remaining-gap roadmap #2004, §5 P1, §7).
  • This is P1 of the documented next-steps roadmap and the single most attack-relevant feature for TORN.

Describe the feature request

Compute a proposal target risk signal from the already-indexed target and surface it on the proposal detail + activity feed.

Risk inputs:

  1. Source verified? Etherscan getsourcecode → empty SourceCode/ABI ⇒ unverified ⇒ HIGH.
  2. Look-alike address? similarity (prefix/suffix + Levenshtein) vs a known-entity allowlist (governor / vault / token / multisig) ⇒ catches …f27… vs …F26….
  3. (optional, later) behavior diff — decompile executeProposal() / scan for storage-slot writes to governance-critical slots.

Describe solution — adaptation across the 5 components (per the dao-integration skill)

1. address-enrichment (apps/address-enrichment) — new home for the analysis (indexer stays on-chain-only).

  • Job that, per TORN proposal target, calls Etherscan verification + runs the similarity check against the known-entity list, and writes a risk record. Reuses the app's existing Etherscan/RPC plumbing.

2. DB — add a side table proposal_target_risk (proposalId, daoId, target, verified bool, lookAlikeOf address|null, riskLevel, details jsonb) rather than migrating the shared proposals_onchain schema (keeps other DAOs untouched; consistent with the "no-migration" approach in RESEARCH.md §4).

3. API (apps/api) — layered controller→service→repository→mapper:

  • GET /proposals/{id}/target-risk (or fold into the proposal-detail mapper).
  • In clients/torn, expose target-risk via the client and flip alreadySupportCalldataReview() once the signal is populated.

4. gateway + client — regenerate packages/anticapture-client from the updated OpenAPI; apps/gateful passes through.

5. dashboard (apps/dashboard) — render a HIGH-risk banner on features/governance/.../ProposalSection.tsx; add a feedEvent flag for the activity feed; reflect support in shared/dao-config/torn.ts.

Enum sync (the 5th component the skill calls out): add a PROPOSAL_RISK feed/metric type consistently across indexer + api + dashboard enums.

Acceptance / validation

  • Proposal 67 (and the May 2023 attack proposal) render with a HIGH target-risk badge (unverified + look-alike of 0x5efda5…A1Ce).
  • Legitimate executed proposals with verified targets render LOW/none.
  • No schema migration affecting other DAOs.

Want a second opinion on the approach before implementation — see the @codex ask in the comments. Tagging @pikonha (owner of #2002) to validate this is the right next step / right home (address-enrichment vs indexer; side-table vs schema extension).

Metadata

Metadata

Assignees

Labels

enhancementImproving an already existing feature

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions