ExportXMLWordPrintableJSON

    • Type: Bug
    • Resolution: Fixed
    • Priority: Major - P3
    • 8.3.16, 9.0.7, 8.0.37, 7.0.48
    • Affects Version/s: None
    • Component/s: None
    • Server Security
    • Fully Compatible
    • ALL
    • v9.0, v8.3, v8.0, v7.0, v8.2
    • Server Security 2026-07-03, Server Security 2026-07-17, Server Security 2026-07-31, Server Security 2026-08-14, Server Security 2026-08-28, Server Security 2026-09-11, Server Security 2026-10-23, Server Security 2026-11-06, Server Security 2026-11-20
    • None
    • None
    • None
    • None
    • None
    • None
    • None

      Security Context

      See SECBUG-1278 for problem description, security impact, preconditions, reproduction steps, and severity rationale.

      Root Cause

      • src/mongo/db/commands/user_management_commands.cpp: the cleanup filters in dropAllRolesFromDBTxnFn are built as nested plain objects that do not match array elements:
        • User-doc cleanup uses filter rolesMatch = {roles: {db: X}} — this matches a roles field whose value is the document {"db": X} exactly, not an array element containing db: X
        • Role-doc cleanup uses filter {roles: {"roles.db": X}} — likewise malformed for array matching
        • Both updates become no-ops while the role documents themselves are deleted, leaving dangling references in admin.system.users and admin.system.roles
        • src/mongo/db/commands/user_management_commands.cpp:1889: dropRole (the single-role command) already uses the correct idiom — $elemMatch — confirming the intended pattern; only the bulk command is affected

      Proposed Fix

      Replace both malformed filters with $elemMatch predicates, matching the idiom already used by dropRole:

      // user_management_commands.cpp — in dropAllRolesFromDBTxnFn
      
      // Correct filter for user-doc cleanup
      auto rolesMatch = BSON("roles" << BSON("$elemMatch" << roleMatch));
      buildUpdateRequest(usersNSS(...), rolesMatch, BSON("$pull" << roleMatch));
      
      // Correct filter for role-doc cleanup
      buildUpdateRequest(rolesNSS(...), rolesMatch, BSON("$pull" << roleMatch)); 

      Ensure both cleanup updates run before role document deletion and remain inside the same UMC transaction path.

      Acceptance Criteria

      • Running dropAllRolesFromDatabase removes all roles array references with db == targetDb from both system.users and system.roles documents.
      • Recreating a previously dropped role does not restore access for users/roles unless explicitly re-granted.
      • Existing dropRole behavior remains unchanged.
      • Regression tests fail on old behavior and pass with the fix.

      Test Coverage

      • Add/extend unit/integration coverage around dropAllRolesFromDatabase in auth role-management tests.
      • Add a regression scenario that:
        • grants role r1 to u1
        • runs dropAllRolesFromDatabase
        • recreates r1 with different privileges
        • asserts u1 does not gain recreated-role privileges until explicit grant
      • Validate both user-role and role-role reference cleanup.

      Notes

      The vulnerable filters on master (src/mongo/db/commands/user_management_commands.cpp:1959-1977):

      auto roleMatch = BSON(AuthorizationManager::ROLE_DB_FIELD_NAME
                            << dbname.serializeWithoutTenantPrefix_UNSAFE());
      auto rolesMatch = BSON("roles" << roleMatch);
      
      
      // users cleanup — filter {roles: {db: X}} does not match array elements
      buildUpdateRequest(usersNSS(...), rolesMatch, BSON("$pull" << rolesMatch));
      
      
      // roles cleanup — filter {roles: {"roles.db": X}} is also malformed
      buildUpdateRequest(rolesNSS(...),
                         BSON("roles" << BSON("roles.db" << dbname.serializeWithoutTenantPrefix_UNSAFE())),
                         BSON("$pull" << rolesMatch)); 

      The correct $elemMatch idiom is already used by dropRole (user_management_commands.cpp:1889):

      BSON("roles" << BSON("$elemMatch" << roleName.toBSON())) 

            Assignee:
            Sam Frank
            Reporter:
            Chye Lin Chee
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: