Incorrect User Management

Description

Incorrect User Management is a vulnerability class that occurs when a product does not properly manage users within its environment. This weakness manifests when users are assigned to incorrect permission groups, granted wrong roles, or have their group memberships improperly recorded or maintained. The result is that users obtain unintended access rights to sensitive objects and functionality. Unlike authorization bypass vulnerabilities that circumvent access controls, this weakness concerns the incorrect assignment or tracking of legitimate user attributes that determine access.

Risk

Incorrect user management creates privilege escalation risks by granting users access beyond their intended scope. When users are assigned to wrong groups, they may access administrative functions, sensitive data, or privileged operations. Container and virtualization environments that fail to properly record supplementary group IDs may allow users to bypass group-based restrictions. Operating systems that incorrectly assign users to privileged groups like wheel or admin enable unauthorized privilege elevation. The risk extends to multi-tenant environments where incorrect user-tenant mapping could expose cross-tenant data. Automated user provisioning systems that misconfigure group memberships can create widespread access control failures affecting many users simultaneously.

Solution

Implement robust user management processes with validation of all user attribute assignments. Verify group memberships and role assignments before granting access. Audit user-group relationships regularly to detect misconfigurations. Record and track all user attributes including supplementary group IDs, ensuring they are properly maintained across operations. Use role-based access control (RBAC) with clearly defined roles and validate that users are assigned only to appropriate roles. Implement approval workflows for privileged group memberships. Test user provisioning and management operations to ensure correct group assignments. Log all user attribute changes for security monitoring. Consider implementing attribute-based access control (ABAC) for more granular user management.

Common Consequences

ImpactDetails
Access ControlScope: Access Control

Users assigned to incorrect groups or with improperly managed attributes gain unintended access to sensitive resources. This can lead to unauthorized data access, privilege escalation, and ability to perform operations reserved for other user classes.

Example Code

Vulnerable Code (Python)

The following examples demonstrate incorrect user management:

# Vulnerable: User provisioning with incorrect group assignment
class VulnerableUserProvisioning:

    def create_user(self, username, department):
        user = User(username=username)

        # Vulnerable: Logic error assigns wrong group
        if department == "engineering":
            # Bug: Should be "developers" but assigns "admins"
            user.groups.add("admins")  # Wrong group!
        elif department == "finance":
            user.groups.add("finance")
        else:
            user.groups.add("users")

        user.save()
        return user

    def sync_user_from_ldap(self, ldap_entry):
        user = User(username=ldap_entry['cn'])

        # Vulnerable: Doesn't sync supplementary groups
        user.primary_group = ldap_entry['gidNumber']
        # Missing: supplementary group sync
        # User loses group memberships during sync

        user.save()

class VulnerableContainerRuntime:

    def start_container(self, user_config):
        # Vulnerable: Fails to record supplementary group IDs
        process = ContainerProcess()
        process.uid = user_config.uid
        process.gid = user_config.gid
        # Missing: process.supplementary_gids = user_config.groups
        # Container can bypass group-based restrictions

        process.start()
// Vulnerable: Operating system user management
#include <grp.h>
#include <pwd.h>
#include <unistd.h>

int vulnerable_add_user_to_system(const char *username) {
    struct passwd *pw;

    // Create user
    pw = create_user(username);

    // Vulnerable: Logic error adds user to privileged group
    // when they should be in regular users group
    if (is_staff_member(username)) {
        // Bug: Should check for admin role, not staff
        add_to_group(username, "wheel");  // Incorrectly grants sudo access
    }

    return 0;
}

int vulnerable_setgroups(uid_t uid) {
    // Vulnerable: Only sets primary group, loses supplementary groups
    struct passwd *pw = getpwuid(uid);
    if (pw) {
        setgid(pw->pw_gid);
        // Missing: initgroups() or setgroups() call
        // User loses all supplementary group memberships
    }
    return 0;
}
// Vulnerable: Java user management service
public class VulnerableUserService {

    public void provisionUser(UserRequest request) {
        User user = new User();
        user.setUsername(request.getUsername());

        // Vulnerable: Role mapping error
        if (request.getAccessLevel().equals("standard")) {
            // Bug: Typo assigns admin role to standard users
            user.addRole(Role.ADMINISTRATOR);  // Should be Role.STANDARD
        }

        userRepository.save(user);
    }

    public void importUsersFromCSV(List<String[]> userData) {
        for (String[] row : userData) {
            User user = new User();
            user.setUsername(row[0]);

            // Vulnerable: Column index error
            // Assumes row[1] is role but CSV has department in row[1]
            user.addRole(Role.valueOf(row[1]));  // Wrong column!

            userRepository.save(user);
        }
    }

    public void copyUserPermissions(User source, User target) {
        // Vulnerable: Copies all groups including privileged ones
        target.setGroups(new HashSet<>(source.getGroups()));
        // Should filter out admin/privileged groups
        userRepository.save(target);
    }
}

Fixed Code (Python)

# Fixed: User provisioning with validated group assignment
class SecureUserProvisioning:

    # Define valid department-to-group mappings
    DEPARTMENT_GROUPS = {
        "engineering": "developers",
        "finance": "finance",
        "hr": "hr",
        "it": "it_staff",
    }

    PRIVILEGED_GROUPS = {"admins", "wheel", "sudo", "root"}

    def create_user(self, username, department, created_by):
        user = User(username=username)

        # Fixed: Use validated mapping
        if department not in self.DEPARTMENT_GROUPS:
            raise ValueError(f"Unknown department: {department}")

        target_group = self.DEPARTMENT_GROUPS[department]

        # Fixed: Prevent accidental privileged group assignment
        if target_group in self.PRIVILEGED_GROUPS:
            raise SecurityError(
                f"Cannot auto-assign privileged group: {target_group}"
            )

        user.groups.add(target_group)
        user.save()

        # Audit log
        self.audit_log.record(
            action='user_created',
            username=username,
            groups=list(user.groups),
            created_by=created_by.username
        )

        return user

    def sync_user_from_ldap(self, ldap_entry):
        user = User(username=ldap_entry['cn'])
        user.primary_group = ldap_entry['gidNumber']

        # Fixed: Sync supplementary groups
        if 'memberOf' in ldap_entry:
            for group_dn in ldap_entry['memberOf']:
                group_name = self.extract_group_name(group_dn)
                if self.is_allowed_group(group_name):
                    user.supplementary_groups.add(group_name)

        user.save()
        return user

class SecureContainerRuntime:

    def start_container(self, user_config):
        process = ContainerProcess()
        process.uid = user_config.uid
        process.gid = user_config.gid

        # Fixed: Record all supplementary group IDs
        process.supplementary_gids = list(user_config.groups)

        # Validate group IDs before starting
        self.validate_group_permissions(process)

        process.start()

        # Log container start with full group information
        self.audit_log.record(
            action='container_started',
            uid=process.uid,
            gid=process.gid,
            supplementary_gids=process.supplementary_gids
        )
// Fixed: Operating system user management
#include <grp.h>
#include <pwd.h>
#include <unistd.h>
#include <syslog.h>

// Define privileged groups
const char *PRIVILEGED_GROUPS[] = {"wheel", "sudo", "admin", "root"};
const int NUM_PRIVILEGED = 4;

int is_privileged_group(const char *group) {
    for (int i = 0; i < NUM_PRIVILEGED; i++) {
        if (strcmp(group, PRIVILEGED_GROUPS[i]) == 0) {
            return 1;
        }
    }
    return 0;
}

int secure_add_user_to_system(const char *username, const char *role) {
    struct passwd *pw;

    pw = create_user(username);

    // Fixed: Explicit role-to-group mapping with validation
    const char *target_group;

    if (strcmp(role, "admin") == 0) {
        // Only explicit admin role gets wheel access
        if (!is_authorized_to_create_admin(get_current_user())) {
            syslog(LOG_WARNING, "Unauthorized admin creation attempt: %s", username);
            return -1;
        }
        target_group = "wheel";
    } else if (strcmp(role, "developer") == 0) {
        target_group = "developers";
    } else {
        target_group = "users";
    }

    add_to_group(username, target_group);

    syslog(LOG_INFO, "User %s created with group %s", username, target_group);
    return 0;
}

int secure_setgroups_for_user(uid_t uid) {
    struct passwd *pw = getpwuid(uid);
    if (!pw) return -1;

    // Fixed: Initialize all groups including supplementary
    if (initgroups(pw->pw_name, pw->pw_gid) != 0) {
        return -1;
    }

    // Verify groups were set
    gid_t groups[NGROUPS_MAX];
    int ngroups = getgroups(NGROUPS_MAX, groups);
    if (ngroups < 0) {
        return -1;
    }

    syslog(LOG_DEBUG, "Set %d groups for user %s", ngroups, pw->pw_name);
    return 0;
}
// Fixed: Java user management service
public class SecureUserService {

    private static final Set<Role> PRIVILEGED_ROLES =
        Set.of(Role.ADMINISTRATOR, Role.SUPER_ADMIN, Role.SECURITY_ADMIN);

    private static final Map<String, Role> ACCESS_LEVEL_MAPPING = Map.of(
        "standard", Role.STANDARD,
        "power_user", Role.POWER_USER,
        "analyst", Role.ANALYST
    );

    public void provisionUser(UserRequest request, User createdBy) {
        User user = new User();
        user.setUsername(request.getUsername());

        // Fixed: Use validated mapping
        String accessLevel = request.getAccessLevel().toLowerCase();
        if (!ACCESS_LEVEL_MAPPING.containsKey(accessLevel)) {
            throw new IllegalArgumentException(
                "Unknown access level: " + accessLevel
            );
        }

        Role role = ACCESS_LEVEL_MAPPING.get(accessLevel);

        // Fixed: Block privileged role assignment through this path
        if (PRIVILEGED_ROLES.contains(role)) {
            throw new SecurityException(
                "Privileged roles cannot be assigned through standard provisioning"
            );
        }

        user.addRole(role);
        userRepository.save(user);

        auditLog.record("user_provisioned", user, createdBy);
    }

    public void importUsersFromCSV(List<String[]> userData, User importedBy) {
        // Fixed: Validate CSV structure
        String[] header = userData.get(0);
        int usernameCol = findColumn(header, "username");
        int roleCol = findColumn(header, "role");

        if (usernameCol < 0 || roleCol < 0) {
            throw new IllegalArgumentException(
                "CSV must have 'username' and 'role' columns"
            );
        }

        for (int i = 1; i < userData.size(); i++) {
            String[] row = userData.get(i);
            User user = new User();
            user.setUsername(row[usernameCol]);

            // Fixed: Validate role value
            String roleName = row[roleCol].toUpperCase();
            try {
                Role role = Role.valueOf(roleName);

                // Block privileged roles in bulk import
                if (PRIVILEGED_ROLES.contains(role)) {
                    logger.warn("Skipping privileged role in import: " + roleName);
                    continue;
                }

                user.addRole(role);
            } catch (IllegalArgumentException e) {
                logger.error("Invalid role in CSV row " + i + ": " + roleName);
                continue;
            }

            userRepository.save(user);
        }
    }

    public void copyUserPermissions(User source, User target, User copiedBy) {
        // Fixed: Filter out privileged groups
        Set<String> safeGroups = source.getGroups().stream()
            .filter(g -> !isPrivilegedGroup(g))
            .collect(Collectors.toSet());

        target.setGroups(safeGroups);
        userRepository.save(target);

        auditLog.record("permissions_copied", source, target, safeGroups, copiedBy);
    }
}

The fix implements validated mappings, prevents accidental privileged group assignment, and properly maintains all user attributes including supplementary groups.


Exploited in the Wild

Container Group ID Bypass (Container Platforms, 2022)

CVE-2022-36109 documented a containerization product that failed to record a user's supplementary group ID, enabling users to bypass group-based restrictions within containers.

Unix Wheel Group Misconfiguration (Unix Systems, 1999)

CVE-1999-1193 documented an operating system that incorrectly assigned users to the privileged wheel group, permitting unauthorized root privilege elevation through su/sudo.

LDAP User Sync Issues (Enterprise Environments, Ongoing)

Organizations using LDAP synchronization have experienced issues where group memberships were not properly synced, resulting in users having either too much or too little access.


Tools to Test/Exploit

  • BloodHound — Active Directory analysis tool for identifying user group misconfigurations.

  • id/groups commands — Unix tools for verifying user group memberships.

  • ADRecon — Active Directory reconnaissance tool for auditing user configurations.


CVE Examples

  • CVE-2022-36109 — Containerization product failed to record supplementary group ID, enabling group restriction bypass.

  • CVE-1999-1193 — Operating system incorrectly assigned users to privileged wheel group.


References

  1. MITRE Corporation. "CWE-286: Incorrect User Management." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/286.html

  2. NIST. "Role-Based Access Control." https://csrc.nist.gov/projects/role-based-access-control

  3. OWASP Foundation. "Broken Access Control." OWASP Top 10. https://owasp.org/Top10/A01_2021-Broken_Access_Control/