{"id":"ERC-191","name":"Signed Data Standard","status":"Final","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"authentication","name":"Authentication & Identity","description":"Proving who you are and logging in"},{"id":"reading","name":"Reading & Understanding","description":"Interpreting what you're being asked to do"}],"uxImpact":"ERC-191 defines an envelope for signed data with a version byte and version-specific payload. It prevents a signed message from being parsed as a legacy transaction, but replay resistance and authorization safety still require domain/intent binding and application checks.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-191","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","kind":"proposal","hasDetailedContent":true,"content":{"id":"ERC-191","summary":"ERC-191 defines an envelope for signed data with a version byte and version-specific payload. It prevents a signed message from being parsed as a legacy transaction, but replay resistance and authorization safety still require domain/intent binding and application checks.","applicability":{"whenToUse":["The app uses ERC-191 signed data and can explain the exact action its verifier accepts.","A personal-sign login is bound to the correct origin, account, nonce, and session policy."],"whenToAvoid":["The signature authorizes a transaction, token spend, or structured action that needs a typed-data or transaction-specific review.","The app cannot bind the message to a domain, intent, nonce, or consumption policy.","The wallet cannot render the requested message in a form the user can review."]},"designerTakeaways":["Show the message purpose, origin, and version-specific payload before signing.","Use nonce validation or one-time consumption to reject replay. A deadline limits validity but does not stop reuse before it expires.","Keep personal messages, typed structured data, and token permits visually distinct."],"problemsSolved":[{"problem":"Signed messages could be replayed as transactions","oldWay":"Sign a message, attacker replays it as a transaction draining funds","newWay":"The 0x19 envelope prevents the signed data from being interpreted as a legacy transaction; the app still controls replay policy","impact":"critical"},{"problem":"No standard format for signed data","oldWay":"Each app invented own signing format, security varied wildly","newWay":"The envelope identifies the signing format; reviewers still need to inspect the payload and verifier.","impact":"high"},{"problem":"Can't verify what type of signature it is","oldWay":"Raw signature could be anything, hard to validate","newWay":"Version byte indicates: personal message, typed data, or validator","impact":"high"},{"problem":"Signing requests look the same regardless of purpose","oldWay":"User signs hex blob, no idea if it's login or permission grant","newWay":"Wallets can use the format and decoded payload to explain the request; the version alone does not identify its intent.","impact":"medium"},{"problem":"Cross-protocol signature collision","oldWay":"Signature for App A might be valid for unrelated use in App B","newWay":"Version 0x00 binds data to a validator address; version 0x45 is personal_sign and version 0x01 is structured data","impact":"medium"}],"uxPatterns":[{"name":"Personal Message Signing","description":"Review a personal_sign request in a wallet that renders its payload. Display and threat detection depend on the wallet.","userFlow":["dApp calls personal_sign with message","Wallet shows readable message content","User reads and understands what they're signing","User clicks Sign","Wallet prepends ERC-191 prefix and signs","Signature returned to dApp"]},{"name":"Login Signature","description":"An ERC-4361 sign-in integration layered on ERC-191, with server-side domain, nonce, time, and signature validation.","mockup":"concept/siwe-sign-in","userFlow":["User selects Sign in","App prepares a login-only challenge with domain, nonce, and validity","Wallet shows the requesting origin and challenge","User signs or rejects","Backend validates the complete challenge, consumes the nonce, and creates a session only if valid"]},{"name":"Proof of Ownership","description":"Verify wallet ownership for external systems","userFlow":["External service needs wallet verification","Presents message with context (what, why)","User understands linking purpose","User signs message","Service verifies signature, grants access"]},{"name":"Dangerous Signature Warning","description":"A wallet may add decoding and threat detection. Keep an unknown-risk state when it cannot interpret the authorization.","userFlow":["Wallet receives a signing request","Decode and inspect the payload when supported","Explain detected risks or state that the authorization could not be interpreted","Offer rejection without claiming an undecoded message is safe"]}],"uiComponents":[{"name":"MessageDisplay","description":"Render signed message content","states":["readable","hex","mixed","suspicious"],"props":["message","encoding","maxLength","expanded"]},{"name":"SignatureTypeIndicator","description":"Show what type of signature this is","states":["personal","typed","login","unknown"],"props":["type","version","tooltip"]},{"name":"OriginBadge","description":"Show requesting site with trust level","states":["trusted","unknown","suspicious","known-malicious"],"props":["origin","trustLevel","previousInteractions"]},{"name":"ScopeExplainer","description":"Explain what signature grants and doesn't grant","states":["collapsed","expanded"],"props":["grants[]","doesNotGrant[]","expiresAt"]},{"name":"NonceDisplay","description":"Show the nonce or unique ID and any application timestamp/expiry used for replay handling.","states":["valid","expired","consumed","missing"],"props":["nonce","uniqueId","timestamp","expiresAt","consumed"]}],"antiPatterns":[{"pattern":"Asking users to sign raw hex data","why":"Users can't verify what they're signing, easy to trick them","instead":"Show decoded fields and the requested authorization when the wallet can interpret them. Otherwise explain that the request could not be interpreted and provide a clear rejection path.","severity":"critical"},{"pattern":"Relying on expiry alone for replay protection","why":"An unconsumed signature can be reused until expiry, and some authorizations need a one-time-use check.","instead":"Bind the message to its domain and intent, include a nonce or unique identifier, and record consumption where the application requires it.","severity":"critical"},{"pattern":"Signing messages that look like transaction data","why":"Could be tricking user into signing malicious permit/approval","instead":"Wallet should warn if message looks like encoded function call","severity":"critical"},{"pattern":"Not explaining what signing does vs doesn't do","why":"Users fear any signature might drain their wallet","instead":"Explain the actual verifier, purpose, permissions, assets, and validity of this message. Use login-only reassurance only after verifying that the payload and verifier authorize login alone.","severity":"high"},{"pattern":"Using one visual treatment for login, personal messages, and permits","why":"An ERC-191 signature can authorize an application action, including asset movement. Its encoding does not establish its purpose or safety.","instead":"Use a neutral message treatment for ERC-191 personal signing and a distinct typed-data or permit treatment for spending authorization.","severity":"high"},{"pattern":"Not showing the requesting origin","why":"Phishing sites can pretend to be legitimate","instead":"Always show full URL of requesting site prominently","severity":"high"}],"keyTakeaways":["The ERC-191 envelope distinguishes signed data from legacy transaction encoding.","Show human-readable message content and the requesting origin.","Use domain binding, a nonce or unique ID, and consumed-signature checks where replay matters.","Clearly explain what a personal signature does and does not authorize.","Keep personal messages, typed data, and token permits visually distinct."],"technicalNotes":"ERC-191 encodes 0x19 followed by a version byte and version-specific data. Version 0x00 includes a validator address, 0x01 is structured data as used by EIP-712, and 0x45 is personal_sign with the Ethereum Signed Message prefix. The envelope prevents transaction parsing confusion; applications still need domain binding, nonces, expiration, and consumed-signature checks where replay matters.","lastUpdated":"2026-09-18","sources":[{"label":"ERC-191 official specification","url":"https://ercs.ethereum.org/ERCS/erc-191","type":"official-spec"},{"label":"ERC-4361 sign-in validation requirements","url":"https://ercs.ethereum.org/ERCS/erc-4361","type":"official-spec"}],"lastReviewed":"2026-09-18"},"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-191","type":"official-spec"},{"label":"Discussion search","url":"https://ethereum-magicians.org/search?q=ERC-191","type":"discussion"},{"label":"ERC-4361 sign-in validation requirements","url":"https://ercs.ethereum.org/ERCS/erc-4361","type":"official-spec"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-191","markdown":"https://www.eipsfordesigners.com/standards/ERC-191/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-191/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-191","official":"https://ercs.ethereum.org/ERCS/erc-191","discussion":"https://ethereum-magicians.org/search?q=ERC-191"},"freshness":{"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18"}}