{"record":{"id":"d6b4a940029d2c65","repo":"passbolt/passbolt_api","slug":"registration-is-not-opened-to-public-this-is-due-to-a","errorCode":null,"errorMessage":"Registration is not opened to public. This is due to a security setting. Please contact your administrator.","messagePattern":"Registration is not opened to public\\. This is due to a security setting\\. Please contact your administrator\\.","errorType":"exception","errorClass":"Cake\\Http\\Exception\\NotFoundException","httpStatus":404,"severity":"warning","filePath":"src/Controller/Users/UsersRegisterController.php","lineNumber":116,"sourceCode":"    }\n\n    /**\n     * @param \\Passbolt\\SelfRegistration\\Service\\DryRun\\SelfRegistrationDryRunServiceInterface $dryRunService dry run service\n     * @return void\n     * @throws \\Cake\\Http\\Exception\\NotFoundException if the user cannot register\n     */\n    protected function assertIsSelfRegistrationOpen(SelfRegistrationDryRunServiceInterface $dryRunService): void\n    {\n        if (!$dryRunService->isSelfRegistrationOpen()) {\n            $msg = __('Registration is not opened to public.') . ' ';\n            $msg .= __('Please contact your administrator.');\n            throw new NotFoundException($msg);\n        }\n        if (Configure::read(UsersRecoverController::PREVENT_EMAIL_ENUMERATION_CONFIG_KEY)) {\n            $msg = __('Registration is not opened to public.') . ' ';\n            $msg .= __('This is due to a security setting.') . ' ';\n            $msg .= __('Please contact your administrator.');\n            throw new NotFoundException($msg);\n        }\n    }\n}\n","sourceCodeStart":98,"sourceCodeEnd":120,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/src/Controller/Users/UsersRegisterController.php#L98-L120","documentation":"Passbolt's registration endpoint is gated by the config key `passbolt.security.preventEmailEnumeration` (UsersRecoverController::PREVENT_EMAIL_ENUMERATION_CONFIG_KEY). When self-registration is already closed (an earlier check in assertIsSelfRegistrationOpen) or when email-enumeration prevention is enabled, the controller throws a 404 NotFoundException instead of revealing whether registration is open. The generic message is intentional: it avoids leaking account/registration state to unauthenticated visitors.","triggerScenarios":"Calling GET or POST /users/register (registerGet/registerPost) when (a) public self-registration is disabled — the first check throws a NotFoundException just before this code — or (b) Configure::read('passbolt.security.preventEmailEnumeration') is truthy.","commonSituations":"Deployments with passbolt.php or config/passbolt.default.php setting 'passbolt.security' => ['preventEmailEnumeration' => true]; admins who disabled the self-registration plugin (passbolt.plugins.accountSettings / registration settings); users trying to reach the /register route on a hardened production instance where only admins can create accounts; staging instances inheriting hardened production config.","solutions":["Check whether public registration should be open; if yes, set 'preventEmailEnumeration' => false under 'passbolt.security' in config and clear the cache (cake cache clear_all).","If registration should stay admin-controlled, direct users to an admin: create the account via UsersAdminController or the 'register' command, and send the invitation email manually.","If the intent is only to hide registration from enumeration while still allowing signup, disable preventEmailEnumeration and instead rely on the registration-open check.","Verify which check is firing: if self-registration itself is closed, re-enabling it requires enabling the self-registration plugin/settings rather than only the enumeration flag."],"exampleFix":"// before (config/passbolt.php)\n'passbolt' => ['security' => ['preventEmailEnumeration' => true]]\n// after (allow public registration)\n'passbolt' => ['security' => ['preventEmailEnumeration' => false]]","handlingStrategy":"validation","validationCode":"// PHP client-side pre-check: only call /users/register when the instance allows it\nconst settings = await fetch(baseUrl + '/healthcheck/status.json').then(r => r.json());\nif (!settings.body.application.registrationPublic) {\n  throw new Error('Public registration is disabled on this instance; ask an admin to create the account.');\n}","typeGuard":null,"tryCatchPattern":"// PHP (CakePHP Http client)\ntry {\n    $response = $http->get($baseUrl . '/users/register.json');\n} catch (Cake\\Http\\Exception\\HttpException $e) {\n    if ($e->getCode() === 404) {\n        // registration closed or email enumeration prevention active\n        throw new DomainException('Signup unavailable on this passbolt instance; contact the administrator.', 0, $e);\n    }\n    throw $e;\n}","preventionTips":["Read passbolt.security.preventEmailEnumeration from server config before advertising a signup link.","Provide admins a documented path to create/invite users when registration is closed.","Treat 404 from the register endpoint as 'feature disabled', not as a missing route.","Keep server config and client expectations in sync during security hardening rollouts."],"tags":["passbolt","cakephp","configuration","registration","security"],"backgroundTag":"invalid-config-value","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}