{"record":{"id":"fb6ffc5e3cbaab7c","repo":"flarum/framework","slug":"erase-requests-cannot-be-confirmed-by-different-users","errorCode":null,"errorMessage":"Erase requests cannot be confirmed by different users.","messagePattern":"Erase requests cannot be confirmed by different users\\.","errorType":"validation","errorClass":"ValidationException","httpStatus":422,"severity":"error","filePath":"extensions/gdpr/src/Http/Controller/ConfirmErasureController.php","lineNumber":47,"sourceCode":"    {\n    }\n\n    public function handle(Request $request): ResponseInterface\n    {\n        $actor = RequestUtil::getActor($request);\n        $token = Arr::get($request->getQueryParams(), 'token');\n\n        /** @var ErasureRequest $erasureRequest */\n        $erasureRequest = ErasureRequest::query()\n            ->with('user')\n            ->where('verification_token', $token)\n            ->firstOrFail();\n\n        /**\n         * @TODO: the token is enough to confirm the erasure request. We should not require the user to be logged in.\n         */\n        if ($erasureRequest->user->isNot($actor) && ! $actor->isGuest()) {\n            throw new ValidationException(['user' => 'Erase requests cannot be confirmed by different users.']);\n        }\n\n        if (in_array($erasureRequest->status, [ErasureRequest::STATUS_PROCESSED, ErasureRequest::STATUS_MANUAL])) {\n            throw new ValidationException(['request' => 'This erasure request has already been processed.']);\n        }\n\n        $ip = $request->getAttribute('ipAddress');\n\n        $erasureRequest->user_confirmed_at = Carbon::now();\n        $erasureRequest->status = ErasureRequest::STATUS_USER_CONFIRMED;\n        $erasureRequest->cancelled_at = null;\n        $erasureRequest->verification_token = null;\n        $erasureRequest->confirmation_ip = $ip;\n        $erasureRequest->save();\n\n        // Attribute to the request's owner: confirmation may arrive via the\n        // emailed token while logged out, so $actor can be a guest.\n        $this->events->dispatch(new ErasureConfirmed($erasureRequest->user, $erasureRequest));","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/flarum/framework/blob/4b939f685389bfe8a380e9e28ddf305a1c66950c/extensions/gdpr/src/Http/Controller/ConfirmErasureController.php#L29-L65","documentation":"ConfirmErasureController handles the erasure confirmation link and requires that the actor either is the owner of the erasure request or is a guest; a logged-in user confirming another user's request throws this ValidationException. The token alone identifies the request, so identity mismatch is rejected.","triggerScenarios":"Visiting the erasure confirmation URL while logged in as a user different from the request's owner (erasureRequest->user->isNot(actor) and actor not guest).","commonSituations":"Admin or another account is logged in when the user clicks the emailed confirmation link; shared computer with another session; testing the confirmation link in the wrong browser profile.","solutions":["Log out (or use an incognito window) so you are a guest, then open the confirmation link.","Open the link in a browser profile where the request owner is logged in.","Confirm the link/token belongs to the currently logged-in user; request a new erasure confirmation email if unsure."],"exampleFix":"null","handlingStrategy":"validation","validationCode":"// before opening the confirmation link, ensure session state:\n// guest OR logged in as the request owner\nif ($actor->isGuest() === false && $erasureRequest->user_id !== $actor->id) { /* do not request */ }","typeGuard":null,"tryCatchPattern":"try { $http->get($confirmUrl); } catch (ValidationException $e) { if (isset($e->getErrors()['user'])) { /* advise logout or correct account */ } }","preventionTips":["Send confirmation links that prompt logout first","Test links in incognito windows","Ensure emails go to the request owner only"],"tags":["authorization","gdpr","session"],"backgroundTag":"permission-denied","analyzedSha":"4b939f685389bfe8a380e9e28ddf305a1c66950c","analyzedAt":"2026-09-15T18:09:20.879Z","contentChangedAt":"2026-09-15T18:09:20.879Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}