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
| Impact | Details |
|---|---|
| Access Control | Scope: 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
-
MITRE Corporation. "CWE-282: Improper Ownership Management." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/282.html
-
OWASP Foundation. "Broken Access Control." OWASP Top 10. https://owasp.org/Top10/A01_2021-Broken_Access_Control/
-
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