Forums Bug Reports Thread

Open redirect: AdminAchievementController redirects to raw $_POST['return_to'] without the safe-path allowlist used by sibling controllers

Patrick Bass · Jun 6 · 11 · 1 Locked
[Minor] [Normal Priority] [Bug Fixed] [Always Reproduces]
🚀 OP Jun 6, 2026 7:37pm

Area: Admin plane (audit p12) · Surface: POST /admin/achievements/grant, POST /admin/achievements/revoke (AdminAchievementController) · Dimension: security · Severity: minor

A crafted form/POST with `return_to=//evil.example` (or `https://evil.example`) sent to /admin/achievements/grant or /revoke causes a 302 Location to the attacker-controlled host. OWASP A01:2021 Broken Access Control (open redirect). Severity is capped because the route requires role 5 + a valid CSRF token, so an attacker must already control a super-admin session/form — primarily a consistency/defense-in-depth defect rather than a remote pre-auth redirect. The fix is one line and the project clearly intends every return-to redirect to go through the allowlist (every other controller does).

Evidence

AdminAchievementController.php uses `$this->redirect($_POST['return_to'] ?? '/admin/achievements');` unfiltered at lines 174, 181, 185, 195, 210, 216, 226. BaseController::redirect() (platform/src/Controllers/BaseController.php:411-416) sends the value straight into `header("Location: {$url}")` with no validation. Sibling controllers performing the identical return-to pattern DO validate: AdminBadgeController.php:177 `$returnUrl = \App\Services\UrlValidator::safeRedirectPath($_SERVER['HTTP_REFERER'] ?? null, '/admin/badges');`, AdminFileController.php:531 same, AdminUserActionController.php:390-394 same. The platform even ships the helper for this: BaseController::isSafeReturnPath() (BaseController.php:717-732) and Services/UrlValidator::safeRedirectPath() (Services/UrlValidator.php:162). AdminAchievementController is the lone outlier that skips it.

Suggested fix. Replace each `$this->redirect($_POST['return_to'] ?? '/admin/achievements')` with `$this->redirect(\App\Services\UrlValidator::safeRedirectPath($_POST['return_to'] ?? null, '/admin/achievements'))`, matching AdminBadgeController/AdminFileController/AdminUserActionController.

Filed by the automated tenant-app audit and adversarially evidence-verified. Status: verified. Open — not yet actioned.


Patrick Bass
@mobieus

🚀 Jun 7, 2026 5:44am

Resolved — fixed and deployed. Commit 059d6bf29b6f, shipped dev-first then to all tenants on 2026-06-06.

Same fix as 367 (overlapping surface): each $this->redirect($_POST['return_to'] ?? '/admin/achievements') in grant() and revoke() now passes return_to through UrlValidator::safeRedirectPath with the /admin/achievements fallback. php -l passes.

Status: fixed. Thread closed and locked.


Patrick Bass
@mobieus

Log in or register to reply to this thread.