# Crypto address checksum validation where applicable

- **Pattern:** `ab-001447` (`finserv-form-validation.account-routing.crypto-checksum`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001447
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001447)

## Why it matters

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.

## Severity rationale

Low because checksum-only failures affect a minority of malformed addresses, but any missed typo results in an irreversible fund loss with no recourse.

## Remediation

Add checksum validation for each crypto address type accepted by the application. For Ethereum, implement EIP-55 in `src/lib/validators.ts`.

```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.

## Detection

- **ID:** `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`:**
  ```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;
  }
  ```

---

## External references

- cwe CWE-20
- owasp A03

Taxons: injection-and-input-trust

HTML version: https://auditbuffet.com/patterns/ab-001447
