SNARKeling Treasure Hunt

First Flight #59
Beginner FriendlyGameFiFoundry
100 EXP
View results
Submission Details
Severity: low
Valid

updateVerifier() Does Not Validate New Verifier Address Can Be Set to address(0)

Root + Impact

Description

  • The constructor correctly validates if (_verifier == address(0)) revert InvalidVerifier().

  • updateVerifier(), which replaces the verifier at runtime, performs no such check, allowing the owner to accidentally (or maliciously, post-key-compromise) set the verifier to address(0) or any non-contract address.

function updateVerifier(IVerifier newVerifier) external {
require(paused, "THE_CONTRACT_MUST_BE_PAUSED");
require(msg.sender == owner, "ONLY_OWNER_CAN_UPDATE_VERIFIER");
// @> No zero-address or code-size check on newVerifier
verifier = newVerifier;
emit VerifierUpdated(address(newVerifier));
}

Risk

Likelihood:

  • Requires a compromised or negligent owner key unlikely but non-zero.

Impact:

  • Setting verifier = address(0) causes verifier.verify(...) to revert on all future claim() calls, permanently bricking the hunt without a recovery path while the contract still holds funds.

  • Even if caught quickly, the contract must be unpaused → re-paused → verifier updated, during which time the hunt is halted.

Proof of Concept

function updateVerifier(IVerifier newVerifier) external {
require(paused, "THE_CONTRACT_MUST_BE_PAUSED");
require(msg.sender == owner, "ONLY_OWNER_CAN_UPDATE_VERIFIER");
// @> No zero-address or code-size check on newVerifier
verifier = newVerifier;
emit VerifierUpdated(address(newVerifier));
}

Recommended Mitigation

Mirror the constructor's validation in updateVerifier():

function updateVerifier(IVerifier newVerifier) external {
require(paused, "THE_CONTRACT_MUST_BE_PAUSED");
require(msg.sender == owner, "ONLY_OWNER_CAN_UPDATE_VERIFIER");
if (address(newVerifier) == address(0)) revert InvalidVerifier();
// Optional: verify new address has deployed code
uint256 size;
assembly { size := extcodesize(newVerifier) }
require(size > 0, "VERIFIER_NOT_A_CONTRACT");
verifier = newVerifier;
emit VerifierUpdated(address(newVerifier));
}
Updates

Lead Judging Commences

s3mvl4d Lead Judge 18 days ago
Submission Judgement Published
Validated
Assigned finding tags:

no zero-address check in updateVerifier()

The issue is that `updateVerifier()` allows the owner to replace the verifier with an arbitrary address, including `address(0)`, even though the constructor explicitly treats a zero verifier as invalid and reverts with `InvalidVerifier()` during initial deployment. In other words, the contract establishes at deployment time that a null verifier address is not an acceptable configuration, but then fails to preserve that same invariant when the verifier is later updated through the admin recovery path.

Support

FAQs

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

Give us feedback!