fix: prevent external weight downgrade via /epoch/enroll#2110
Merged
Scottcjn merged 1 commit intoScottcjn:mainfrom Apr 6, 2026
Merged
fix: prevent external weight downgrade via /epoch/enroll#2110Scottcjn merged 1 commit intoScottcjn:mainfrom
Scottcjn merged 1 commit intoScottcjn:mainfrom
Conversation
Contributor
Author
|
For bounty payout, please use RTC wallet: RTC1d48d848a5aa5ecf2c5f01aa5fb64837daaf2f35. |
Owner
|
Merged. Payment: 50 RTC. Addresses #2109.
|
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.
Fix: prevent external weight downgrade via /epoch/enroll
Problem
The
/epoch/enrollendpoint andsophia_elya_service.enroll_epoch()useINSERT OR REPLACE INTO epoch_enroll, allowing any caller to overwrite alegitimate miner's epoch weight with a near-zero value. This causes
proportional reward loss for the victim miner.
Unlike the prior fix (which covered the auto-enroll path and attestation
record path), the explicit enrollment endpoint remained vulnerable to
external downgrade — an attacker with a miner's pubkey can call this
endpoint to destroy the miner's epoch rewards.
Exploit:
POST /epoch/enrollwith victim'sminer_pubkey+ empty/defaultdevice→ weight recalculated as 1.0 (or 1e-9 if fingerprint fails) →INSERT OR REPLACEoverwrites victim's legitimate enrollment (e.g. 2.5).Changes
node/rustchain_v2_integrated_v2.2.1_rip200.py/epoch/enrollendpoint: ChangeINSERT OR REPLACEtoINSERT OR IGNOREforepoch_enroll. The first enrollment in an epochwins; subsequent calls for the same
(epoch, miner_pk)are no-ops.node/sophia_elya_service.pyenroll_epoch(): SameINSERT OR REPLACE→INSERT OR IGNOREchange.node/tests/test_attestation_overwrite_reward_loss.py3 new tests:
test_external_enroll_downgrade_old_behaviour— demonstrates the externaldowngrade bug (INSERT OR REPLACE allows weight overwrite)
test_external_enroll_downgrade_fixed— verifies INSERT OR IGNORE blocksthe external downgrade
test_first_enroll_wins_fixed— documents the first-enrollment-winstrade-off (acceptable: attacker needs victim's pubkey and sacrifices own rewards)
Testing
All 11 tests pass (8 existing + 3 new).
Risk
Minimal. Narrowly scoped to the
epoch_enrollupsert logic:INSERT OR IGNOREonly affects same-epoch re-enrolls; new epochs are unaffected.INSERT OR IGNORE.Trade-off
With
INSERT OR IGNORE, the first enrollment wins. An attacker who enrollsa victim's pubkey first with low weight blocks the victim's later legitimate
enrollment. This is acceptable because: