Advance booking limits enforced server-side with a structured error response
Why it matters
Advance booking limits that exist only as a UI filter are not limits at all. A direct POST to the booking API skips the date picker entirely. OWASP A03 (Injection) and CWE-20 (Improper Input Validation) apply to any business rule that can be bypassed by sending a raw HTTP request. Without a server-side ceiling, a misbehaving client can book a slot 5 years in the future, creating junk data in the schedule, blocking the resource for phantom appointments, and polluting analytics.
Severity rationale
Low because far-future junk bookings are annoying and pollute analytics but do not expose sensitive data or create immediate revenue loss, making it lower urgency than buffer or duration violations.
Remediation
Define MAX_ADVANCE_DAYS as a server-side constant and validate it in the booking API handler. The check belongs next to duration and cutoff validation so all time-boundary rules are visible in one file.
// src/app/api/book/route.ts
const MAX_ADVANCE_DAYS = 90
export async function POST(req: Request) {
const { startTime } = await req.json()
const requested = new Date(startTime)
const ceiling = new Date(Date.now() + MAX_ADVANCE_DAYS * 86_400_000)
if (requested > ceiling) {
return Response.json(
{
error: 'Booking too far in advance',
detail: `Bookings cannot exceed ${MAX_ADVANCE_DAYS} days from today`,
},
{ status: 400 }
)
}
// ... create booking
}
Detection
-
ID:
advance-booking-limits -
Severity:
low -
What to look for: Search for max advance booking configuration (e.g.,
MAX_ADVANCE_DAYS = 90,maxBookingDays,advanceLimitDays). Count all booking creation API endpoints. For each, verify the server compares the requested time againstnow + maxAdvanceDaysand rejects requests that exceed the limit with a structured JSON error (HTTP 400). Examine files matchingsrc/app/api/book*/route.ts,src/app/api/appointment*/route.ts,src/lib/*config*,src/lib/*booking*. -
Pass criteria: Count all booking API endpoints. At least 1 max advance booking constant must be defined server-side (e.g.,
MAX_ADVANCE_DAYS). 100% of booking creation endpoints must comparerequestedTimeagainstnow + maxAdvanceDaysand return HTTP 400 with a structured JSON error when exceeded. Report: "Max advance days: [value]. X of Y endpoints enforce server-side." -
Fail criteria: Max advance limit is only applied when filtering available slots for display, not when validating a booking request. Or no advance limit constant exists in server-side code.
-
Skip (N/A) when: Platform explicitly does not enforce max advance booking limits (allows booking arbitrarily far in the future by design).
-
Detail on fail: Example:
"Calendar hides slots beyond 90 days, but API does not check. A direct POST with a date 120 days in the future succeeds." -
Cross-reference: Check
same-day-cutoff— advance limits guard the far end; cutoff guards the near end. Both should be in the same validation layer. -
Cross-reference: Check
duration-validation— all booking time boundaries (duration, cutoff, advance) should be validated together. -
Cross-reference: Check
buffer-enforcement— advance limits and buffer time are both server-side time validations. -
Remediation: Validate max advance booking server-side:
// pages/api/appointments.ts const MAX_ADVANCE_DAYS = 90 export async function POST(req: Request) { const { startTime } = await req.json() const now = new Date() const requestedTime = new Date(startTime) const maxAllowedTime = new Date( now.getTime() + MAX_ADVANCE_DAYS * 24 * 60 * 60 * 1000 ) if (requestedTime > maxAllowedTime) { return Response.json( { error: 'Booking too far in advance', detail: `Bookings cannot be made more than ${MAX_ADVANCE_DAYS} days in advance`, }, { status: 400 } ) } // ... create booking }
External references
- cwe · CWE-20 — Improper Input Validation — advance booking limit not enforced server-side
- owasp:2021 · A03 — Injection — advance booking constraints bypassed via direct API call
Taxons
History
- 2026-04-18·v1.0.0·Initial import from booking-calendar-availability·automated