Reproduced Exploit
beraBTC — a blacklisted holder still moves 1000 tokens through an approval
notBlacklisted reverts when isBlacklisted[msg.sender] is true. transfer and transferFrom both use it. The holder's own transfer reverts after they are blacklisted. transferFrom does not look at from, so a spender they approved beforehand moves the 1000. The fixed transferFrom also rejects a blackli…
Chain
Other
Category
access-control
Date
Apr 2025
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 55100-h-01-blacklisted-user-can-transfer-tokens-via-approved-addre. Standalone Foundry PoC and full write-up: 55100-h-01-blacklisted-user-can-transfer-tokens-via-approved-addre_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/access-control/missing-auth · vuln/logic/missing-check
Key info#
| Protocol | Terplayer beraBTC |
| Finding | Shieldify H-01, AuditVault 55100 |
| Vulnerable code | notBlacklisted on transferFrom checks only msg.sender |
| Harm | 1000 tokens move from a blacklisted holder to an approved spender |
| Chain | local synthetic |
TL;DR#
notBlacklisted reverts when isBlacklisted[msg.sender] is true. transfer and transferFrom both use it. The holder's own transfer reverts after they are blacklisted. transferFrom does not look at from, so a spender they approved beforehand moves the 1000. The fixed transferFrom also rejects a blacklisted from, and the 1000 stay.
The vulnerable code#
modifier notBlacklisted() {
// @> VULN: only the caller is checked. transferFrom never looks at `from`.
if (isBlacklisted[msg.sender]) revert AccountIsBlacklisted();
_;
}
function transferFrom(address from, address to, uint256 amount) public notBlacklisted returns (bool) {
// spends `from`, who was never checked
}
Root cause#
The blacklist is applied to the caller of the token function. transferFrom's caller is the spender, not the owner. An approval created before the blacklist is still a valid allowance, and the modifier never reads from.
Preconditions#
The holder has 1000 tokens and has approved the spender for 1000. The holder is then blacklisted. The spender is not blacklisted.
Attack walkthrough#
- The holder is minted 1000 and approves the spender.
- The holder is blacklisted. Their own
transferreverts. - The spender calls
transferFrom. The modifier sees a non-blacklisted caller and the 1000 move.
The control uses a transferFrom that reverts when from is blacklisted. The same call reverts and the holder keeps 1000.
Diagrams#
Impact#
A blacklisted holder moves 1000 tokens through a pre-existing approval. The blacklist does not freeze that balance.
Remediation#
In transferFrom, reject the call when from is blacklisted as well as when msg.sender is blacklisted.
Sources#
- AuditVault finding: https://github.com/Auditware/AuditVault/blob/main/findings/55100-h-01-blacklisted-user-can-transfer-tokens-via-approved-addre.md
- Shieldify report (Terplayer beraBTC, upgradeable ERC20, April 2025): https://github.com/shieldify-security/audits-portfolio-md/blob/main/Terplayer-BeraBTC-Security-Review.md
- Vulnerable code:
batoshidao/bera-bitcoinsrc/BeraBitcoin.solat19d509911de64a062dfaeef33f14e26f08b23c10(notBlacklistedandtransferFrom).
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 55100-h-01-blacklisted-user-can-transfer-tokens-via-approved-addre_exp (evm-hack-registry mirror).
- AuditVault finding: 55100-h-01-blacklisted-user-can-transfer-tokens-via-approved-addre.
Alerts & third-party analyses
These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.