Skip to content

fix(address): getAddress() returns a malformed 41-nibble address for over-length ICAP input#5154

Open
sravan27 wants to merge 1 commit into
ethers-io:mainfrom
sravan27:fix-getaddress-icap-overflow
Open

fix(address): getAddress() returns a malformed 41-nibble address for over-length ICAP input#5154
sravan27 wants to merge 1 commit into
ethers-io:mainfrom
sravan27:fix-getaddress-icap-overflow

Conversation

@sravan27

Copy link
Copy Markdown

Bug

getAddress() returns a malformed 41-nibble string for an over-length ICAP address — a value it itself rejects.

const { getAddress, isAddress } = require("ethers");
// crafted ICAP whose base36 body decodes to >= 2**160 (passes the IBAN checksum)
const out = getAddress("XE54" + "Z".repeat(31));
// => "0x1343093195196b9fCCa7C68CE3fFFfffFffFFffff"  (41 hex nibbles, 20.5 bytes)
isAddress(out);    // false
getAddress(out);   // throws "invalid address"

getAddress is documented to return a normalized, checksummed 20-byte address or throw. Here it returns a 41-nibble value that fails isAddress() and that getAddress() rejects on the next call — a contract violation an app would propagate downstream (display, comparison, RPC).

Cause

src.ts/address/address.ts, ICAP branch:

let result = fromBase36(address.substring(4)).toString(16);
while (result.length < 40) { result = "0" + result; }   // only left-pads to >= 40
return getChecksumAddress("0x" + result);

The regex /^XE[0-9]{2}[0-9A-Za-z]{30,31}$/ permits a 31-char base36 body, and 36**31 > 2**160, so result can be 41 nibbles. The normalization only enforces a 40-nibble minimum, never a maximum.

Fix

Assert the decoded result is exactly 40 nibbles (i.e. value < 2**160); reject otherwise:

while (result.length < 40) { result = "0" + result; }
assertArgument(result.length === 40, "invalid icap address", "address", address);
return getChecksumAddress("0x" + result);

Verified: "Z".repeat(31) body (value ≥ 2^160) now throws invalid address; valid ≤30-char bodies and in-range 31-char bodies are unaffected (still pad to exactly 40 and checksum normally).

getAddress() left-padded the base36 ICAP body to >=40 nibbles but never
capped at 40, so an over-length body returned a malformed 41-nibble
string that isAddress() rejects and getAddress() itself throws on.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant