Kuby (Kuby) security report
Radar by SecureChain AI scanned Kuby’s verified contract source on BNB Smart Chain. The review found material control and transfer-availability risks, while GoPlus reported no minting, blacklist, proxy, or honeypot signal.
The source does not show an unrestricted mint, blacklist, or obvious direct theft function. Material risks remain: the owner controls when pool trading becomes available, a configured dividend contract can block ordinary transfers by reverting, and tax processing depends on an external processor that can receive accumulated tax tokens.
Trust score: 58/100. Source verified: Yes. Chain: bsc. Contract: 0x955fbb58fed462ac0ad8f79b092490abe3177777.
This report was last modified on 2026-10-07 and contains 4 material findings.
medium finding: Owner-controlled migration can keep pool transfers restricted
The contract initializes in BondingCurve state and rejects every transfer involving a configured pool. Only the owner can call startMigration(), followed by finalizeMigration(), so the owner controls when pool transfers are permitted and when trading tax logic begins. There is no automatic transition from BondingCurve.
Evidence: initialize() sets poolState.state to PoolState.BondingCurve. In _transfer(), BondingCurve requires !pools[from] && !pools[to], reverting with "Transfers to/from pools are restricted in BondingCurve state". startMigration() and finalizeMigration() are both external onlyOwner functions.
Recommendation: Use an immutable or time-bounded launch mechanism, require multisignature governance for migration controls, and publish the configured pool addresses and transition criteria. Test that users can exit or transfer tokens under every intended state.
medium finding: Dividend callback can block ordinary token transfers
When dividendContract is configured, transfers involving non-excluded addresses synchronously call IDividend.setShare(). Any revert from that external contract is propagated as DividendShareUpdateFailed, causing the entire token transfer to revert. A malfunctioning, restrictive, or unavailable dividend contract can therefore create a material transfer denial-of-service condition.
Evidence: _afterTokenTransfer() calls IDividend(dividendContract).setShare(from, balanceOf(from)) and setShare(to, balanceOf(to)) inside try/catch blocks. Each catch executes revert DividendShareUpdateFailed(...). The callback is skipped only for the token contract, zero address, dead address, dividend contract, or configured pools.
Recommendation: Decouple share accounting from ERC-20 transfer success, or make callback failures non-blocking with bounded recovery mechanisms. Add an emergency setter or fail-open mode governed by a timelocked multisignature process.
medium finding: Tax liquidation relies on a privileged external processor
Collected tax tokens are approved to taxProcessor with an unlimited allowance. If processTaxTokens() reverts, the contract catches the error and transfers its entire remaining token balance directly to taxProcessor. The processor is supplied during initialization and cannot be changed through the shown token contract, making its correctness and custody behavior a critical external dependency.
Evidence: _processTax() sets allowance(address(this), taxProcessor) to type(uint256).max when needed, calls ITaxProcessor(taxProcessor).processTaxTokens(taxAmount), and on failure executes _plainTransfer(address(this), taxProcessor, remainingBalance).
Recommendation: Use a narrowly scoped allowance, transfer only the intended tax amount on failure, validate processor code and configuration during initialization, and add governance-controlled recovery or replacement procedures for processor failure.
medium finding: Tax expiry is finalized only during a sell to the main pool
Tax and anti-farmer state transitions are checked inside _liquidateTax(), but that function performs state transition checks only when the current transfer recipient is mainPool. Consequently, a transfer involving another pool or a wallet-to-wallet transfer can continue using the old tax-enforced state after the configured expiration until a qualifying sell occurs.
Evidence: _transfer() calls _liquidateTax(to). _liquidateTax() enters its state-transition and expiration logic only when to == mainPool. Expiration checks then set TaxFree or TaxEnforced state and zero tax rates, but no equivalent check runs for other transfer recipients.
Recommendation: Evaluate expiration before tax calculation for every transfer, or provide a permissionless state-sync function that can finalize expired tax phases without requiring a sell to mainPool.