# Review text content cannot be edited after submission without moderation

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

## Why it matters

An edit route that updates review text without resetting `status` to `'pending'` creates a post-approval backdoor: a user submits a clean review, it passes moderation, then they edit it to inject harmful content that immediately goes live because the approved status is preserved. CWE-284 (Improper Access Control) applies — the user gains a privilege (bypassing moderation) they were not supposed to retain after the initial approval. This also means edit protection is inseparable from `ecommerce-reviews.moderation-trust.moderation-enforced`: if moderation exists, every write path to review content must re-enter it.

## Severity rationale

High because a post-approval edit bypass gives any authenticated user a reliable path to publish arbitrary content to live product pages without moderation.

## Remediation

Either remove edit functionality entirely, or force re-approval on every text edit in `api/reviews/[id]/route.ts`.

```ts
// api/reviews/[id]/route.ts — PATCH handler
export async function PATCH(req: Request, { params }: { params: { id: string } }) {
  const { text } = await req.json()
  const session = await getServerSession()
  if (!session) return Response.json({ error: 'Unauthorized' }, { status: 401 })

  // Verify ownership
  const review = await db.reviews.findUnique({ where: { id: params.id } })
  if (review?.user_id !== session.user.id) return Response.json({ error: 'Forbidden' }, { status: 403 })

  await db.reviews.update({
    where: { id: params.id },
    data: {
      text,
      status: 'pending' // Always re-queue; never preserve 'approved' after content change
    }
  })

  return Response.json({ status: 'pending_review' })
}
```

Any edit pathway that touches `text` or `rating` must include `status: 'pending'` in the same `UPDATE` statement.

## Detection

- **ID:** `edit-protection`
- **Severity:** `high`
- **What to look for:** List all API routes and form components that handle review editing (PUT/PATCH endpoints for reviews, edit buttons in review display). For each edit pathway, classify whether the handler resets status to `pending` after an edit operation. Count edit pathways that bypass moderation.
- **Pass criteria:** Either no edit functionality exists for submitted reviews (no edit routes or UI), or every edit pathway (at least 1 API route and 1 UI trigger) resets the review status to `pending` for re-approval before the edited content becomes publicly visible.
- **Fail criteria:** At least 1 edit pathway allows authors to modify review content that is auto-published without re-entering the moderation queue. Must not pass when an edit route exists that updates `text` without also setting `status = 'pending'`.
- **Skip (N/A) when:** The moderation-enforced check already failed or was skipped — if reviews are not moderated at all, edit protection is moot.
- **Detail on fail:** `"1 edit pathway found (PUT /api/reviews/:id). Handler updates text and rating but does not reset status to pending. Edited reviews bypass moderation."`
- **Remediation:** Either remove edit functionality or require re-approval on edit in `api/reviews/[id]/route.ts`:

  ```ts
  // Option 1: Disable editing
  // Don't create an edit form/route

  // Option 2: Require re-approval on edit
  // POST /api/reviews/:id/edit
  await db.reviews.update({
    where: { id: reviewId },
    data: {
      text: newText,
      status: 'pending' // Re-queue for review
    }
  })
  ```

## External references

- cwe CWE-284

Taxons: data-integrity

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