Same-day cutoff rules that live only in the slot-filter query are display controls, not booking controls. A direct POST to the booking API bypasses the hidden slots entirely. OWASP A03 (Injection) and CWE-20 (Improper Input Validation) apply whenever a server accepts client-supplied timestamps without verifying them against business rules. Without server-side cutoff enforcement, a customer can schedule a same-day appointment that the host has no time to prepare for, or an automated client can flood the schedule with last-minute bookings.
High because the gap between UI slot-filtering and API validation means any direct API caller can book inside the cutoff window, bypassing the host's advance-notice requirement entirely.
Add a cutoff constant and validate it against the request timestamp at the booking API handler, not only when generating the list of available slots.
// src/app/api/book/route.ts
const ADVANCE_BOOKING_HOURS = 24
export async function POST(req: Request) {
const { startTime } = await req.json()
const requested = new Date(startTime)
const earliest = new Date(Date.now() + ADVANCE_BOOKING_HOURS * 3_600_000)
if (requested < earliest) {
return Response.json(
{
error: 'Too soon',
detail: `Bookings require at least ${ADVANCE_BOOKING_HOURS}h notice`,
},
{ status: 400 }
)
}
// ... create booking
}
Co-locate this check with duration and buffer validation so all server-side time boundaries are auditable in one place.
ID: booking-calendar-availability.availability-logic.same-day-cutoff
Severity: high
What to look for: Search for advance booking cutoff configuration (e.g., ADVANCE_BOOKING_HOURS = 24, MIN_NOTICE_HOURS, cutoffHours). Count all booking creation API endpoints. For each, verify the server compares the requested time against now + cutoff and rejects requests that violate the rule. Check if this validation is in the API route handler or only in the calendar UI filter. Examine files matching src/app/api/book*/route.ts, src/app/api/appointment*/route.ts, src/lib/*booking*, src/lib/*config*.
Pass criteria: Count all booking API endpoints. At least 1 advance booking cutoff constant must be defined server-side (e.g., ADVANCE_BOOKING_HOURS). 100% of booking creation endpoints must compare requestedTime against now + cutoffHours and return HTTP 400/409 when violated. Report: "Cutoff hours: [value]. X of Y endpoints enforce server-side."
Fail criteria: Cutoff is only applied when filtering available slots for display, not when validating a booking request. Or no cutoff constant exists in server-side code.
Skip (N/A) when: Platform explicitly does not enforce advance booking cutoffs (accepts last-minute bookings by design).
Detail on fail: Example: "Calendar hides same-day slots, but API does not check. A direct POST with a same-day time succeeds."
Cross-reference: Check duration-validation — cutoff and duration validations should be co-located in the same API middleware.
Cross-reference: Check advance-booking-limits — same-day cutoff guards the near end; advance limits guard the far end.
Cross-reference: Check past-date-protection — client-side past-date guard complements server-side cutoff validation.
Remediation: Validate cutoff server-side:
// pages/api/appointments.ts
const ADVANCE_BOOKING_HOURS = 24
export async function POST(req: Request) {
const { startTime } = await req.json()
const now = new Date()
const requestedTime = new Date(startTime)
const minimumAllowedTime = new Date(
now.getTime() + ADVANCE_BOOKING_HOURS * 60 * 60 * 1000
)
if (requestedTime < minimumAllowedTime) {
return Response.json(
{
error: 'Too late to book',
detail: `Bookings must be made at least ${ADVANCE_BOOKING_HOURS} hours in advance`,
},
{ status: 400 }
)
}
// ... create booking
}