fix: mitigate set-paused and set-fee-basis-points timelock bypass (Issue #224)#253
Merged
fix: mitigate set-paused and set-fee-basis-points timelock bypass (Issue #224)#253
Conversation
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.
# Conflicts: # CHANGELOG.md # README.md # frontend/eslint.config.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Addresses the timelock bypass vulnerability where
set-pausedandset-fee-basis-pointscan 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
useAdminhook polling contract owner, pending changes, and block heightadmin-contract.jsread-only query helpers with Clarity hex parseradmin-transactions.jstimelocked transaction builders (propose/execute/cancel)timelock.jsutility module with countdown, progress, and formattingset-pausedandset-fee-basis-pointsstring literalsChainhook Monitoring
bypass-detection.jsmodule flagging direct admin calls that skip timelock/api/admin/eventsendpoint for admin event history/api/admin/bypassesendpoint for detected bypass eventsDocumentation
Verification