-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Open
Description
Summary
checkNSignatures(address executor, bytes32 dataHash, bytes signatures, uint256 requiredSignatures) is documented to revert if any signature is invalid and to return normally otherwise.
However, if the target address is not a Safe (or is a proxy pointing elsewhere) and the contract has a permissive fallback() that does not revert, an external staticcall/call:
(bool ok, ) = safe.staticcall(
abi.encodeWithSelector(
ISafe.checkNSignatures.selector,
executor,
dataHash,
signatures,
requiredSignatures
)
);returns ok == true with empty return data — indistinguishable from a genuine, fully‑validated call.
Libraries and integrations therefore cannot tell whether any signature check actually occurred.
Minimal Reproduction
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;
contract NotSafe {
// Accept any call, do nothing and return success
fallback() external payable {}
}
interface ISafe {
function checkNSignatures(
address executor,
bytes32 dataHash,
bytes calldata signatures,
uint256 requiredSignatures
) external view;
}
contract SignatureChecker {
function check(
address maybeSafe,
address executor,
bytes32 dataHash,
bytes calldata signatures,
uint256 requiredSignatures
) external view returns (bool ok) {
// *Always* returns true when maybeSafe is NotSafe
(ok, ) = maybeSafe.staticcall(
abi.encodeWithSelector(
ISafe.checkNSignatures.selector,
executor,
dataHash,
signatures,
requiredSignatures
)
);
}
}- Deploy
NotSafe. - Call
SignatureChecker.check, pointingmaybeSafeto theNotSafeaddress with arbitrary data. - The call returns
trueeven though no signature check occurred.
Expected Behaviour
checkNSignatures SHOULD provide an explicit return value, e.g.
function checkNSignatures(
address executor,
bytes32 dataHash,
bytes calldata signatures,
uint256 requiredSignatures
) external view returns (bool success);Metadata
Metadata
Assignees
Labels
No labels