{"record":{"id":"bc762a282738f638","repo":"apache/cassandra","slug":"only-superusers-can-drop-a-role-with-superuser-sta","errorCode":null,"errorMessage":"Only superusers can drop a role with superuser status","messagePattern":"Only superusers can drop a role with superuser status","errorType":"validation","errorClass":"UnauthorizedException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/statements/DropRoleStatement.java","lineNumber":58,"sourceCode":"    private final RoleResource role;\n    private final boolean ifExists;\n\n    public DropRoleStatement(RoleName name, boolean ifExists)\n    {\n        this.role = RoleResource.role(name.getName());\n        this.ifExists = ifExists;\n    }\n\n    public void authorize(ClientState state) throws UnauthorizedException\n    {\n        super.checkPermission(state, Permission.DROP, role);\n\n        // We only check superuser status for existing roles to avoid\n        // caching info about roles which don't exist (CASSANDRA-9189)\n        if (DatabaseDescriptor.getRoleManager().isExistingRole(role)\n            && Roles.hasSuperuserStatus(role)\n            && !state.getUser().isSuper())\n            throw new UnauthorizedException(\"Only superusers can drop a role with superuser status\");\n    }\n\n    public void validate(ClientState state) throws RequestValidationException\n    {\n        // validate login here before authorize to avoid leaking user existence to anonymous users.\n        state.ensureNotAnonymous();\n\n        if (!ifExists && !DatabaseDescriptor.getRoleManager().isExistingRole(role))\n            throw new InvalidRequestException(String.format(\"%s doesn't exist\", role.getRoleName()));\n\n        AuthenticatedUser user = state.getUser();\n        if (user != null && user.getName().equals(role.getRoleName()))\n            throw new InvalidRequestException(\"Cannot DROP primary role for current login\");\n    }\n\n    public ResultMessage execute(ClientState state) throws RequestValidationException, RequestExecutionException\n    {\n        // not rejected in validate()","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/DropRoleStatement.java#L40-L76","documentation":"Cassandra throws UnauthorizedException when a non-superuser attempts to DROP a role that has superuser status. The check only runs for roles that actually exist, to avoid caching information about nonexistent roles (CASSANDRA-9189). Only a superuser may remove another superuser role.","triggerScenarios":"A logged-in (authenticated, non-superuser) user with sufficient permissions on the role executes DROP ROLE <role> where <role> exists and has superuser status (hasSuperuserRole option set).","commonSituations":"Operators with AUTHORIZE/ALTER-style permissions try to clean up or rotate old superuser accounts; mistaken assumption that DROP permission alone suffices; after a security review revoking superuser from an admin they still try to delete the role.","solutions":["Log in as (or assume) a superuser role and re-run the DROP ROLE statement","Demote the target role first with ALTER ROLE <role> WITH SUPERUSER = false as a superuser, then drop it","Grant the executing role SUPERUSER status: ALTER ROLE <you> WITH SUPERUSER = true (requires an existing superuser)"],"exampleFix":"// before\nDROP ROLE old_admin; -- as non-superuser -> UnauthorizedException\n// after\nALTER ROLE old_admin WITH SUPERUSER = false; -- as superuser\nDROP ROLE old_admin;","handlingStrategy":"validation","validationCode":"boolean targetIsSuperuser = Roles.hasSuperuserStatus(RoleResource.role(targetName));\nboolean iAmSuper = clientState.getUser().isSuper();\nif (targetIsSuperuser && !iAmSuper) throw new IllegalStateException(\"login as a superuser before dropping \" + targetName);","typeGuard":null,"tryCatchPattern":"try { session.execute(\"DROP ROLE \" + role); } catch (UnauthorizedException e) { log.warn(\"need superuser to drop {}\", role); }","preventionTips":["Verify Roles.hasSuperuserStatus(target) before scripting drops","Use IF EXISTS plus a superuser service account for role lifecycle automation","Demote roles to non-superuser before routine cleanup"],"tags":["cassandra","cql","authorization","roles","superuser"],"backgroundTag":"permission-denied","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}