Skip to content

Connection security

EIP-712 signatures: check the permission behind the fields

Decode a fictional typed-data receipt, check its nonce and deadline timeline, and use a worksheet to identify what a signature can authorize.

Folded ivory paper passes through a ceramic inspection ring with a lime wedge on a dark surface.
Illustration for connection security; examples in this article are educational.

EIP-712 lets a wallet display structured fields before you sign, but readable data is not proof that the request is safe. Check the signing domain, chain, verifying contract, message fields and replay rules against the action you intended. The application that accepts the signature determines what it can authorize.

Read the request as a proposed authorization

A page says “verify your wallet.” The wallet then displays a neatly labeled message. Before signing, translate that request into a sentence: this account authorizes this action, under these conditions, for this application. If the fields cannot support that sentence, the page's explanation has left a gap.

EIP-712 defines how to hash and sign typed structured data with a signing domain. A request normally presents types, the field definitions; primaryType, the main structure; domain, its signing context; and message, the values. The standard does not define every application's authorization policy or provide automatic replay protection.

In MetaMask, eth_signTypedData_v4 is the documented method for this structured signing flow. Its documentation treats the domain name, main type name and field names as a security interface because they appear in the confirmation. Those are useful reading aids, but the names themselves are supplied by the application. See MetaMask's signing guidance.

Read the whole structure, including nested objects and arrays. A friendly title cannot explain an unfamiliar recipient, a large permission amount or an opaque nested operation. If the wallet cannot expose the material fields, obtain a trustworthy decoding before deciding whether to proceed.

Decode a harmless receipt request

Consider an original, fictional request for an isolated practice application. It only acknowledges receipt of report 84. There are no assets, token permissions or trading functions in this example. The addresses are invented placeholders; no contract is deployed and no usable signature is supplied.

The practice domain contains these fields. Their types are part of types.EIP712Domain.

Domain field and typeFictional valueWhat to compare
name, stringPracticeReceiptExpected application name
version, string1Expected signing format version
chainId, uint25631337The exercise's chosen local chain identifier
verifyingContract, address0x1111111111111111111111111111111111111111The exercise's expected verifier

The primaryType is Receipt. Its ordered field definitions and message values are:

Message fieldTypeFictional value
readeraddress0x2222222222222222222222222222222222222222
reportIduint25684
purposestringreceipt-only
nonceuint2567
deadlineuint2561793189100

For this exercise, the deadline means 28 October 2026 at 12:05:00 UTC, expressed as Unix seconds. The nonce is the practice application's sequence number for this reader. It is unrelated to the reader's ordinary Ethereum transaction nonce.

The intended sentence is now specific: the reader acknowledges report 84 to this practice verifier on this local chain, once, no later than 12:05 UTC. That interpretation still needs an acceptance rule. A field named purpose does not prevent a badly designed application from using the signature for something else.

The example is harmless because of the stated application's behavior, not because the message happens to omit a token amount. This is the same boundary examined in AI tool least privilege: an understandable request still needs a component that enforces its scope.

Separate the website from the signing domain

The signing domain is not a browser hostname. Its name is not a certificate that the requester owns a particular website. Compare the website you deliberately opened with the protocol's authoritative deployment information, then compare the requested chain and full verifier address with that information.

EIP-712 permits applications to include the domain fields relevant to their design; not every valid domain includes every possible field. The specification defines chainId as the chain identifier and verifyingContract as the contract checking the signature. See the domain separator definition. An absent field therefore needs a protocol-specific explanation, rather than an assumption that the wallet silently filled it in.

For an ordinary single-chain contract action, an unexplained missing chain or verifier leaves the intended scope unresolved. Conversely, the presence of both does not prove the contract is trustworthy. It tells you which context to investigate.

Where supported, a read-only domain query can add evidence. OpenZeppelin's EIP712 implementation exposes eip712Domain() to return the fields used by its domain separator. Its helper still leaves type-specific message encoding to the protocol. That is documented library behavior, not evidence that an arbitrary deployed verifier uses it correctly.

Test replay scope with an explicit state rule

For the fictional receipt, define the verifier's rule before checking the timeline. It accepts only the expected domain, a valid signature from reader, report 84, the receipt-only purpose, the reader's current nonce and a verification time no later than the deadline. Acceptance records one receipt and advances the nonce atomically. A rejected attempt changes neither value.

These are teaching assumptions, not properties inherited from the EIP-712 label. The exercise models the signature-validity result; it does not implement cryptography.

Start at 12:00 UTC with next nonce 7 and zero receipts. The request above has a five-minute window: 1793189100 − 1793188800 = 300 seconds.

UTC timeFictional eventNext nonce afterwardReceipts afterwardResult
12:00Reader signs the request; nobody submits it70No application state change
12:03Valid request with nonce 7 reaches the expected verifier81Accepted
12:04The same signed request is submitted again81Rejected: nonce 7 is stale
12:06A separate unused request has nonce 8 but the same deadline81Rejected: deadline passed

The sequence contains three submissions, one acceptance and two rejections. The accepted request arrives 180 seconds after the start, leaving 120 seconds before its deadline. The last request is 60 seconds late. Signing and accepting are separate events.

Check boundary cases independently from that sequence. With a fresh initial snapshot, verification exactly at 12:05:00 passes the exercise's inclusive deadline rule; 12:05:01 fails. A different chainId or verifyingContract value must fail the expected-domain comparison. These independent tests do not add receipts to the main timeline.

These checks compare field values and stored state. In a separate hypothetical copy of the practice verifier with identical domain values and its nonce reset to 7, the same unexpired signature could be accepted again. Domain fields cannot distinguish two environments that reuse those fields. Nonce state must also remain intact for the one-use rule to hold.

A nonce written into a message is insufficient unless the verifier checks and consumes the corresponding state. Likewise, a deadline needs a defined unit, clock and comparison. EIP-712 explicitly leaves repeated-message handling to applications, which may reject repetition or make the repeated action idempotent. See its replay considerations.

Check the effect, not just the readable fields

The fictional receipt ends at acknowledgement. Real typed data can have very different effects. ERC-2612, for example, uses a structured signature to authorize a token allowance update. Its signed fields include an owner, spender, value, nonce and deadline, and any caller can submit a valid permit. Those details belong to that specific permit standard, not every EIP-712 message.

In that design, the domain's verifier is the token contract, while spender identifies the address receiving allowance. Checking the verifier alone therefore misses another address that determines the permission.

If the request concerns spending, use the permit versus approval guide to follow that authorization into contract state. Also inspect the existing token allowance worksheet for the token, spender and remaining permission. A readable amount needs the correct asset units before it becomes an understandable limit.

Watch for these practical failures:

  • Familiar name, unexpected verifier. A copied protocol name can make a substituted address easy to overlook. Use the deployment record to resolve the full address.
  • Short submission window, lasting permission. A deadline may govern when a signature can be accepted. Do not infer that every resulting permission expires at the same moment; check the specific contract's resulting state.
  • One visible action, nested instructions. An array or opaque bytes field can leave the important effects unexplained. A short wallet summary is incomplete evidence when those contents remain undecoded.
  • Unexpected signing request. Connecting an account, authenticating to a site and granting spending authority need different explanations. The wallet connection versus approval guide separates those permission layers.

Use a before-signing worksheet

Complete this worksheet from the request and independent application evidence. “The wallet displayed no warning” does not fill an empty evidence cell.

CheckEvidence to retainStop condition
Intended taskPlain sentence describing the requested actionPage explanation and fields disagree
SignerExpected account and any account-specific restrictionsWrong account or unexplained signer role
DomainName, version, chain and full verifier; source used to check themUnexplained deployment or domain mismatch
MessageMain type, nested fields, recipients, amounts and units where relevantImportant contents cannot be interpreted
ReuseNonce scope, acceptance rule and current state where availableRepeated use or invalidation behavior is unknown
Time and effectDeadline interpretation, resulting authority and cancellation routeExpiry is being assumed to cancel a continuing permission

Retain a minimal review record and the decision, rather than pasting a usable signature into a support chat or ordinary logs. A signature is not the private key, but an unconsumed authorization may still be usable. The log redaction guide explains preserving evidence while excluding authentication material.

If a request remains unclear, reject it and return to the intended task through a verified application route. If it has already been signed, determine whether it was accepted, remains usable, expired or can be invalidated under that protocol. Those are separate states. The practical completion record is a permission sentence whose domain, effect and reuse conditions you can explain from evidence.

Keep the context with the example.

Each worked example is illustrative, with its sources and assumptions in the article. Read our editorial standards for authorship, verification and corrections.