{"record":{"id":"ada02eb8e588b545","repo":"alibaba/nacos","slug":"role-nacos-anonymous-role-is-reserved-by-the","errorCode":null,"errorMessage":"role '__nacos_anonymous_role__' is reserved by the system","messagePattern":"role '__nacos_anonymous_role__' is reserved by the system","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"plugin-default-impl/nacos-default-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/roles/AbstractCheckedRoleService.java","lineNumber":152,"sourceCode":"    /**\n     * Mark the local global-admin lookup cache after an administrator role is created.\n     */\n    protected void markGlobalAdminRolePresent() {\n        hasGlobalAdminRole = true;\n    }\n    \n    /**\n     * Reject deletion or manual creation of system-reserved roles.\n     *\n     * @param role role name to check\n     */\n    protected void rejectReservedRole(String role) {\n        if (AuthConstants.GLOBAL_ADMIN_ROLE.equals(role)) {\n            throw new IllegalArgumentException(\n                \"role '\" + AuthConstants.GLOBAL_ADMIN_ROLE + \"' is not permitted to delete!\");\n        }\n        if (AuthConstants.ANONYMOUS_ROLE.equals(role)) {\n            throw new IllegalArgumentException(\n                \"role '\" + AuthConstants.ANONYMOUS_ROLE + \"' is reserved by the system\");\n        }\n    }\n    \n    /**\n     * If API is update user password, don't do permission check, because there is permission check in API logic.\n     */\n    private boolean isUpdatePasswordPermission(Permission permission) {\n        Properties properties = permission.getResource().getProperties();\n        return null != properties && properties.contains(AuthConstants.UPDATE_PASSWORD_ENTRY_POINT);\n    }\n    \n    private String joinResource(Resource resource) {\n        if (SignType.SPECIFIED.equals(resource.getType())) {\n            return resource.getName();\n        }\n        StringBuilder result = new StringBuilder();\n        String namespaceId = resource.getNamespaceId();","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/plugin-default-impl/nacos-default-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/roles/AbstractCheckedRoleService.java#L134-L170","documentation":"Thrown by AbstractCheckedRoleService.rejectReservedRole when an attempt is made to delete or manually create the anonymous role (__nacos_anonymous_role__). This role is reserved by the system for unauthenticated access and cannot be removed or recreated through the API. The guard prevents breaking anonymous/public access functionality.","triggerScenarios":"An admin API call attempts to delete or create a role named __nacos_anonymous_role__. The rejectReservedRole method catches this and throws before any persistence operation. This can happen via direct API calls, automated scripts, or tools that enumerate and delete all roles.","commonSituations":"Cleanup or migration script deletes all roles indiscriminately; a security audit tool attempts to remove the anonymous role; an admin tries to restructure roles and remove the default anonymous role; test setup code wipes all roles between tests.","solutions":["Do not attempt to delete __nacos_anonymous_role__ — it is required for anonymous/public API access.","Filter system-reserved roles (ROLE_ADMIN, __nacos_anonymous_role__) out of any batch role operations.","If you want to disable anonymous access, configure nacos.core.auth.enabled=true and manage permissions instead of removing the role.","In role management tooling, maintain a deny-list of reserved role names."],"exampleFix":"// before\nfor (String role : allRoles) {\n    roleService.deleteRole(role); // throws on __nacos_anonymous_role__\n}\n\n// after\nSet<String> reserved = Set.of(AuthConstants.GLOBAL_ADMIN_ROLE, AuthConstants.ANONYMOUS_ROLE);\nfor (String role : allRoles) {\n    if (!reserved.contains(role)) {\n        roleService.deleteRole(role);\n    }\n}","handlingStrategy":"validation","validationCode":"// Check for reserved role before attempting deletion\nSet<String> reservedRoles = Set.of(\n    AuthConstants.GLOBAL_ADMIN_ROLE,\n    AuthConstants.ANONYMOUS_ROLE\n);\nif (reservedRoles.contains(roleName)) {\n    throw new IllegalArgumentException(\"Cannot delete system-reserved role: \" + roleName);\n}\nroleService.deleteRole(roleName);","typeGuard":"public static boolean isReservedRole(String role) {\n    return AuthConstants.GLOBAL_ADMIN_ROLE.equals(role)\n        || AuthConstants.ANONYMOUS_ROLE.equals(role);\n}","tryCatchPattern":"try {\n    roleService.deleteRole(roleName);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"reserved by the system\")) {\n        return Result.failed(\"Role '\" + roleName + \"' is reserved and cannot be deleted\");\n    }\n    throw e;\n}","preventionTips":["Exclude __nacos_anonymous_role__ and ROLE_ADMIN from any automated role cleanup.","In role management APIs, validate against a reserved-role set before deletion.","To restrict anonymous access, configure auth settings and permissions rather than removing the role.","Document system-reserved roles for all API and tool consumers."],"tags":["auth-plugin","role-management","reserved-role","anonymous","input-validation"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}