Improper Ownership Management

Description

Improper Ownership Management is a vulnerability class that occurs when a product assigns incorrect ownership or fails to verify proper ownership of objects or resources. This represents a fundamental access control failure where the system cannot reliably establish who legitimately controls a given resource. The weakness can manifest as assigning files to wrong users, failing to verify ownership before allowing destructive operations, or accepting configuration from sources not properly validated as owners. Ownership management is distinct from permission management - it concerns who controls a resource rather than what operations are allowed.

Risk

Improper ownership management creates significant privilege escalation risks. When applications fail to verify ownership, users can perform operations on resources they don't own, potentially destroying or modifying other users' data. Setuid programs that use configuration files owned by non-root users allow those users to influence privileged program behavior. Processes that kill other users' processes without ownership verification enable denial of service attacks. Resource ownership confusion can lead to one user gaining access to another's privileges, data, or capabilities. The risk extends to privilege escalation when attackers can manipulate ownership to gain control over system resources.

Solution

Carefully manage the setting, management, and handling of resource ownership throughout the lifecycle. Always verify ownership before allowing destructive or privileged operations on resources. Setuid programs should only use configuration files owned by root with restrictive permissions. Implement ownership checks before process signals, file modifications, or resource deallocations. Explicitly establish and maintain trust zone boundaries based on ownership. When creating resources, assign ownership to the appropriate principal immediately and atomically. Log ownership changes for security auditing. Use platform-provided ownership verification APIs rather than implementing custom checks. Consider using capability-based security where ownership is cryptographically verified.

Common Consequences

ImpactDetails
Access ControlScope: Access Control

An attacker can gain elevated privileges or assume the identity of another user by exploiting improper ownership assignment. Operations performed without ownership verification can affect resources belonging to other users, leading to unauthorized data modification, deletion, or privilege escalation.

Example Code

Vulnerable Code (Python)

The following examples demonstrate improper ownership management:

# Vulnerable: Process killing without ownership verification
import os
import signal

def vulnerable_kill_process(process_id):
    # Vulnerable: No verification that user owns the process
    os.kill(process_id, signal.SIGKILL)
    # Any user can kill any process!

def vulnerable_delete_user_file(file_path):
    # Vulnerable: No ownership check
    os.remove(file_path)
    # User can delete files they don't own

class VulnerableResourceManager:

    def deallocate_resource(self, resource_id):
        # Vulnerable: No ownership verification
        resource = self.get_resource(resource_id)
        resource.deallocate()
        # Any user can deallocate any resource

    def modify_resource(self, resource_id, new_data):
        # Vulnerable: Modifies without checking ownership
        resource = self.get_resource(resource_id)
        resource.update(new_data)
// Vulnerable: Setuid program using non-root config file
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

// This is a setuid root program
int vulnerable_setuid_program(void) {
    char config_path[256];
    char *home = getenv("HOME");

    // Vulnerable: Uses config file from user's home directory
    snprintf(config_path, sizeof(config_path), "%s/.myapp.conf", home);

    FILE *config = fopen(config_path, "r");
    if (config) {
        // Vulnerable: Config file is owned by non-root user
        // User can control privileged program behavior!
        parse_config(config);
        fclose(config);
    }

    // Runs privileged operations based on user-controlled config
    do_privileged_operations();

    return 0;
}

// Vulnerable: No ownership check before file operations
int vulnerable_file_operation(const char *filepath, uid_t requesting_user) {
    // Vulnerable: Doesn't verify requesting_user owns the file
    int fd = open(filepath, O_RDWR);
    if (fd >= 0) {
        write(fd, "modified", 8);  // Modifying file user may not own
        close(fd);
    }
    return 0;
}
// Vulnerable: Java resource management without ownership
public class VulnerableResourceManager {

    public void deleteUserData(String userId, String dataId) {
        // Vulnerable: No verification that current user is the owner
        UserData data = userDataRepository.findById(dataId);
        userDataRepository.delete(data);
        // Any authenticated user can delete any user's data
    }

    public void updateUserProfile(String targetUserId, ProfileData newData) {
        // Vulnerable: No ownership check
        UserProfile profile = profileRepository.findByUserId(targetUserId);
        profile.update(newData);
        profileRepository.save(profile);
        // User can modify other users' profiles
    }

    public void terminateUserSession(String sessionId) {
        // Vulnerable: Can terminate sessions they don't own
        Session session = sessionRepository.findById(sessionId);
        session.terminate();
        // User can terminate other users' sessions
    }
}

Fixed Code (Python)

# Fixed: Process killing with ownership verification
import os
import signal
import pwd

def get_process_owner(process_id):
    """Get the UID of the process owner"""
    try:
        with open(f'/proc/{process_id}/status', 'r') as f:
            for line in f:
                if line.startswith('Uid:'):
                    # Real UID is the first value
                    return int(line.split()[1])
    except (FileNotFoundError, PermissionError):
        return None
    return None

def secure_kill_process(process_id):
    """Kill process only if owned by current user"""
    current_user = os.getuid()
    process_owner = get_process_owner(process_id)

    if process_owner is None:
        raise ProcessNotFoundError(f"Process {process_id} not found")

    if process_owner != current_user:
        raise PermissionError(
            f"Cannot kill process {process_id}: owned by UID {process_owner}"
        )

    os.kill(process_id, signal.SIGKILL)

def secure_delete_user_file(file_path, requesting_user):
    """Delete file only if owned by requesting user"""
    try:
        file_stat = os.stat(file_path)
    except FileNotFoundError:
        raise FileNotFoundError(f"File not found: {file_path}")

    if file_stat.st_uid != requesting_user:
        raise PermissionError(
            f"Cannot delete {file_path}: not owned by requesting user"
        )

    os.remove(file_path)

class SecureResourceManager:

    def deallocate_resource(self, resource_id, requesting_user):
        """Deallocate resource only if owned by requesting user"""
        resource = self.get_resource(resource_id)

        if resource.owner_id != requesting_user.id:
            raise PermissionError(
                f"User {requesting_user.id} does not own resource {resource_id}"
            )

        resource.deallocate()
        self.audit_log.record('resource_deallocated', resource_id, requesting_user.id)

    def modify_resource(self, resource_id, new_data, requesting_user):
        """Modify resource only after ownership verification"""
        resource = self.get_resource(resource_id)

        if resource.owner_id != requesting_user.id:
            raise PermissionError(
                f"User {requesting_user.id} cannot modify resource {resource_id}"
            )

        resource.update(new_data)
        self.audit_log.record('resource_modified', resource_id, requesting_user.id)
// Fixed: Setuid program with proper configuration ownership
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>

// Fixed: Only use root-owned configuration
int secure_setuid_program(void) {
    const char *config_path = "/etc/myapp/config.conf";

    // Verify configuration file ownership before use
    struct stat config_stat;
    if (stat(config_path, &config_stat) != 0) {
        fprintf(stderr, "Cannot stat config file\n");
        return -1;
    }

    // Fixed: Config must be owned by root
    if (config_stat.st_uid != 0) {
        fprintf(stderr, "SECURITY: Config file not owned by root\n");
        return -1;
    }

    // Fixed: Config must not be writable by others
    if (config_stat.st_mode & (S_IWGRP | S_IWOTH)) {
        fprintf(stderr, "SECURITY: Config file has insecure permissions\n");
        return -1;
    }

    FILE *config = fopen(config_path, "r");
    if (config) {
        parse_config(config);
        fclose(config);
    }

    do_privileged_operations();
    return 0;
}

// Fixed: Verify ownership before file operations
int secure_file_operation(const char *filepath, uid_t requesting_user) {
    struct stat file_stat;

    if (stat(filepath, &file_stat) != 0) {
        return -1;
    }

    // Verify ownership
    if (file_stat.st_uid != requesting_user) {
        fprintf(stderr, "User %d does not own file %s (owned by %d)\n",
                requesting_user, filepath, file_stat.st_uid);
        return -1;
    }

    int fd = open(filepath, O_RDWR);
    if (fd >= 0) {
        write(fd, "modified", 8);
        close(fd);
    }

    return 0;
}
// Fixed: Java resource management with ownership verification
public class SecureResourceManager {

    public void deleteUserData(User currentUser, String dataId) {
        UserData data = userDataRepository.findById(dataId)
            .orElseThrow(() -> new ResourceNotFoundException(dataId));

        // Fixed: Verify ownership before deletion
        if (!data.getOwnerId().equals(currentUser.getId())) {
            auditLog.logUnauthorizedAccess(currentUser, "delete", dataId);
            throw new UnauthorizedAccessException(
                "User does not own this data"
            );
        }

        userDataRepository.delete(data);
        auditLog.logResourceDeleted(currentUser, dataId);
    }

    public void updateUserProfile(User currentUser, String targetUserId, ProfileData newData) {
        // Fixed: Can only update own profile
        if (!currentUser.getId().equals(targetUserId)) {
            auditLog.logUnauthorizedAccess(currentUser, "update_profile", targetUserId);
            throw new UnauthorizedAccessException(
                "Cannot modify another user's profile"
            );
        }

        UserProfile profile = profileRepository.findByUserId(targetUserId)
            .orElseThrow(() -> new ProfileNotFoundException(targetUserId));

        profile.update(newData);
        profileRepository.save(profile);
        auditLog.logProfileUpdated(currentUser);
    }

    public void terminateUserSession(User currentUser, String sessionId) {
        Session session = sessionRepository.findById(sessionId)
            .orElseThrow(() -> new SessionNotFoundException(sessionId));

        // Fixed: Verify session ownership
        if (!session.getUserId().equals(currentUser.getId())) {
            // Admin override check
            if (!currentUser.hasRole(Role.ADMIN)) {
                auditLog.logUnauthorizedAccess(currentUser, "terminate_session", sessionId);
                throw new UnauthorizedAccessException(
                    "Cannot terminate another user's session"
                );
            }
            auditLog.logAdminSessionTermination(currentUser, session.getUserId(), sessionId);
        }

        session.terminate();
    }
}

The fix verifies ownership before allowing destructive or modifying operations on resources.


Exploited in the Wild

Setuid Configuration Exploitation (Unix Systems, Historical)

CVE-1999-1125 documented a setuid root program that relied on configuration files owned by non-root users, allowing privilege escalation by modifying the configuration to influence privileged program behavior.

Process Killing Vulnerabilities (Various Systems, Ongoing)

Applications that kill processes without ownership verification have enabled denial of service attacks where users terminate other users' processes or critical system services.

Multi-tenant Resource Access (Cloud Applications, Ongoing)

Cloud applications that failed to verify resource ownership have allowed cross-tenant attacks where one customer could access, modify, or delete another customer's resources.


Tools to Test/Exploit

  • ps/top — Process listing tools for identifying process ownership.

  • stat — File status tool for checking file ownership.

  • Application security scanners — Tools for identifying ownership verification gaps.


CVE Examples

  • CVE-1999-1125 — Setuid root program relied on configuration files owned by non-root users, allowing privilege escalation.

References

  1. MITRE Corporation. "CWE-282: Improper Ownership Management." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/282.html

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

  3. CERT C Secure Coding Standard. "FIO15-C. Ensure that file operations are performed in a secure directory." https://wiki.sei.cmu.edu/confluence/display/c/FIO15-C