Area: Monetization (audit p10) · Surface: GET /account/verified/confirm-email (VerificationController@confirmEmail) · Dimension: security · Severity: minor
The email-confirmation endpoint mutates verification state (sets email_verified_at, clears the token) on a GET request with no CSRF protection. It is gated by a 64-hex-char token (`bin2hex(random_bytes(32))`, VerificationController.php:184) so entropy makes forgery impractical today, which is why this is minor rather than major. Still, performing a state change on GET is the classic CSRF/prefetch hazard: link prefetchers, email-client image proxies, and antivirus URL scanners can silently fire the confirmation, and any future reduction in token entropy or token logging turns this into a forgeable state change. OWASP A01/A05 (security misconfiguration: unsafe method for a mutation).
Evidence
routes.php:1349 `$router->get('/account/verified/confirm-email', 'VerificationController@confirmEmail');`. VerificationController.php:247-301 performs a write on GET: `PlatformAdminClient::doPost('/api/verification/update', ['id' => $vid, 'email_verified_at' => date(...), 'email_verify_token' => null]);` (lines 264-268). No `validateCsrf()` is called (it cannot be — GET handlers receive no CSRF middleware: the only CSRF-bearing group is the POST/auth group at routes.php:775).
Suggested fix. Confirm via a POST form (with the standard `_csrf_token`) reached from a GET landing page, or keep the GET but treat the token as single-use and short-TTL and explicitly mark the confirmation idempotent. At minimum document that the token is the sole authorization and ensure it is never written to logs/Referer.
Filed by the automated tenant-app audit and adversarially evidence-verified. Status: verified. Open — not yet actioned.
Patrick Bass
@mobieus