Skip to content

Escrow fund() allows issue-id griefing via front-running before the legitimate sponsor funds #1

Description

@chonilius

Background / Context

contracts/escrow/src/lib.rs::fund() uses issue_id (a u64 chosen off-chain by mergefi-backend/the sponsor's wallet) as the sole key into persistent storage (DataKey::Escrow(issue_id)), and rejects a second fund call on the same id with AlreadyFunded. Critically, fund performs no admin check and no validation that the caller is the "intended" sponsor for that issue — any address can call fund(issue_id, sponsor=attacker, token=<attacker-chosen>, amount=1, deadline=<attacker-chosen>) for any issue_id, as long as they supply a valid require_auth signature for themselves as sponsor.

Problem Statement

Because Stellar issue ids are presumably predictable (sequential GitHub issue numbers, or a deterministic hash the backend computes ahead of time), an attacker who front-runs the real sponsor's fund transaction — or simply calls fund proactively for issue ids they anticipate being funded — permanently claims that issue_id slot with a trivial deposit (amount=1) of a token of their choosing. The legitimate sponsor's later fund call then reverts with AlreadyFunded, and there is no top-up or re-fund-different-id path described in the README. This is a low-cost, high-impact griefing vector against a system whose entire value proposition is "sponsors fund GitHub issues."

Requirements

  • Analyze the full griefing surface: is issue_id predictable/guessable before the real fund call lands? Model the mempool/submission-ordering assumptions on Stellar/Soroban (there is no public mempool in the traditional sense, but front-running via fee/priority is still analyzed differently — investigate Soroban's actual transaction ordering guarantees).
  • Propose and implement a mitigation: options include (a) binding fund to a specific expected sponsor address set at issue-creation time by the admin/oracle, (b) a commit-reveal or admin-pre-registration step before fund is callable, (c) an admin-callable reassign/force_refund_and_reopen recovery path for squatted ids, or another design you can justify as superior.
  • Add regression tests in contracts/escrow/src/test.rs that reproduce the griefing scenario and prove the fix closes it (attacker funds first, legitimate sponsor's transaction should still succeed, or attacker's low-value funding should be recoverable without requiring off-chain intervention).
  • Document the chosen trust model change in the README's escrow section.

Acceptance Criteria

  • Written analysis of whether/why issue_id squatting is exploitable given Soroban's actual ordering model (not just Ethereum-style mempool assumptions)
  • A concrete, implemented mitigation in contracts/escrow/src/lib.rs
  • New tests proving the attack fails post-fix and existing legitimate flows (README's funding flow) still pass
  • cargo test --workspace green, make build still produces valid wasm
  • README updated to reflect the new trust assumptions for fund

Technical Notes / Hints

  • Relevant code: contracts/escrow/src/lib.rs lines ~54-88 (fund), types.rs DataKey::Escrow(u64).
  • Consider whether the fix should also apply symmetrically to create_milestone (contracts/milestones/src/lib.rs) and deposit's implicit pool-creation-on-first-deposit (contracts/maintenance-pool/src/lib.rs) — file separate issues if the fix diverges per contract, but note the shared pattern here.

Difficulty Justification

This requires understanding Soroban/Stellar's actual transaction-ordering and mempool semantics (not assumed from EVM intuition), reasoning about an economic griefing attack with no simple "add a require" fix, and designing a new access-control primitive that doesn't break the permissionless, oracle-driven trust model the rest of the contract relies on. Getting the fix wrong (e.g., adding an admin-only fund) would break the sponsor-initiated funding flow the whole product depends on.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26Stellar WaveIssues in the Stellar wave programbugSomething isn't workingsecuritySecurity-related issuevery hardVery difficult task, expert-level effort required

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions