Severity: High
After a transfer_from spends an allowance, the contract does not reduce the stored allowance. The spender can call transfer_from repeatedly, draining the owner's balance far beyond the approved amount.
- Alice approves Bob for 100 tokens.
- Bob calls
transfer_from(alice, bob, 100)— succeeds. - Bob calls
transfer_from(alice, bob, 100)again — still succeeds because the allowance was never decremented. - Bob drains Alice's entire balance.
pub fn transfer_from(env: Env, spender: Address, from: Address, to: Address, amount: i128) {
spender.require_auth();
let allowance = get_allowance(&env, &from, &spender);
assert!(allowance >= amount, "insufficient allowance");
// ❌ Missing: set_allowance(&env, &from, &spender, allowance - amount);
do_transfer(&env, &from, &to, amount);
}set_allowance(&env, &from, &spender, allowance - amount); // ✅
do_transfer(&env, &from, &to, amount);See the inline secure.rs module inside this crate for the full corrected implementation.