The smart contract contains a Low severity vulnerability where it accepts contributions of 0 SOL without validation, creating unnecessary state bloat and potentially confusing account state
In the contribute() function, there is no validation to ensure that the contribution amount is greater than zero:
pub fn contribute(ctx: Context<FundContribute>, amount: u64) -> Result<()> {
let cpi_context = CpiContext::new(
ctx.accounts.system_program.to_account_info(),
system_program::Transfer {
from: ctx.accounts.contributor.to_account_info(),
to: fund.to_account_info(),
},
);
system_program::transfer(cpi_context, amount)?;
fund.amount_raised += amount;
Ok(())
}
This allows users to create contribution accounts and increment the contribution counter without actually contributing any SOL to the fund.
it("Allows contributions of 0 amount", async () => {
const zeroContribFundName = "Zero Contribution Fund";
const [zeroContribFundPDA] = await PublicKey.findProgramAddress(
[Buffer.from(zeroContribFundName), creator.publicKey.toBuffer()],
program.programId
);
await program.methods
.fundCreate(zeroContribFundName, description, goal)
.accounts({
fund: zeroContribFundPDA,
creator: creator.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
})
.rpc();
const contribDeadline = new anchor.BN(Math.floor(Date.now() / 1000) + 100);
await program.methods
.setDeadline(contribDeadline)
.accounts({
fund: zeroContribFundPDA,
creator: creator.publicKey,
})
.rpc();
const [zeroContribPDA] = await PublicKey.findProgramAddress(
[zeroContribFundPDA.toBuffer(), provider.wallet.publicKey.toBuffer()],
program.programId
);
const balanceBefore = await provider.connection.getBalance(
provider.wallet.publicKey
);
const zeroAmount = new anchor.BN(0);
await program.methods
.contribute(zeroAmount)
.accounts({
fund: zeroContribFundPDA,
contributor: provider.wallet.publicKey,
contribution: zeroContribPDA,
systemProgram: anchor.web3.SystemProgram.programId,
})
.rpc();
const balanceAfter = await provider.connection.getBalance(
provider.wallet.publicKey
);
const fund = await program.account.fund.fetch(zeroContribFundPDA);
const contributionAccount = await program.account.contribution.fetch(
zeroContribPDA
);
reportBug(
"LOW",
"Missing Contribution Amount Validation",
"The contract allows contributions of 0 SOL, which creates unnecessary accounts and state bloat",
`Balance before: ${balanceBefore}, after: ${balanceAfter}\n` +
`Successfully contributed 0 lamports to the fund.\n` +
`Fund amount raised: ${fund.amountRaised.toString()}\n` +
`Created contribution account with PDA: ${zeroContribPDA}\n` +
`This creates unnecessary accounts and state bloat for no actual contribution.`
);
});
========================================
🐛 BUG REPORT [LOW]: Missing Contribution Amount Validation
----------------------------------------
Description: The contract allows contributions of 0 SOL, which creates unnecessary accounts and state bloat
Evidence: Balance before: 499995000, after: 499994000
Successfully contributed 0 lamports to the fund.
Fund amount raised: 0
Created contribution account with PDA: AeLGbKviBFJqFKSbEUmvFQeQRKJiNcZ7uQikXYHQKbHK
This creates unnecessary accounts and state bloat for no actual contribution.
========================================