Approximately 12 US states tax shipping charges; the remaining 38 do not. When shipping is always included in the taxable subtotal — or always excluded with no jurisdiction check — the store either overcharges customers in non-taxing states or under-collects tax in states like New York, Illinois, and Pennsylvania (CWE-682, ISO 25010:2011 functional correctness). The EU VAT Directive 2006/112/EC treats shipping as part of the taxable supply, applying a different rule than most US states. US state shipping taxability rules are jurisdiction-specific and cannot be flattened to a global default. When no code comment documents the shipping tax policy, the decision becomes invisible and unauditble.
High because shipping tax treatment errors produce systematic over- or under-collection across every order that involves a jurisdiction with non-default shipping tax rules, compounding into audit exposure.
Implement jurisdiction-aware shipping tax in lib/tax.ts with a documented configuration object:
// lib/tax.ts
// Source: state revenue authority rulings. Last reviewed: 2024-01.
// US states that tax shipping charges as of 2024:
const STATES_TAXING_SHIPPING = new Set(['NY', 'IL', 'PA', 'WA', 'GA', 'IN', 'TX', 'KS'])
function buildTaxableSubtotal(
items: OrderItem[],
shippingCents: number,
address: Address
): number {
const productSubtotal = items
.filter(i => !i.is_tax_exempt)
.reduce((sum, i) => sum + i.price * i.quantity, 0)
const taxShipping = address.country === 'US'
? STATES_TAXING_SHIPPING.has(address.state)
: true // EU VAT applies to shipping
return productSubtotal + (taxShipping ? shippingCents : 0)
}
Replace any global taxableSubtotal = productSubtotal + shippingCents with this function and add a comment citing the source of the jurisdiction list.
ID: ecommerce-shipping-tax.tax-computation.shipping-tax-handling
Severity: high
What to look for: Before evaluating, quote the tax calculation function that computes the taxable subtotal. Classify whether shipping cost is: (1) always included in the taxable subtotal, (2) always excluded, or (3) conditionally included based on jurisdiction. If conditional, enumerate all jurisdictions that tax shipping and count the total.
Pass criteria: Shipping tax handling is jurisdiction-aware: either shipping is excluded from the taxable subtotal by default with a configurable list of at least 3 states where it is included (e.g., NY, IL, PA), or a tax service API handles shipping tax automatically. A code comment must document the policy.
Fail criteria: Shipping is always included in the taxable subtotal regardless of jurisdiction, or always excluded without any jurisdiction awareness, or no documentation exists for the shipping tax policy.
Skip (N/A) when: Shipping is always free (no shipping cost exists in the calculation) or the business is non-US with VAT applied to the total including shipping by default.
Detail on fail: "Shipping cost of $12.99 always included in taxable subtotal for all 50 states. Shipping is only taxable in ~12 states." or "Shipping excluded from tax calculation globally — no jurisdiction-specific override for NY, IL, PA."
Cross-reference: Related to ecommerce-shipping-tax.regional-compliance.shipping-tax-per-jurisdiction (per-jurisdiction rules) and ecommerce-shipping-tax.tax-computation.jurisdiction-detection (jurisdiction must be detected first).
Remediation: Implement jurisdiction-aware shipping tax in lib/tax.ts:
const STATES_TAXING_SHIPPING = ['NY', 'IL', 'PA'] // example jurisdictions
function calculateTax(items: OrderItem[], shipping: number, address: Address): number {
let taxableSubtotal = items.reduce((sum, item) => {
return sum + (item.is_tax_exempt ? 0 : item.price * item.quantity)
}, 0)
if (STATES_TAXING_SHIPPING.includes(address.state)) {
taxableSubtotal += shipping
}
const rate = getTaxRate(address)
return Math.round(taxableSubtotal * rate)
}