Signature Verification
What is signed or verified diverges from what actually executes — via delegatecall storage overwrite, malleability, or blind signing.
Definition
Signature-verification issues occur when the payload a signer approves is not the payload that executes, or when verification can be bypassed. This includes delegatecall-based storage overwrites in multisigs, signature malleability, missing replay protection, and UIs that induce blind signing of malicious calldata.
How it works
- A signer approves a transaction whose surface meaning differs from its on-chain effect (e.g. a delegatecall that rewrites the multisig's own storage).
- Verification passes because the signatures are valid for the presented payload.
- Execution reinterprets or redirects the approved action — swapping the implementation, changing owners, or moving funds.
Vulnerable vs. fixed
// A signed operation permits delegatecall to an arbitrary address.
// delegatecall runs foreign code in THIS contract's storage context.
(bool ok, ) = to.delegatecall(data); // 'to' can rewrite owners/implementation
require(ok, "call failed");// Restrict delegatecall to a vetted allowlist and prefer plain 'call'.
require(allowlistedDelegate[to], "delegate not allowed");
(bool ok, ) = to.call(data);
require(ok, "call failed");
// Off-chain: decode and display calldata so signers approve what executes.Detection steps
- Identify the sensitive value or permission the pattern can influence.
- Trace every path that can update or consume that value, including callbacks, routers, and privileged helpers.
- Reproduce the worst-case attacker flow with adversarial ordering, manipulated inputs, and maximum feasible capital.
Common signals
- Security depends on an assumption that is not enforced by code.
- A critical value is consumed immediately after an attacker-controlled interaction.
- A privileged call path crosses multiple contracts without one clear authorization boundary.
False positives
- The risky-looking operation is read-only and cannot affect settlement or authorization.
- The value is bounded by independent checks before it moves assets.
- All privileged entry points share the same tested guard and monitoring path.
Review questions
- Which invariant would fail if this input or caller were attacker-controlled?
- Can the attacker compose setup, trigger, settlement, and cleanup atomically?
- What independent check stops the exploit if the first guard is wrong?
Defensive checklist
- Decode and display calldata to signers; never blind-sign opaque payloads.
- Restrict or forbid delegatecall to arbitrary targets in multisig flows.
- Include replay protection (nonce, chainId) and reject malleable signatures.
- Verify the executed effect matches the signed intent, not just signature validity.
Related cases
Related tools
Related glossary
