Crocollout (Crocollout) security report
Radar AI reviewed Crocollout's verified source on BNB Smart Chain. Material findings include unprotected initialization, tax-rate validation gaps, dividend-hook denial of service, and trusted tax-processor custody. Slither was not run.
The contract does not expose a public mint function after initialization, blacklist, pause, or proxy-admin upgrade function in the supplied source. However, deployment must atomically initialize each instance, because an uninitialized instance can be claimed by any caller. Initialization parameters also create meaningful configuration and external-dependency risks.
Trust score: 48/100. Source verified: Yes. Chain: bsc. Contract: 0xaea02d78674ee262c82c3b8441cddc10a64a7777.
This report was last modified on 2026-10-10 and contains 4 material findings.
high finding: Permissionless initialization can seize an uninitialized instance and mint the full supply
initialize is externally callable and protected only by the one-time initializer guard, with no deployer or factory authorization. The first caller sets the owner, tax processor, dividend contract, pools, taxes, and receives maxSupply through _mint(msg.sender, maxSupply). If a deployed instance is left uninitialized, any caller can initialize it and become the token owner while receiving the entire initial supply.
Evidence: FlapTaxTokenV3.initialize(...) is declared external and uses initializer without an access restriction. It calls __Ownable_init(), which assigns ownership to _msgSender(), and then calls _mint(msg.sender, maxSupply). The constructor disables initialization only on the implementation contract, not on a separate proxy or clone instance.
Recommendation: Initialize every instance atomically during deployment, preferably by passing initialization calldata through the proxy or clone deployment transaction. Verify the initialized event, owner, token parameters, and recipient before making the instance available for use.
medium finding: Initializer accepts tax rates above 100%, which can lock pool transfers
The initializer does not constrain buyTax or sellTax to a valid percentage. When tax is applied, _taxedTransfer calculates remainingAmount = amount - tax. A rate above 10000 basis points makes tax exceed amount for nonzero transfers and causes an arithmetic underflow revert, blocking the affected buy or sell path while the relevant tax state is active.
Evidence: initialize stores params.buyTax and params.sellTax directly in poolState. _getTaxWithPoolState computes amount * rate / 10000, and _taxedTransfer executes uint256 remainingAmount = amount - tax without a cap or validation. The fields are uint16, so values greater than 10000 are accepted.
Recommendation: Require both tax rates to be less than or equal to 10000 during initialization, and add tests covering boundary values. If rates are intended to be immutable, validate them before any instance can be initialized.
medium finding: External dividend hook can revert ordinary transfers
When dividendContract is nonzero, every transfer involving a non-excluded user calls IDividend.setShare. Any revert from that external contract is converted into DividendShareUpdateFailed and reverts the token transfer. A misconfigured, incompatible, unavailable, or intentionally reverting dividend contract can therefore block user transfers and pool trades that update a user share.
Evidence: _afterTokenTransfer calls IDividend(dividendContract).setShare(from, balanceOf(from)) and setShare(to, balanceOf(to)) inside try/catch blocks. The catch clauses explicitly revert DividendShareUpdateFailed. The dividendContract address is supplied during initialize and has no setter or validation that the target implements the expected behavior.
Recommendation: Validate the dividend contract during initialization, consider making share updates non-blocking, and provide a controlled recovery path such as disabling the hook or replacing a failed dividend module under tightly governed authorization.
medium finding: Configured tax processor has broad custody over accrued tax tokens
The configured taxProcessor receives an unlimited token allowance from the token contract. It is called to process accrued taxes, and if processing fails, the catch path transfers the token contract's remaining balance directly to taxProcessor. This is an intentional trusted-role design, but a malicious or compromised processor can take accrued tax balances and influence the tax-processing outcome.
Evidence: _processTax sets _approve(address(this), taxProcessor, type(uint256).max) when needed, then calls ITaxProcessor(taxProcessor).processTaxTokens(taxAmount). If that call reverts, the contract executes _plainTransfer(address(this), taxProcessor, remainingBalance). taxProcessor is supplied during initialize and cannot be changed in the shown contract.
Recommendation: Use an audited immutable processor, validate its address and code interface during initialization, avoid unlimited approvals where practical, and replace the fallback transfer with a governed recovery mechanism that preserves accounting and limits unauthorized custody.