ERC2771 Explained in Detail
ERC2771 lets a trusted forwarder relay a signed request to a recipient contract. The forwarder verifies the request and appends the original signer address to the end of calldata.
The recipient must use the ERC2771 context, usually _msgSender(), instead of raw msg.sender for user authorization.
Smart contract example
address sender = _msgSender();
When the caller is the trusted forwarder, _msgSender() extracts the original signer.
ERC2771 in Auditing
ERC2771 changes caller identity. A contract that mixes msg.sender and _msgSender() can accidentally grant or deny access.
Auditors treat the trusted forwarder as part of the contract's trust boundary.
Red flags in code
-
Privileged functions still use raw
msg.sender. -
The trusted forwarder can be changed without controls.
-
Untrusted callers can spoof the appended address.
-
Forwarded requests lack nonce, deadline, or EIP-712 domain checks.
-
Calldata length is not checked before reading the final 20 bytes.
How to test or review it
-
Call functions directly and through the forwarder.
-
Try spoofing calldata from an untrusted caller.
-
Replay a forwarded request and expect failure.
-
Test expired requests and wrong target contracts.
-
Review every access-control check for
msg.senderversus_msgSender().