# Deadline enforcement for changes

- **Pattern:** `ab-000551` (`booking-flow-lifecycle.lifecycle.deadline-enforcement`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000551
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000551)

## Why it matters

Allowing cancellation or rescheduling up to the moment an event starts undermines the service provider's ability to prepare: a massage therapist who learns of a cancellation 5 minutes before the appointment has no time to fill the slot, collects no revenue, and bears the full cost of the blocked time. CWE-20 applies because the handler accepts a time-based parameter (booking start time) without validating it against a business constraint. CWE-841 applies because the behavioral workflow — "changes require N hours notice" — is defined in business policy but absent from the code. Client-provided timestamps must never be used for the deadline calculation; only server-side `Date.now()` is trustworthy.

## Severity rationale

Medium because missing deadline enforcement causes predictable revenue loss for every last-minute cancellation, and the client cannot be trusted to enforce the policy on their own.

## Remediation

Compute the deadline server-side using the booking's stored `startTime` in your cancel and reschedule handlers (e.g., `src/app/api/bookings/[id]/cancel/route.ts`). Do not accept a client-provided timestamp for this comparison.

```typescript
import { differenceInHours } from 'date-fns';

const hoursUntilEvent = differenceInHours(booking.startTime, new Date());
if (hoursUntilEvent < 24) {
  return res.status(422).json({
    code: 'CANCELLATION_WINDOW_CLOSED',
    message: 'Cancellations require at least 24 hours notice.',
  });
}
```

Apply the same check in the reschedule handler.

## Detection

- **ID:** `deadline-enforcement`
- **Label:** Deadline enforcement for changes
- **Severity:** `medium`
- **What to look for:** Logic checking that the current time is before a cutoff (e.g., `now < booking.startTime - 24 hours`). Count all cancel and reschedule handlers and verify each one includes a time-based deadline check. Look for `differenceInHours`, `Date.now()`, `isBefore`, `subHours`, or manual timestamp arithmetic. Enumerate: "X of Y cancel/reschedule handlers include deadline enforcement."
- **Pass criteria:** Code enforces a minimum notice requirement for cancellations/changes in every cancel and reschedule handler. The cutoff must be at least 1 hour before the booking start time (24 hours is standard). The check must compare the current server time against the booking start time, not a client-provided timestamp. Report: `"X of Y handlers enforce [N]-hour deadline in [file:line]."`
- **Fail criteria:** Users can cancel or reschedule 1 minute before the event, or no deadline check exists in any handler. Do NOT pass when a deadline exists in the cancel handler but not in the reschedule handler (or vice versa) — both must enforce it.
- **Skip (N/A) when:** Business policy explicitly allows last-minute changes with no restrictions (verifiable in a config file, README, or code comment stating the policy).
- **Detail on fail:** `"No time-based restriction found in the cancellation handler. Users can cancel an appointment 1 minute before it starts."`
- **Cross-reference:** The cancellation-state-machine check in this category verifies the cancellation handler where this deadline should be enforced.
- **Cross-reference:** The modification-validation check in this category verifies the reschedule handler where this deadline should also be enforced.
- **Cross-reference:** The refund-logic check in Payment Integration may interact with deadline policy (partial refunds for late cancellations).
- **Remediation:** Add a deadline check in your cancel and reschedule handlers (e.g., `src/app/api/bookings/[id]/cancel/route.ts`).

  ```typescript
  const hoursUntilEvent = differenceInHours(booking.startTime, new Date());
  if (hoursUntilEvent < 24) {
    throw new Error("Cannot cancel within 24 hours of event start");
  }
  ```

## External references

- cwe CWE-20
- cwe CWE-841
- iso-25010 functional-suitability.functional-correctness

Taxons: injection-and-input-trust

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