Conversation
unrentRegion computed the pro-rata refund as
price * remainingSeconds / totalSeconds
where remainingSeconds came from (now -> endDate) but totalSeconds was a single
durationSeconds. renewLeasehold pushes endDate out by another durationSeconds per
renewal without re-escrowing, so a tenant could rent a region, renew it N times
(free, and unlimited when maxExtensions is null), then unrent for a refund of
price * N β draining the landlord's account. Observed in production: a $150 rent
refunded as $49,999.73.
Clamp remainingSeconds to a single period (totalSeconds) so the refund can never
exceed one period's price β the amount actually paid for the current term.
Adds a regression test (rent -> renew x5 -> unrent) asserting refund <= price.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
md5sha256
approved these changes
Jun 21, 2026
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.
Security fix β early lease termination refund could drain landlords
The bug
RealtyBackendImpl.unrentRegioncomputed the pro-rata refund as:where
remainingSecondsisnow β endDatebuttotalSecondsis a singledurationSeconds.renewLeasehold(MariaLeaseholdContractMapper) extendsendDateby anotherdurationSecondsper renewal without re-escrowing, and renewals are unlimited whenmaxExtensionsis null. So a tenant could:price,unrentβ refundprice Γ N, debited from the landlord.The ledger stays balanced (no minting), but it drains the landlord's real balance.
Observed in production (DemocracyCraft, 2026-06-14): a
$150rent refunded as$49,999.73; ~$294k moved from three landlords to two tenant accounts in ~20 minutes.The fix
Clamp
remainingSecondsto a single period (totalSeconds), so the refund can never exceed one period'spriceβ the amount actually paid for the current term.Test
Adds a regression test (
RealtyBackendImplTest.UnrentRefund): rent β renew Γ5 β unrent must refund β€ one period's price. Pre-fix this returnedprice Γ 6.Follow-ups (not in this PR β separate decisions)
maxExtensions(no unlimited renewals).Remediation (out of band)
The exploited balances still need reversing (claw back the two tenant accounts; restore the three landlords). Staff issued a partial fine already.