Ethereum EIP-55 mixed-case checksum and Bitcoin Base58Check both exist to catch single-character typos that would otherwise route funds to a valid-looking but incorrect address. A format-only regex (/^0x[0-9a-fA-F]{40}$/) accepts thousands of invalid checksummed Ethereum addresses — funds sent to those addresses are irreversibly lost. OWASP A03 applies: crypto wallet addresses are untrusted user input that requires structural validation, not just length checks.
Low because checksum-only failures affect a minority of malformed addresses, but any missed typo results in an irreversible fund loss with no recourse.
Add checksum validation for each crypto address type accepted by the application. For Ethereum, implement EIP-55 in src/lib/validators.ts.
// src/lib/validators.ts (Ethereum EIP-55)
export function isValidEthAddress(address: string): boolean {
if (!/^0x[0-9a-fA-F]{40}$/.test(address)) return false;
// All-lowercase or all-uppercase passes (no checksum to verify)
const stripped = address.slice(2);
if (stripped === stripped.toLowerCase() || stripped === stripped.toUpperCase()) return true;
const hash = keccak256(stripped.toLowerCase());
return stripped.split('').every((c, i) =>
parseInt(hash[i], 16) >= 8 ? c === c.toUpperCase() : c === c.toLowerCase()
);
}
Apply as a Zod .refine() in src/lib/schemas.ts and validate server-side in the relevant API route.
ID: finserv-form-validation.account-routing.crypto-checksum
Severity: low
What to look for: List all crypto wallet address input fields. For each, classify whether validation includes the proper checksum algorithm (EIP-55 for Ethereum, Base58Check for Bitcoin) or only checks format/length. Quote the validation expression found. Report: "X of Y crypto address inputs have checksum validation."
Pass criteria: At least 100% of crypto address inputs validate using the appropriate checksum algorithm server-side. No more than 0 inputs rely on length-only checks. Report even on pass: "X crypto address fields with full checksum validation."
Fail criteria: Any crypto address input accepts values without checksum verification, or validation is only client-side.
Skip (N/A) when: The project does not accept cryptocurrency payments (0 crypto address fields found after searching src/, app/, components/ for wallet, address, ethereum, bitcoin patterns).
Detail on fail: Example: "Ethereum addresses accepted without EIP-55 checksum validation. Typos in address case would not be caught." or "Bitcoin address accepted with only regex format check; no version byte checksum validation"
Cross-reference: The account-format-validation check covers traditional banking account formats; this check covers blockchain-specific address validation.
Remediation: Validate crypto addresses with proper checksums in src/lib/validators.ts:
Ethereum EIP-55 in src/lib/validators.ts:
function isValidEthereumAddress(address) {
if (!/^0x[0-9a-fA-F]{40}$/.test(address)) return false;
if (address === address.toLowerCase() || address === address.toUpperCase()) {
return true;
}
const hash = keccak256(address.toLowerCase().slice(2));
for (let i = 0; i < 40; i++) {
const char = address[i + 2];
const hashByte = parseInt(hash[i], 16);
if (hashByte >= 8 && char !== char.toUpperCase()) return false;
if (hashByte < 8 && char !== char.toLowerCase()) return false;
}
return true;
}