Skip to content

fix: mitigate set-paused and set-fee-basis-points timelock bypass (Issue #224)#253

Merged
Mosas2000 merged 34 commits intomainfrom
fix/set-paused-timelock-bypass
Mar 10, 2026
Merged

fix: mitigate set-paused and set-fee-basis-points timelock bypass (Issue #224)#253
Mosas2000 merged 34 commits intomainfrom
fix/set-paused-timelock-bypass

Conversation

@Mosas2000
Copy link
Copy Markdown
Owner

Summary

Addresses the timelock bypass vulnerability where set-paused and set-fee-basis-points can circumvent the 144-block timelock in the deployed mainnet contract. Since the contract is immutable on mainnet, mitigation is applied at the frontend, monitoring, documentation, and operational layers.

Closes #224

Changes

Frontend

  • AdminDashboard component with timelocked-only pause and fee controls
  • useAdmin hook polling contract owner, pending changes, and block height
  • admin-contract.js read-only query helpers with Clarity hex parser
  • admin-transactions.js timelocked transaction builders (propose/execute/cancel)
  • timelock.js utility module with countdown, progress, and formatting
  • Admin nav link restricted to contract owner only
  • Visual timelock progress bar on pending change cards
  • ESLint rules banning set-paused and set-fee-basis-points string literals

Chainhook Monitoring

  • bypass-detection.js module flagging direct admin calls that skip timelock
  • /api/admin/events endpoint for admin event history
  • /api/admin/bypasses endpoint for detected bypass events
  • Bypass scanning integrated into event processing loop

Documentation

  • Timelock bypass vulnerability audit report
  • Admin operations guide with timelocked procedures and monitoring
  • Contract upgrade strategy for v2 bypass removal
  • Security policy with timelock disclosure
  • README updated with- README updated with- README updated with- README updated with- README updatimelock utilities
  • 18 unit tests for Clarity hex parser
  • 19 unit tests for admin transaction builders
  • 9 print event verification tests for timelocked and bypass operations
  • 25 contract tests for timelocked pause/fee propose/execute/cancel cycles

Verification

  • Frontend buil- Frontend buil- Frontend buil- Frontend buil- Frontets- Frontend buil- Frontend buis from missing simnet contracts)
  • 77 frontend unit tests pass
  • No Vercel deployment impact

Document the dual admin path vulnerability where set-paused and
set-fee-basis-points bypass the 144-block timelock mechanism in the
deployed mainnet contract. Classify severity as high with detailed
risk assessment, root cause analysis, and mitigation strategy.
Define standard operating procedures for pause and fee management
using the propose-wait-execute pattern. Document when emergency
bypass is justified, pending change queries, multisig integration,
and incident response procedures.
Outline the v2 contract design that removes direct bypass functions,
adds emergency-specific authorization, includes cancel-pause-change,
and implements timelock extension. Describe migration strategy from
v1 to v2 with deployment checklist and timeline.
Document the known dual-path admin vulnerability, timelocked vs
direct bypass functions, post-condition enforcement, ownership
transfer safety, and contributor security checklist.
Replace non-existent set-fee and toggle-pause with the actual
function names: set-fee-basis-points, set-paused, propose-fee-change,
execute-fee-change, cancel-fee-change, propose-pause-change, and
execute-pause-change. Note which functions bypass the timelock.
Include get-pending-fee-change, get-pending-pause-change,
get-multisig, and get-contract-version in the read-only functions
table to document the full admin query surface.
Document the 144-block timelocked admin changes, frontend enforcement
of timelocked paths over direct bypass, and optional multisig
governance layer in the security section.
Test propose-pause-change authorization, pending state verification,
timelock enforcement before 144 blocks, successful execution after
timelock, non-admin execution rejection, no-pending-change rejection,
state cleanup after execution, and proposal override behavior.
Change result.data to result.value to match Clarity value wrapper
structure returned by simnet callReadOnlyFn. Fix expect.any assertion
that is incompatible with Cl.uint constructor.
Implement TIMELOCK_BLOCKS constant, estimateSecondsRemaining,
isTimelockExpired, timelockProgress, formatDuration,
formatBlocksRemaining, and getPendingChangeStatus helpers for
admin dashboard timelock display logic.
Implement fetchCurrentBlockHeight, fetchPauseState, fetchFeeState,
fetchContractOwner, fetchMultisig, and fetchCurrentFee read-only
query functions. Include a Clarity hex value parser for decoding
tuple, uint, bool, and optional response types.
Provide reactive admin state including contract owner, ownership
check, block height, pause state, fee state, and computed pending
change statuses. Poll the contract at a configurable interval and
expose a manual refresh function.
Implement proposePauseChange, executePauseChange, proposeFeeChange,
executeFeeChange, and cancelFeeChange using openContractCall with
PostConditionMode.Deny. Explicitly exclude direct bypass functions
set-paused and set-fee-basis-points from the frontend API.
Build the admin dashboard with PauseSection and FeeSection sub-
components that exclusively use propose-wait-execute operations.
Include timelock progress bars, block countdown display, pending
change cards, and owner-only access guard. Direct bypass functions
are intentionally excluded from the UI.
Add Shield from lucide-react for admin nav item icon and register
AdminDashboard as a lazy-loaded component for code-splitting.
Register the AdminDashboard component at /admin with the connected
user address and toast callback. The component enforces owner-only
access internally, so all authenticated users can navigate to the
route but non-owners see an access restricted message.
Include the Admin tab with Shield icon in the navigation items
array. The route is visible to all authenticated users but the
AdminDashboard component enforces owner-only access internally.
Add block-based countdown helpers including blocksRemaining,
estimateTimeRemaining, getPendingChangeStatus, timelockProgress,
formatBlockHeight, and formatBasisPoints. Define TIMELOCK_BLOCKS
constant of 144 and AVERAGE_BLOCK_TIME_SECONDS of 600.
Build the full AdminDashboard component with owner-only access guard,
pause propose/execute controls, fee propose/execute/cancel controls,
status cards for block height and owner, pending change cards with
countdown timers, and a security notice about timelock enforcement.
The direct bypass functions are intentionally excluded.
Cover blocksRemaining edge cases, estimateTimeRemaining formatting,
getPendingChangeStatus transitions between NONE/PENDING/READY,
timelockProgress calculation at boundaries, formatBlockHeight with
null and locale handling, and formatBasisPoints conversion accuracy.
Test parseClarityValue with null inputs, primitive types including
bool, uint, and none, optional wrapping with some/none, ok/err
response unwrapping, and 0x prefix handling.
Test all five timelocked transaction functions with mock contract
calls, verify PostConditionMode.Deny enforcement, validate fee
bounds checking, confirm bypass functions set-paused and
set-fee-basis-points are never invoked, and test callback wiring.
Disallow string literals 'set-paused' and 'set-fee-basis-points'
in frontend source code using no-restricted-syntax. Each violation
shows a message directing developers to the timelocked alternatives
propose-pause-change and propose-fee-change.
Document all security fixes, new admin components, utility modules,
test suites, documentation, and corrections added in this branch
under the Unreleased section.
Detect when set-paused or set-fee-basis-points bypass the timelock
by checking for contract-paused and fee-updated events without
corresponding timelocked proposal history. Include alert formatting
and admin event parsing for the chainhook callback server.
Import bypass detection module and scan all incoming events for
timelock bypass usage. Log security alerts when direct set-paused
or set-fee-basis-points calls are detected without corresponding
timelocked proposals. Also log all admin events for audit trail.
@Mosas2000 Mosas2000 merged commit 22c3f1f into main Mar 10, 2026
3 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🟠 HIGH: set-paused bypasses timelock governance in tipstream.clar

1 participant