A critical vulnerability has been identified in the RAAC token's burn mechanism where users are subjected to double taxation during the burn operation. This occurs due to an interaction between the burn() function and the underlying _update() mechanism, resulting in excessive token burns and reduced tax collection.
The vulnerability exists in the burn() function implementation:
The issue arises because:
The function first calculates and applies the burn tax
Then uses _transfer for the tax amount, which triggers _update()
The _update() function applies the tax again on the tax transfer
Example calculation for burning 1000 tokens with 0.5% burn tax:
1. Initial tax calculation: 1000 0.5% = 5 tokens
2. First operation: Burns 995 tokens
Second operation: Transfers 5 tokens but gets taxed again
Final result:
FeeCollector receives 4.975 tokens (instead of 5)
Additional 0.025 tokens are burned
Total burned: 995.025 tokens (more than intended)
The vulnerability has three main impacts:
Protocol Revenue Loss: The protocol receives less tax than intended (4.975 instead of 5 tokens in the example)
Excessive Token Burn: More tokens are burned than should be (995.025 instead of 995)
User Asset Loss: Users lose more tokens than they should in the burn process
While the impact per transaction is small (0.025% in this example), it becomes significant with:
Large burn transactions
High frequency of burns
Long-term accumulation of losses
Severity: Medium
The issue is mathematically certain to occur
Results in direct financial loss
Affects both users and protocol revenue
But the per-transaction impact is relatively small
Manual code review
Unit testing with Hardhat
Mathematical analysis
POC test case demonstrating the vulnerability
This is by design, sponsor's words: Yes, burnt amount, done by whitelisted contract or not always occur the tax. The feeCollector is intended to always be whitelisted and the address(0) is included in the _transfer as a bypass of the tax amount, so upon burn->_burn->_update it would have not applied (and would also do another burn...). For this reason, to always apply such tax, the burn function include the calculation (the 2 lines that applies) and a direct transfer to feeCollector a little bit later. This is done purposefully
This is by design, sponsor's words: Yes, burnt amount, done by whitelisted contract or not always occur the tax. The feeCollector is intended to always be whitelisted and the address(0) is included in the _transfer as a bypass of the tax amount, so upon burn->_burn->_update it would have not applied (and would also do another burn...). For this reason, to always apply such tax, the burn function include the calculation (the 2 lines that applies) and a direct transfer to feeCollector a little bit later. This is done purposefully
This is by design, sponsor's words: Yes, burnt amount, done by whitelisted contract or not always occur the tax. The feeCollector is intended to always be whitelisted and the address(0) is included in the _transfer as a bypass of the tax amount, so upon burn->_burn->_update it would have not applied (and would also do another burn...). For this reason, to always apply such tax, the burn function include the calculation (the 2 lines that applies) and a direct transfer to feeCollector a little bit later. This is done purposefully
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.