Signature-related Attacks¶
Signatures serve critical functions in smart contract systems. The EVM exposes the ecrecover precompile for native signature validity checks and recovery, which underpins authorization, data validity checks, and gas-less transactions. Signature systems malfunction in a number of distinct ways, and the consequences are usually severe.
Missing Validation¶
The most common vulnerability is missing validation of the address ecrecover returns on error.
1 2 3 4 5 | |
The check for address(0) is absent, which lets an attacker submit invalid signatures carrying arbitrary payloads and have them pass as valid. A single guard closes the gap:
1 | |
OpenZeppelin's ECDSA library is the better option, since it reverts on invalid signatures automatically.
Replay Attacks¶
Replay attacks occur where a signature and the system consuming it share no deduplication mechanism, typically because signatures are never invalidated or because the system carries no nonce. The following examples work through the attack angles on a signature system and its successive iterations.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
An attacker in possession of the owner's signature performs the same action repeatedly. Where the owner signed a transfer of funds, replaying the signature drains the contract. A mapping that invalidates each submitted signature after its first execution fixes the immediate problem, and a nonce encoded into the signed payload restores the owner's ability to authorize the same action more than once. Changing the final signature while the payload data stays the same is the nonce's only purpose.
The following code adds both the invalidation mechanism and the nonce-related business logic:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
Even the enhanced contract is not secure. Deployment on multiple chains, or reuse of the signer address in other contexts on different chains, leaves signature replay open.
Cross-chain Replay Attacks¶
Cross-chain replay attacks arise where signatures are reusable across different blockchain systems. A signature already used and invalidated on one chain is copied to another and triggers an unwanted state change there, which puts every smart contract system deployed with identical code across chains at risk.
Encoding the chain ID in the signature payload and validating it against the current chain closes the gap:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
Signatures over EIP712 typed data payloads already carry the chain ID inside the domain separator value.
Frontrunning¶
Attackers monitor the mempool for transactions carrying ECDSA signatures, particularly in systems that pay a reward to third parties for executing a payload. Depending on what the signature payload covers, an attacker frontruns the original transaction, manipulates the parameters it left out, and exploits the system.
Applied to the example above, a signature becomes vulnerable to frontrunning once the hash is calculated like this:
1 2 | |
With param1 missing, a frontrunning attacker sets its value arbitrarily. Every parameter participating in the business logic that the signature triggers belongs inside the signed payload.
Signature Malleability¶
Signature malleability is a characteristic of digital signatures. An ECDSA signature on Ethereum consists of two 32-byte values, r and s, plus a one-byte recovery value v. The symmetric structure of elliptic curves means no signature is unique, so a malleable signature is alterable without being invalidated.
For every parameter set {r, s, v} behind a signature, a distinct set {r', s', v'} produces an equivalent one. A smart contract system calling ecrecover directly rather than through a well-known library such as OpenZeppelin's ECDSA therefore has to detect and discard malleable signatures itself.
OpenZeppelin's ECDSA library carries the following code to prevent forged signatures:
1 2 3 | |
The check stops malleability attacks, because signatures from current libraries carry an s-value in the lower half order and are therefore unique. No signature validation library is complete without it.
EIP-2098 Compact Signatures¶
The ECDSA.recover and ECDSA.tryRecover methods are susceptible to a specific form of malleability, because they process both EIP-2098 compact signatures and the conventional 65-byte format. The problem is confined to the overloads accepting a single bytes argument and does not reach those taking {r, v, s} or {r, vs} as separate arguments.
Affected contracts are those implementing signature reuse or replay protection by marking the signature itself as used rather than the signed message. A user takes an already submitted signature, resubmits it in the compact format, and circumvents the protection.
The issue affects OpenZeppelin contracts in versions before 4.7.3. The related security advisory covers the details.