Base price is correctly set and numeric
Why it matters
Price stored as a string type (VARCHAR, TypeScript string) bypasses all numeric comparison operators: sorting by price returns lexicographic order ('9' > '100'), and arithmetic in checkout produces NaN or '$50' + '$10' = '$50$10'. CWE-20 (Improper Input Validation) applies when the schema accepts price values that the business logic cannot safely process. A zero or negative price — even for a free product — creates a Stripe charge for $0 or triggers a refund flow, and no validation to prevent it means a data entry error or API misuse propagates directly to customer receipts and revenue reports.
Severity rationale
Critical because a string-typed or unvalidated price field corrupts sort order, arithmetic, and payment charges — defects that appear in customer invoices and financial reporting.
Remediation
Use Decimal in prisma/schema.prisma (not Float, which has floating-point precision loss, and not String) and enforce price > 0 validation in src/app/api/products/route.ts before every create or update.
model Product {
id String @id @default(cuid())
price Decimal @db.Decimal(10, 2)
}
if (!price || price <= 0) {
return Response.json({ error: 'Price must be greater than 0' }, { status: 400 })
}
For free products, use a separate isFree boolean flag rather than price = 0 — this makes the intent explicit and prevents accidental zero charges.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Catalog & Product Logic Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe · CWE-20 — Improper Input Validation
- iso-25010:2011 · functional-correctness — Functional Correctness (Functional Suitability)
Taxons
History
- 2026-04-18·v1.0.0·Initial import from ecommerce-catalog·automated