Radar by SecureChain AI

GangDaCook (Gang) security report

Radar AI-scanned GangDaCook's verified source on BNB Smart Chain. Findings include conditional proxy takeover risk, owner-controlled pool restrictions, transfer-blocking dividend callbacks, and external tax-processor dependency.

The source does not show an unrestricted mint, blacklist, or adjustable tax setter after initialization. Material risks remain: an uninitialized proxy could be seized by the first initializer, the owner can control migration timing while pool transfers are restricted in BondingCurve state, and a reverting dividend contract can block ordinary transfers.

Trust score: 58/100. Source verified: Yes. Chain: bsc. Contract: 0xf397998c705c1c3d82ee7456e04ef70c115d7777.

This report was last modified on 2026-10-05 and contains 5 material findings.

high finding: Uninitialized proxy could be taken over and fully supplied

The external initialize function is protected only by the standard one-time initializer guard. If a proxy deployment is left uninitialized, the first caller can set all configuration, become the Ownable owner, and receive the entire maxSupply through _mint(msg.sender, maxSupply). This is a conditional deployment risk rather than proof that the supplied address is currently uninitialized.

Evidence: FlapTaxTokenV3.initialize(...) is external and uses initializer; it calls __Ownable_init(), which assigns ownership to _msgSender(), and then calls _mint(msg.sender, maxSupply). The implementation constructor calls _disableInitializers(), but that does not initialize or lock a separate proxy. GoPlus supplied an owner address, which is consistent with an initialized deployment but does not independently prove that initialization was atomic.

Recommendation: Initialize the proxy atomically in its deployment transaction or factory flow, verify the Initialized and OwnershipTransferred events, and reject or quarantine any proxy whose initializer has not been consumed. Keep the implementation contract locked as already done.

medium finding: Owner-controlled migration timing can restrict pool transfers

While the token is in BondingCurve state, every transfer involving an address marked in pools reverts. Only the owner can advance the state through startMigration and finalizeMigration. A delayed or unavailable owner can therefore prevent transfers to or from configured pools until migration is progressed.

Evidence: _transfer checks PoolState.BondingCurve and requires !pools[from] && !pools[to], otherwise reverting with "Transfers to/from pools are restricted in BondingCurve state". startMigration() and finalizeMigration() are both external onlyOwner functions. The initializer marks every supplied params.pools address as a restricted pool.

Recommendation: Use an immutable or publicly verifiable migration schedule, enforce bounded state-transition deadlines, and monitor owner-controlled migration calls. Confirm that pool addresses and the operational migration authority are correct before enabling trading.

medium finding: Dividend callback failure can block ordinary token transfers

When dividendContract is nonzero, normal transfers invoke an external setShare callback for eligible sender and recipient addresses. Any callback failure is converted into a revert, so a broken, incompatible, or deliberately reverting dividend contract can prevent affected transfers from completing.

Evidence: _afterTokenTransfer calls IDividend(dividendContract).setShare(from, balanceOf(from)) and setShare(to, balanceOf(to)) inside try/catch blocks. Each catch executes revert DividendShareUpdateFailed(...). The dividendContract address is supplied during initialize and is not changeable through a public setter in this contract.

Recommendation: Validate the dividend contract before initialization, ensure it cannot be disabled accidentally, and provide a fail-open or administrative recovery design in a reviewed upgrade. Test transfers when the dividend callback reverts or runs out of gas.

medium finding: Tax processing delegates token custody to an initialization-time external processor

Collected tax tokens are approved to the configured taxProcessor with an effectively unlimited allowance. If processing reverts, the contract transfers its entire remaining token balance to that processor. This creates a strong trust and configuration dependency on the processor selected during initialization.

Evidence: _processTax sets allowance(address(this), taxProcessor) to type(uint256).max when needed. In the catch branch after processTaxTokens fails, it calls _plainTransfer(address(this), taxProcessor, remainingBalance). taxProcessor is assigned directly from params.taxProcessor in initialize and has no public setter or validation beyond nonzero.

Recommendation: Use a vetted immutable processor, validate its code and expected behavior before initialization, minimize allowances where practical, and add bounded recovery controls that do not automatically send all accumulated tax tokens to a failing external component.

medium finding: Initialization accepts unchecked pool and integration configuration

The initializer accepts arbitrary pool, router, quoteToken, taxProcessor, and dividendContract addresses. Incorrect or hostile values can alter which transfers are taxed or restricted, route tax processing externally, or trigger transfer failures through the dividend callback. The contract does not validate that configured addresses implement the intended interfaces.

Evidence: initialize stores params.v2Router, params.quoteToken, params.taxProcessor, params.dividendContract, and every params.pools entry without code-size or interface checks. _getTaxWithPoolState uses the pools mapping to identify buys and sells, while _afterTokenTransfer calls the configured dividendContract.

Recommendation: Perform interface and code validation during initialization, restrict pool configuration to a trusted factory or deployment process, and publish the complete initialization parameters for independent verification before use.