# International shipping rates are configured (if applicable)

- **Pattern:** `ab-001230` (`ecommerce-shipping-tax.regional-compliance.international-shipping`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001230
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001230)

## Why it matters

An address form that accepts 12 countries but routes every order through a domestic shipping rate table charges Canadian customers the same flat US rate as Los Angeles — producing direct financial losses when shipping a package to Toronto for $12 that actually costs $34. The store either absorbs the loss or charges the customer incorrectly. CWE-682 (Incorrect Calculation) applies when a country parameter is accepted by the address form but silently ignored by the shipping calculation. International expansion is invalidated if the first cross-border order ships at a domestic rate.

## Severity rationale

Low because the defect only affects international orders, but within that segment it produces predictable per-order financial losses or customer overcharges that scale with international traffic.

## Remediation

Add a country branch to the shipping calculation in `lib/shipping.ts`:

```ts
// lib/shipping.ts
async function getShippingRate(
  destination: Address,
  method: ShippingMethod,
  items: OrderItem[]
): Promise<number> {
  if (destination.country === 'US') {
    return getDomesticRate(destination.state, method, items)
  }

  // International: delegate to carrier API for live rates
  const shipment = await easypost.shipment.create({
    to_address: {
      country: destination.country,
      city: destination.city,
      zip: destination.zip,
    },
    parcel: {
      weight: items.reduce((sum, i) => sum + i.weight * i.quantity, 0),
    },
  })
  return Number(shipment.rates[0].rate) * 100
}
```

If carrier API integration is out of scope, restrict the address form's country dropdown to domestic only rather than silently applying domestic rates to international addresses.

## Detection

- **ID:** `international-shipping`
- **Severity:** `low`
- **What to look for:** List all countries supported in the shipping address form (country dropdown options or validation). Count the number of distinct international rate configurations vs. domestic-only rates. Check whether the shipping calculation function has a country parameter.
- **Pass criteria:** If the shipping address form accepts at least 2 countries, the shipping rate calculation includes a country parameter and returns different rates for domestic vs. international destinations. At least 1 international shipping rate configuration exists distinct from domestic rates.
- **Fail criteria:** The address form accepts international addresses but the shipping calculation ignores the country field, applying domestic rates to all destinations.
- **Skip (N/A) when:** The shipping address form restricts to a single country (domestic-only), or no country dropdown/field exists and all customers are assumed domestic.
- **Detail on fail:** `"Address form accepts 12 countries but shipping calculation at lib/shipping.ts has no country parameter. All orders use US domestic rates."` or `"Country field exists but rate lookup only has entries for US states."`
- **Remediation:** Add international shipping support in `lib/shipping.ts`:

  ```ts
  function getShippingRates(destination: Address, method: ShippingMethod): number[] {
    if (destination.country === 'US') {
      return DOMESTIC_RATES[destination.state][method]
    } else {
      const shipment = await easypost.shipment.create({
        to_address: { country: destination.country, ... },
        ...
      })
      return shipment.rates.map(r => r.rate)
    }
  }
  ```

## External references

- external iata-dangerous-goods-regulations — https://www.iata.org/en/programs/cargo/dgr/
- cwe CWE-682

Taxons: data-integrity

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