CRITICAL: Unauthenticated Balance Inflation in Continuous Flow Streams
Affected Function
add_continuous_balance (L5506) -> delegates to add_balance_to_flow (L2817)
Description
add_continuous_balance is a public entry point with zero require_auth() on either the wrapper or its internal delegate add_balance_to_flow.
Unlike update_flow_rate which has env.current_contract_address().require_auth() at L2676, add_balance_to_flow (L2817-L2846) has NO auth check whatsoever - it simply fetches the flow, adds additional_balance to flow.accumulated_balance, and stores it.
Attack
- Attacker calls
add_continuous_balance(env, victim_stream_id, 1_000_000)
add_balance_to_flow inflates flow.accumulated_balance by 1,000,000 with no token deposit
- The stream now has 1,000,000 extra units of
accumulated_balance
- When the stream recipient claims or
sweep_dust runs, tokens are transferred from the contract shared token pool - stealing from legitimate depositors
Comparison
update_flow_rate (L2676): has env.current_contract_address().require_auth() - partial protection via self-auth
add_balance_to_flow (L2817): NO auth of any kind - confirmed unprotected
Impact
- Any caller can inflate any stream balance without depositing tokens
- Draws from the contract shared token pool when claims are processed
- Scalable - attacker can target multiple streams
Severity: CRITICAL
No authentication required. Direct theft from shared pool.
Fix
Add flow.provider.require_auth() to add_continuous_balance wrapper before calling add_balance_to_flow.
Also recommend adding flow.provider.require_auth() to update_continuous_flow_rate (L5497), pause_continuous_flow (L5549), and resume_continuous_flow (L5554).
CRITICAL: Unauthenticated Balance Inflation in Continuous Flow Streams
Affected Function
add_continuous_balance(L5506) -> delegates toadd_balance_to_flow(L2817)Description
add_continuous_balanceis a public entry point with zerorequire_auth()on either the wrapper or its internal delegateadd_balance_to_flow.Unlike
update_flow_ratewhich hasenv.current_contract_address().require_auth()at L2676,add_balance_to_flow(L2817-L2846) has NO auth check whatsoever - it simply fetches the flow, addsadditional_balancetoflow.accumulated_balance, and stores it.Attack
add_continuous_balance(env, victim_stream_id, 1_000_000)add_balance_to_flowinflatesflow.accumulated_balanceby 1,000,000 with no token depositaccumulated_balancesweep_dustruns, tokens are transferred from the contract shared token pool - stealing from legitimate depositorsComparison
update_flow_rate(L2676): hasenv.current_contract_address().require_auth()- partial protection via self-authadd_balance_to_flow(L2817): NO auth of any kind - confirmed unprotectedImpact
Severity: CRITICAL
No authentication required. Direct theft from shared pool.
Fix
Add
flow.provider.require_auth()toadd_continuous_balancewrapper before callingadd_balance_to_flow.Also recommend adding
flow.provider.require_auth()toupdate_continuous_flow_rate(L5497),pause_continuous_flow(L5549), andresume_continuous_flow(L5554).