{"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"}],"uxImpact":"ERC-191 prefixes signed data with version-specific envelopes to prevent legacy-transaction parsing. It does not provide general replay or authorization safety; bind domain/intent and use nonce/consumption checks in the application, with visual separation from permits and typed data.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-191","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","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":["Your product addresses: signed messages could be replayed as transactions.","Your product addresses: no standard format for signed data.","The 0x19 envelope helps keep signed data from being parsed as a legacy transaction; replay and authorization still need application checks.","You are designing a personal message signing experience with visible states and recovery paths."],"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":"Standard prefix + version byte = consistent, auditable signing","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":"Different prefixes enable different wallet UI treatments","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":"Standard wallet UI for human-readable message signing","mockup":"concept/verify-safety","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":"Sign-in authentication flow","mockup":"concept/siwe-sign-in","userFlow":["User clicks \"Connect\" or \"Sign In\"","Wallet explains what signature does and doesn't do","User understands this is just authentication","User signs","Backend verifies signature, creates session"]},{"name":"Proof of Ownership","description":"Verify wallet ownership for external systems","mockup":"concept/verify-safety","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":"Wallet warns about suspicious signing requests","mockup":"concept/verify-safety","userFlow":["Suspicious site requests signature","Wallet detects non-readable content","Shows warning about potential attack","User encouraged to reject","If user proceeds, extra confirmation required"]}],"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":"Always show human-readable message with clear purpose","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":"Clearly state \"This will NOT approve transactions or spend funds\"","severity":"high"},{"pattern":"Using one visual treatment for login, personal messages, and permits","why":"ERC-191 envelopes do not make a personal signature a token allowance or transaction authorization.","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"}],"lastReviewed":"2026-09-18"},"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-191","type":"official-spec"},{"label":"Discussion","url":"https://ethereum-magicians.org/search?q=ERC-191","type":"discussion"},{"label":"ERC-191 official specification","url":"https://ercs.ethereum.org/ERCS/erc-191","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"}}