{"record":{"id":"59c1a6b9d35559d2","repo":"apache/cassandra","slug":"only-superusers-can-bind-identities-to-a-role-with","errorCode":null,"errorMessage":"Only superusers can bind identities to a role with superuser status","messagePattern":"Only superusers can bind identities to a role with superuser status","errorType":"validation","errorClass":"UnauthorizedException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/cql3/statements/AddIdentityStatement.java","lineNumber":58,"sourceCode":"{\n    final String identity;\n    final String role;\n    final boolean ifNotExists;\n\n    public AddIdentityStatement(String identity, String role, boolean ifNotExists)\n    {\n        this.role = role;\n        this.identity = identity;\n        this.ifNotExists = ifNotExists;\n    }\n\n    @Override\n    public void authorize(ClientState state)\n    {\n        checkPermission(state, Permission.CREATE, RoleResource.root());\n\n        if (!state.getUser().isSuper() && DatabaseDescriptor.getRoleManager().isSuper(RoleResource.role(role)))\n            throw new UnauthorizedException(\"Only superusers can bind identities to a role with superuser status\");\n    }\n\n    @Override\n    public void validate(ClientState state)\n    {\n        state.ensureNotAnonymous();\n\n        if (!DatabaseDescriptor.getRoleManager().isExistingRole(RoleResource.role(role)))\n        {\n            throw new InvalidRequestException(String.format(\"Can not add identity for non-existent role '%s'\", role));\n        }\n\n        if (!ifNotExists && DatabaseDescriptor.getRoleManager().isExistingIdentity(identity))\n            throw new InvalidRequestException(String.format(\"%s already exists\", identity));\n    }\n\n    @Override\n    public AuditLogContext getAuditLogContext()","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/cql3/statements/AddIdentityStatement.java#L40-L76","documentation":"An authorization check in AddIdentityStatement.authorize: a non-superuser attempting to CREATE an identity bound to a role that currently has superuser status is rejected with UnauthorizedException. This prevents privilege escalation by letting ordinary users attach credentials/identities to superuser roles.","triggerScenarios":"CREATE IDENTITY ... FOR role 'x' (or equivalent AddIdentityStatement execution) where the authenticated user is not a superuser and DatabaseDescriptor.getRoleManager().isSuper(RoleResource.role(role)) returns true for the target role.","commonSituations":"Admin delegation setups where a lesser admin manages identities but tries to add one for the built-in superuser or another superuser role; scripts running under non-super credentials that previously worked against non-super roles.","solutions":["Run the statement as a superuser","Remove superuser status from the target role first (as a superuser), then add the identity","Pick a different, non-superuser role to bind the identity to"],"exampleFix":"// before (as non-super user)\nCREATE IDENTITY cert1 FOR 'superadmin';\n// after: run as superuser, or\nCREATE IDENTITY cert1 FOR 'app_role';  -- non-superuser role","handlingStrategy":"try-catch","validationCode":"// pre-check before issuing CREATE IDENTITY\nboolean targetIsSuper = roleManager.isSuper(RoleResource.role(roleName));\nboolean iAmSuper = clientUser.isSuper();\nif (targetIsSuper && !iAmSuper) throw new IllegalStateException(\"Need superuser to bind identity to superuser role \" + roleName);","typeGuard":null,"tryCatchPattern":"try { session.execute(createIdentity); } catch (UnauthorizedException e) { if (e.getMessage().contains(\"Only superusers can bind identities\")) { /* escalate credentials or target non-super role */ } else throw e; }","preventionTips":["Run identity-provisioning scripts with superuser credentials","List role superuser status (LIST ROLES) before binding identities","Never point identity automation at the default superuser role"],"tags":["auth","security","roles"],"backgroundTag":"permission-denied","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}