# Verified purchase badge distinguishes buyer reviews from non-buyer reviews

- **Pattern:** `ab-001213` (`ecommerce-reviews.moderation-trust.verified-purchase`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001213
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001213)

## Why it matters

The FTC Endorsement Guides (revised 2023) explicitly require that "Verified Purchase" or equivalent indicators be truthful — displaying the badge for reviews from non-buyers is a deceptive endorsement. Beyond legal risk, unverified reviews mixed into the same display as genuine buyer reviews dilute trust: a product with 100% "Verified Purchase" badges where the badge is just hardcoded to `true` will have the label completely reverse-fired when a single fraudulent review is exposed publicly. The `verified_purchase` check must reach into order history at submission time to have any meaning; a database field alone without that query is cosmetic.

## Severity rationale

Medium because a hardcoded or query-free verified-purchase badge violates FTC endorsement guidelines and misleads shoppers without allowing unauthorized data access.

## Remediation

Check order history at review submission time in `api/reviews/submit` and expose the badge in `components/ReviewItem.tsx`.

```sql
ALTER TABLE reviews ADD COLUMN verified_purchase BOOLEAN NOT NULL DEFAULT FALSE;
```

```ts
// api/reviews/submit
const purchase = await db.orders.findFirst({
  where: { user_id: userId, product_id: productId, status: 'completed' }
})

await db.reviews.create({
  data: {
    verified_purchase: purchase !== null,
    // ...
  }
})
```

```tsx
// components/ReviewItem.tsx
{review.verified_purchase && (
  <span className="badge-verified" aria-label="Verified Purchase">
    ✓ Verified Purchase
  </span>
)}
```

Never set `verified_purchase: true` on insert without the order lookup — the badge only has legal standing if it reflects an actual completed transaction.

## Detection

- **ID:** `verified-purchase`
- **Severity:** `medium`
- **What to look for:** Count the number of verification layers: (1) `verified_purchase` boolean field in the reviews database schema, (2) logic in the review submission handler that queries order history to set the flag, (3) visual badge/indicator in the review display component that distinguishes verified from unverified reviews. Report: X of 3 verification layers present.
- **Pass criteria:** At least 2 of 3 verification layers are implemented: the database has a `verified_purchase` field, the submission handler checks order history to set it, and the display component shows a visible "Verified Purchase" badge or distinguishing indicator for reviews from actual buyers.
- **Fail criteria:** Fewer than 2 of 3 verification layers exist, or all reviews display "Verified Purchase" regardless of actual purchase history (hardcoded badge).
- **Skip (N/A) when:** The project has no order/purchase system or no auth system (cannot correlate users to purchases).
- **Detail on fail:** `"1 of 3 verification layers found (database field exists). Submission handler does not check order history. Display has no visual badge."` or `"All reviews render 'Verified Purchase' badge — field is hardcoded to true on insert without checking orders."`
- **Remediation:** Add purchase verification in `api/reviews/submit` and display the badge in `components/ReviewItem.tsx`:

  ```sql
  ALTER TABLE reviews ADD COLUMN verified_purchase BOOLEAN DEFAULT FALSE;
  ```

  ```ts
  // On review submission, check if user purchased the product
  const purchase = await db.orders.findFirst({
    where: {
      user_id: userId,
      product_id: productId,
      status: 'completed'
    }
  })

  const review = await db.reviews.create({
    data: {
      verified_purchase: !!purchase,
      // ...
    }
  })

  // Display component
  {review.verified_purchase && <span className="badge">✓ Verified Purchase</span>}
  ```

## External references

- external ftc-endorsement-guides-verified-purchase — https://www.ecfr.gov/current/title-16/chapter-I/subchapter-B/part-255

Taxons: data-integrity, content-integrity

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