Attack Vector
In UnDelegateResourceActuator.execute(), the transferUsage calculation uses Java double casting for bandwidth accounting. With large TRON balances (billions of SUN), the double cast silently drops precision — systematic underestimation of reclaimed bandwidth. Attacker can accumulate "ghost bandwidth" beyond staked TRX cap.
Kill Chain
1Account A: freeze 10,001,000 SUN for BANDWIDTH
2Delegate to Account B at precision-edge amount
3B spends bandwidth to trigger double truncation floor
4A undelegates — transferUsage = L instead of L+1
5B retains ghost bandwidth · Repeat to amplify
Vulnerable Code
transferUsage = (long) (receiverCapsule.getNetUsage()
* ((double) (unDelegateBalance)
/ receiverCapsule.getAllFrozenBalanceForBandwidth()));
Java double: 53-bit mantissa. With billion-SUN values, integer precision drops below 1 unit. Systematic floor truncation.
Shape · S_precision · Integer/Float Boundary
Invariant violated:
transferUsage(exact) = ⌊N × B / F⌋
transferUsage(double) = ⌊N × (double)(B/F)⌋
For large values, the double intermediate introduces systematic rounding error:
double_result ≤ exact_result - 1
The difference of 1 unit per delegation cycle compounds across many accounts. Bandwidth in the system exceeds the staked TRX cap — a mint-like invariant violation at the resource layer.
γ₁ Stratum · T4 (47min)
T4 = throttle/queue/resource windows. Each delegate/undelegate cycle takes ~47min to reclaim bandwidth through the normal TRON maintenance interval. Attacker exploits this window to amplify ghost bandwidth accumulation.
Adelic Weight
γ₁/(L+1) = 14.134725 / (2+1) = 4.71
L=2 · Requires TRON testnet PoC
Theorem · PrecisionLossInvariantViolation
-- Bandwidth conservation: total_reclaimed = total_delegated
def bandwidthConservation (delegate undelegate : ℤ → ℤ) : Prop :=
∀ n f : ℤ, delegate n + undelegate n = n
-- Float truncation breaks conservation:
theorem double_truncation_violates_conservation
(n f : ℤ)
(h_large : n * f > 2^53) -- exceeds double mantissa
(exact_result := n / f)
(double_result := (n : Float).toUInt64.toInt / (f : Float).toUInt64.toInt) :
double_result < exact_result := by
-- When n*f > 2^53, float division drops the LSB
-- double_result can be ≤ exact_result - 1
-- ∴ undelegate returns less than delegated
-- ghost bandwidth = exact_result - double_result ≥ 1
sorry -- requires numeric analysis over IEEE 754
-- Fix: use integer-only arithmetic
theorem integer_fix_preserves_conservation (n f : ℤ) :
(n * bandwidthUsage / f : ℤ) = ⌊(n : ℚ) * bandwidthUsage / f⌋ := by
simp [Int.ediv_eq_fdiv]
Fix
Replace double cast with:
Math.multiplyExact(receiverCapsule.getNetUsage(), unDelegateBalance) / receiverCapsule.getAllFrozenBalanceForBandwidth()
Filing Blocker
Verify before filing:
1. Clone tronprotocol/java-tron develop branch
2. Confirm double-cast still present in UnDelegateResourceActuator
3. Run PoC on TRON Nile testnet
4. Check TRON DAO audit reports (Least Authority, Slowmist)
Filing Status
Programme: TRON DAO (hackerone.com/tron_dao)
File after MM-005/006 land
Expected: $5K–$50K
Priority: P4