Skip to content

[CRITICAL] No pause/circuit-breaker mechanism — cannot halt system in emergency #95

Description

@Muyideen-js

[CRITICAL] No pause/circuit-breaker mechanism — cannot halt system in emergency

Summary

None of the four contracts has a pause or circuit-breaker function. In the event of a critical vulnerability (e.g., issue #1, #3, #27), there is no way to halt betting, claims, or withdrawals while a fix is deployed. The only recourse is a full upgrade (issue #5), which itself is irreversible and requires a trusted admin.

This means:

The Missing Feature

No contract in the system implements:

  • A pause flag or is_paused state
  • A pause() function callable by admin
  • A resume() function to restart operations
  • A paused() query function to check status
  • Any state modification that checks the pause flag before proceeding

Why It's Critical

  1. No containment capability: If a critical bug is discovered (e.g., the cancel_market fee theft in issue Systemic accounting & state-invariant violation across prediction_market ↔ referral_registry ↔ leaderboard — fee theft, leaderboard displacement, and unbounded inflation #1, the reentrancy in issue fix(leaderboard): count bonus awards in total_bets #27, or the empty-side sweep in issue [CRITICAL] resolve_market lets a resolver sweep the entire pool to fees by resolving to the empty side — griefing / fund theft #3), there is no way to stop the bleeding while a fix is prepared and tested.

  2. Exploits propagate unchecked: An attacker can continue exploiting the vulnerability across many blocks/users until the upgrade is deployed. There is no "cooling off" period.

  3. No emergency response: Unlike traditional financial systems that have circuit breakers to halt trading during volatility, this system has no equivalent mechanism.

  4. Combined with no events (issue [HIGH] No event emission anywhere — off-chain indexers, UIs, and auditors cannot track state transitions #7): Even if a pause mechanism existed, there's no event infrastructure to notify users that the system was paused and then resumed.

  5. Combined with upgrade vulnerability (issue [CRITICAL] upgrade() allows arbitrary WASM replacement with no timelock, delay, or multi-sig — single compromised admin key = total loss #5): If the admin key is compromised, the attacker can upgrade the contract to remove any pause mechanism that was added, or upgrade to a malicious version.

Attack Scenario: Unchecked Exploit Propagation

  1. Security researcher discovers the cancel_market fee theft (issue Systemic accounting & state-invariant violation across prediction_market ↔ referral_registry ↔ leaderboard — fee theft, leaderboard displacement, and unbounded inflation #1)
  2. Researcher reports to team, team needs 48 hours to prepare and test a fix
  3. During those 48 hours, any user can cancel a market and trigger the fee theft
  4. Funds drain continuously across all cancelled markets
  5. No way to stop the bleeding — no pause, no circuit breaker
  6. Team must rush the fix, risking incomplete or buggy deployment
  7. Or team decides to live with the bug, accepting ongoing fund loss

Why It's Hard to Fix

Adding a pause mechanism requires addressing several intertwined problems:

Possible Implementations

  • (a) Global pause flag: Single bool paused state checked at the start of every state-altering function. Simple but requires modifying every function.

  • (b) Per-function pause flags: Each critical function has its own pause flag. More granular but requires more storage and checks.

  • (c) Emergency withdrawal path: Instead of a full pause, add a function to withdraw all funds to a safe address in an emergency. Still requires trust in the withdrawer.

  • (d) Timed pause with governance override: Pause for a fixed duration (e.g., 24 hours) during which governance can vote to resume or extend. Adds complexity but provides a defined window.

Suggested Triage

This is a system safety issue. The absence of a circuit breaker is a fundamental design gap. Possible approaches:

  • (a) Add global pause flag: simplest to implement. Add a paused bool to each contract, checked at the start of every external-call-prone function. Admins can pause/resume. Requires modifying ~200+ function calls across 4 contracts.

  • (b) Add emergency withdrawal: Instead of pausing, add a function emergency_withdraw_all(recipient) that transfers all contract XLM to a specified address. More targeted but still requires trust.

  • (c) Multi-sig controlled pause: Require M-of-N signatures to pause, reducing risk of single-admin compromise. More complex UX but more secure.

  • (d) Pause + events + governance: Add pause mechanism + events to notify users + governance process for emergency decisions. Most robust but heaviest implementation.

This issue is marked CRITICAL because it means there is no mechanism to contain or halt exploits in progress. Any critical vulnerability discovered in the contract code will continue to drain funds unchecked until an upgrade is deployed, and the upgrade mechanism itself has vulnerabilities (issue #5) that could be exploited to remove or bypass the pause.

Metadata

Metadata

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third Campaign

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions