For the complete documentation index, see llms.txt. This page is also available as Markdown.

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 — TxExtension ordering

  • runtime/src/configs/mod.rs — is_whitelisted

  • primitives/high-security/src/lib.rs — is_call_allowed

  • pallets/reversible-transfers/README.md — stated guarantees

  • pallets/mining-rewards/src/lib.rs — CollectedFees payout to block author

Proof of Concept

1

Save the test

Save the test below as runtime/tests/hs_tip_drain_poc.rs in audit-comp-quantus-chain at commit 3b243b870a5442a6e5f443056f67bbba87d472f5.

2

Run the test

3

Observed output

4

Test source

Was this helpful?