Both availability creation paths accept arbitrary start_dt / end_dt strings:
AvailabilityEndpoint::create() (src/Availability/AvailabilityEndpoint.php) — REST, sanitize_text_field only
AvailabilityController::addSlot() (src/Availability/AvailabilityController.php) — admin form (datetime-local inputs, Y-m-d\TH:i)
On the weekly path, new \DateTimeImmutable($startDt) in AvailabilityRepository::createWeeklySeries() throws on garbage → unhandled 500. On the single path the raw string lands in a DATETIME column and MySQL decides what to store. There is also no check that end_dt > start_dt.
Only authenticated instructors reach these paths, so this is robustness/data-integrity more than exploitability.
Fix
Normalise and validate in both paths: accept Y-m-d H:i[:s] and the datetime-localY-m-d\TH:i[:s] variants, canonicalise to Y-m-d H:i:s, reject anything else and any slot where end <= start (REST → 400; admin form → no-op like the existing empty-field check). Cover with unit tests.
## Finding (security review — Low / robustness)
Both availability creation paths accept arbitrary `start_dt` / `end_dt` strings:
- `AvailabilityEndpoint::create()` (src/Availability/AvailabilityEndpoint.php) — REST, `sanitize_text_field` only
- `AvailabilityController::addSlot()` (src/Availability/AvailabilityController.php) — admin form (`datetime-local` inputs, `Y-m-d\TH:i`)
On the weekly path, `new \DateTimeImmutable($startDt)` in `AvailabilityRepository::createWeeklySeries()` throws on garbage → unhandled 500. On the single path the raw string lands in a DATETIME column and MySQL decides what to store. There is also no check that `end_dt > start_dt`.
Only authenticated instructors reach these paths, so this is robustness/data-integrity more than exploitability.
## Fix
Normalise and validate in both paths: accept `Y-m-d H:i[:s]` and the `datetime-local` `Y-m-d\TH:i[:s]` variants, canonicalise to `Y-m-d H:i:s`, reject anything else and any slot where end <= start (REST → 400; admin form → no-op like the existing empty-field check). Cover with unit tests.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Finding (security review — Low / robustness)
Both availability creation paths accept arbitrary
start_dt/end_dtstrings:AvailabilityEndpoint::create()(src/Availability/AvailabilityEndpoint.php) — REST,sanitize_text_fieldonlyAvailabilityController::addSlot()(src/Availability/AvailabilityController.php) — admin form (datetime-localinputs,Y-m-d\TH:i)On the weekly path,
new \DateTimeImmutable($startDt)inAvailabilityRepository::createWeeklySeries()throws on garbage → unhandled 500. On the single path the raw string lands in a DATETIME column and MySQL decides what to store. There is also no check thatend_dt > start_dt.Only authenticated instructors reach these paths, so this is robustness/data-integrity more than exploitability.
Fix
Normalise and validate in both paths: accept
Y-m-d H:i[:s]and thedatetime-localY-m-d\TH:i[:s]variants, canonicalise toY-m-d H:i:s, reject anything else and any slot where end <= start (REST → 400; admin form → no-op like the existing empty-field check). Cover with unit tests.