Puppy Raffle

AI First Flight #1
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: low
Likelihood: medium
Invalid

I-01: Admin foot-guns when setting ownership or fee addresses

Root + Impact

Description

  • Normal behavior: Administrative configuration should prevent accidental misconfiguration and make access control expectations explicit.

  • Specific issue: changeFeeAddress() accepts any address with no non-zero validation. withdrawFees() is callable by anyone, which may be unintended and can surprise operators.

@> changeFeeAddress(): PuppyRaffle.sol:L167-L169 (no validation)
167: function changeFeeAddress(address newFeeAddress) external onlyOwner {
@>168: feeAddress = newFeeAddress;
169: emit FeeAddressChanged(newFeeAddress);
@> withdrawFees(): PuppyRaffle.sol:L156-L163 (permissionless fee withdrawal trigger)
@>156: function withdrawFees() external {
@>161: (bool success,) = feeAddress.call{value: feesToWithdraw}("");

Risk

Likelihood:

  • Reason 1 Missing validation on feeAddress updates can lead to broken fee collection paths.

  • Reason 2 Permissionless triggering of fee withdrawals can be unexpected in operational monitoring.

Impact:

  • Impact 1 When this will occur: During ongoing protocol operations when fee addresses are updated and fees are withdrawn.

  • Impact 2 Fees can become stuck or withdrawals can fail due to invalid feeAddress configuration.

  • Impact 3 Unexpected third-party triggers can complicate operations/monitoring even if funds still go to feeAddress.

Proof of Concept

Misconfiguration foot-gun:
@> PuppyRaffle.sol:L168 allows feeAddress = address(0) (no require).
Steps:
1) Owner calls changeFeeAddress(address(0)).
2) withdrawFees() attempts to call address(0) at L161, causing failure or lost operational path.
Operational foot-gun (access expectations):
@> PuppyRaffle.sol:L156 withdrawFees() is external without onlyOwner.
Any caller can trigger the fee withdrawal to feeAddress at L161 when the balance condition at L158 h

Recommended Mitigation

• Add require(newFeeAddress != address(0)) in changeFeeAddress().
• Restrict withdrawFees() to onlyOwner (or document the permissionless design explicitly).
• Emit withdrawal events and consider a two-step change for feeAddress.
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 12 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!