The deployMerkleDropper() function is a helper intended to be called only internally by run() during the deployment process.
However, the function is declared public instead of internal, making it callable by any external account or contract. This allows anyone to invoke it directly with arbitrary merkleRoot and zkSyncUSDC parameters, deploying unintended MerkleAirdrop instances that share no relation to the intended deployment. In a testing or staging environment this inflates the deployment footprint with spurious contract instances; in a production context it could be used to deploy lookalike contracts under the deployer's script address to mislead users.
Likelihood:
Any external account calls deployMerkleDropper() directly with a crafted merkleRoot and a fake token address, deploying a malicious MerkleAirdrop lookalike that appears to originate from the same deploy script
An automated deployment pipeline or test suite invokes the helper function directly outside of run(), producing unintended contract instances that pollute the deployment registry
Impact:
Arbitrary MerkleAirdrop instances can be deployed by anyone using the script as a factory, with no access control on the parameters — a malicious actor deploys a lookalike airdrop contract with a controlled merkle root to phish eligible users into claiming from the wrong contract
The unintended public surface area violates the principle of least privilege — a function that is only ever called from one place inside the same contract should never be externally accessible
Because deployMerkleDropper() is public, it is part of the contract's ABI and can be called directly by any account without going through run(). The caller has full control over both parameters, meaning the deployed instance has no relationship to the intended airdrop configuration:
Change the visibility of deployMerkleDropper() from public to internal. Since the function is only called from run() within the same contract, internal is the correct and sufficient visibility. This removes the function from the ABI entirely, eliminating the external call surface with a one-word change.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.