FeeRouter: setDistributableToken can brick live-sale buys via canonical-asset delisting (DoS vector behind GOVERNOR_ROLE) #127
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:open_issues
agents
agent:security_audit
agent:verify
area
timecurve
arena
arena-v2
audit
block:feature_review
block:security
bug
contracts
design
devops
docs
documentation
enhancement
epic
feature
frontend
indexer
low priority
megaeth
operations
ops
performance
QA
qa checklist
referrals
removal
security
smart-contracts
tech-debt
testing
time-arena
timecurve
visual-qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
code/yieldomega#127
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
found during the post-audit security review pass (followup to #126).
Summary
FeeRouter.setDistributableToken(IERC20 token, bool allowed)(line 112) letsGOVERNOR_ROLEtoggle any token in/out of the distribution allowlist with no guards.distributeFees(line 70) reverts on non-allowlisted tokens.TimeCurve._buycallsfeeRouter.distributeFees(acceptedAsset, amount)on every buy. ifdistributableToken[acceptedAsset]is set tofalsemid-sale, every subsequentbuy()reverts. sale frozen until governor re-allowlists.Code
FeeRouter.sol:112-116:FeeRouter.sol:73:TimeCurve.sol:423-424(consumes from_buy):Attack paths
setDistributableToken(CL8Y, false)→ all buys revert. recovery requires governor key recovery + re-allowlist tx. live sale frozen during gap.allowed=false) → if the wrong address happens to be CL8Y, same outcome.during the freeze window:
extendDeadlinemath still ticksdistributeFees)deadlinemay have moved against participantsSeverity
Medium — privileged DoS, no fund extraction. but new category not explicitly covered by audit H-01 (which focused on "redirect value" rather than "brick distribution").
Mitigations
pick one or combine:
acceptedAssetas immutable distributable — never allowed to be unlisted. requires either an immutable mapping seed or a runtime check that prevents settingdistributableToken[canonicalSaleAsset] = false.unfreezeFeeRoutingadmin call that re-allowlists in a single tx. doesn't prevent the DoS, just reduces recovery latency.startUnlistToken+finalizeUnlistTokenwith a delay window. gives ops time to catch mistakes.option 1 (hardcode canonical asset) is strongest. option 2 is least invasive change.
Pre-deploy relevance
This is in v1 deployment scope (FeeRouter ships tonight). worth a fix or explicit operational policy (e.g., "governor mnemonic stays cold-stored, only thawed for emergency rotation") before mainnet.
cc @PlasticDigits
mentioned in issue #130
mentioned in issue #131
Acceptable governance risk. Closing