Radar by SecureChain AI

分身 (分身) security report

Radar AI scanned the verified 分身 contract on BNB Smart Chain. Material findings include broad tax-processor authority, lazy tax expiry, callback-based transfer blocking, and full-supply assignment at initialization.

The contract is not free of material security risks. The most significant issue is the trust placed in the configured tax processor, which receives an effectively unlimited allowance and can receive the token contract's remaining balance when processing fails. Additional medium-severity risks affect tax expiry, transfer availability, and supply allocation.

Trust score: 48/100. Source verified: Yes. Chain: bsc. Contract: 0xc0ffa44cce92071d9bdac92798056e9edb0f7777.

This report was last modified on 2026-10-07 and contains 4 material findings.

high finding: Tax processor receives broad custody authority over contract-held tokens

The token grants the configured taxProcessor an effectively unlimited allowance and invokes it during tax liquidation. If processing reverts, the fallback path transfers the entire remaining token balance held by the token contract to taxProcessor, not only the current tax amount. A compromised, malicious, or incorrectly configured processor could therefore divert contract-held tokens.

Evidence: In _processTax(), the contract sets allowance(address(this), taxProcessor) to type(uint256).max when the current allowance is insufficient, then calls ITaxProcessor(taxProcessor).processTaxTokens(taxAmount). In the catch block it reads balanceOf(address(this)) and calls _plainTransfer(address(this), taxProcessor, remainingBalance), transferring all tokens held by the token contract after a processing failure.

Recommendation: Use a narrowly scoped allowance for the current taxAmount, avoid granting a permanent maximum allowance, and restrict fallback transfers to the amount being processed. Validate the processor implementation and add explicit emergency controls and monitoring for processor balance movements.

medium finding: Initialization assigns the full maximum supply to the initializer

The initialization routine mints the entire fixed maximum supply to msg.sender. There is no vesting, distribution constraint, allocation split, or mint authorization beyond the one-time initializer guard. This creates a significant supply-allocation and centralization risk if initialization is performed by an unintended account or without separate distribution controls.

Evidence: initialize() executes _mint(msg.sender, maxSupply), and maxSupply is defined as 1e9 ether. The initializer caller is also made the Ownable owner through __Ownable_init().

Recommendation: Use an explicit treasury or distribution recipient rather than msg.sender, validate the intended recipient during deployment, and document or enforce vesting and allocation controls outside the token contract where appropriate.

medium finding: Tax expiration is enforced only after a sell to the main pool

The configured tax duration does not automatically transition the token to TaxFree at the expiration timestamp. The state transition is evaluated only inside _liquidateTax(), and _liquidateTax() runs its state-transition logic only when the current transfer recipient is mainPool. Until such a sell occurs, pool transfers can continue using the expired tax rates.

Evidence: _transfer() calls _liquidateTax(to), while _liquidateTax() enters its state-transition branch only when to == mainPool. The expiration check then changes the state to TaxFree and zeros the tax rates. Buys from mainPool and transfers involving other configured pools do not satisfy that trigger condition.

Recommendation: Evaluate expiration before every taxed transfer, or expose a permissionless state-maintenance function that can transition expired tax state without requiring a sell to mainPool. Add tests covering buys and secondary pools after expiration.

medium finding: Dividend callback can block token transfers

When dividendContract is configured, every non-excluded sender or recipient causes an external setShare call. Any revert from that callback is propagated as DividendShareUpdateFailed, causing the entire token transfer to revert. A faulty, unavailable, or hostile dividend contract can therefore create a transfer lock for affected addresses.

Evidence: _afterTokenTransfer() calls IDividend(dividendContract).setShare(from, balanceOf(from)) and setShare(to, balanceOf(to)) for non-excluded addresses. Each call is wrapped in try/catch, but the catch block reverts with DividendShareUpdateFailed rather than allowing the ERC20 transfer to complete.

Recommendation: Decouple balance transfers from dividend bookkeeping. Consider non-blocking callbacks, bounded failure handling, or an asynchronous share-update queue. Validate the dividend contract during initialization and provide a safe recovery path if it becomes unavailable.