89347 bc critical high security accounts can be drained immediately via an unbounded tip on a whitelisted call
Submitted on Aug 18th 2026 at 18:10:47 UTC by @Tradi3 for Audit Comp | Quantus
Report ID: #89347
Report Type: Blockchain/DLT
Report severity: Critical
Target: https://github.com/immunefi-team/audit-comp-quantus-chain
Impacts:
Direct loss of funds
Description
Commit: 3b243b870a5442a6e5f443056f67bbba87d472f5 (audit-comp-ready)
Brief / Intro
A high-security account is supposed to be unable to move funds immediately. Transfers are delayed and a guardian can cancel them. The runtime enforces this on the call only. It never looks at the tip.
A signed extrinsic carrying a whitelisted call and a large tip drains the account's free balance to the existential deposit in that same extrinsic. There is no delay, no pending transfer, and nothing for the guardian to cancel.
Vulnerability Details
ReversibleTransactionExtension sits before ChargeTransactionPayment in TxExtension (runtime/src/lib.rs). Its validate only checks the call:
is_call_allowed is !is_high_security || is_whitelisted(call) (primitives/high-security/src/lib.rs). The tip is not a parameter of that check, and pallet_reversible_transfers never inspects tips anywhere else.
cancel is listed in is_whitelisted (runtime/src/configs/mod.rs), so it passes the gate. ChargeTransactionPayment then computes the fee from the signed tip and withdraws it at pre-dispatch, before the call runs. There is no tip cap in the runtime.
Because the charge happens before dispatch, the call does not have to succeed. A cancel of a nonexistent tx_id is enough. Nothing is scheduled, so PendingTransfersBySender stays empty and the guardian has nothing to act on. The withdrawn amount is queued in CollectedFees and minted to the block author.
A direct Balances transfer from the same account is still rejected by the gate. That is the point: the whitelist works, but it does not cover the tip field.
This is the threat model the feature documents for itself. pallets/reversible-transfers/README.md states:
An attacker who compromises account keys cannot disable protections to steal funds immediately Users cannot be tricked into disabling security during a scam
Both claims fail when the signed extrinsic is a whitelisted call with a large tip. High-security mode cannot be switched off, and the documented way out is a delayed schedule_transfer; this path skips that delay entirely.
Impact Details
The high-security account's free balance is taken immediately, in one extrinsic. recover_funds cannot unwind a tip that has already gone to CollectedFees.
If the submitter also authors the block, pallets/mining-rewards/src/lib.rs mints that amount to the block author, so the attacker recovers the drained value. If they do not author the block, the funds are still gone from the victim.
The signed origin is the high-security account itself. The attack requires no pending transfer, no guardian signature, and no privileged role.
Recommendation
Reject a non-zero tip for high-security origins in ReversibleTransactionExtension, or charge tips through the same delayed, cancellable path used for transfers.
Add a regression test asserting that a whitelisted cancel carrying a large tip cannot reduce a high-security account's free balance outside the delayed-transfer rules.
References
runtime/src/lib.rs—TxExtensionorderingruntime/src/configs/mod.rs—is_whitelistedprimitives/high-security/src/lib.rs—is_call_allowedpallets/reversible-transfers/README.md— stated guaranteespallets/mining-rewards/src/lib.rs—CollectedFeespayout to block author
Proof of Concept
Was this helpful?