Unverified Ownership
Description
Unverified Ownership is a vulnerability that occurs when a product does not properly verify that a critical resource is owned by the proper entity before allowing access or manipulation. This weakness represents the failure to confirm that the actor requesting an operation actually owns the target resource. Unlike general authorization checks that verify permissions, ownership verification specifically confirms that the resource belongs to the requesting party. This is critical for operations like process termination, file deletion, or resource deallocation where acting on another entity's resources could cause significant harm.
Risk
Failure to verify ownership before resource operations creates significant privilege escalation and denial of service risks. Attackers can terminate other users' processes, delete files they don't own, or deallocate resources belonging to other principals. In multi-user systems, this enables cross-user attacks where one user can disrupt or compromise another's work. Unix socket operations without ownership verification can expose passwords transmitted between processes. Access to special device files without ownership checks can lead to root access. The risk is particularly severe for destructive operations that cannot be undone, and for shared resources where ownership confusion leads to privilege escalation.
Solution
Always verify resource ownership before allowing access or modification operations. Before terminating a process, verify that the requesting user owns that process. Before modifying or deleting files, confirm file ownership matches the requesting user. Implement ownership checks as a mandatory step in resource access control, separate from but complementary to permission checks. Use platform-provided ownership verification mechanisms (stat() for files, /proc for processes) rather than implementing custom checks. For sensitive resources like Unix sockets, verify both endpoints of the connection own their respective objects. Apply the separation of privilege principle by requiring multiple conditions before permitting resource access. Log ownership verification failures for security monitoring.
Common Consequences
| Impact | Details |
|---|---|
| Access Control | Scope: Access Control Attackers could gain unauthorized access to system resources by bypassing ownership verification. This enables privilege escalation, cross-user attacks, denial of service through resource destruction, and unauthorized access to sensitive data or functionality. |
Example Code
Vulnerable Code (Python)
The following examples demonstrate unverified ownership vulnerabilities:
# Vulnerable: Process killing without ownership check
import os
import signal
def vulnerable_kill_process(process_id):
# Vulnerable: No verification of process ownership
os.kill(process_id, signal.SIGKILL)
# Any user can kill any process!
def vulnerable_delete_file(file_path):
# Vulnerable: No ownership verification
if os.path.exists(file_path):
os.remove(file_path)
# User can delete files they don't own
class VulnerableSessionManager:
def terminate_session(self, session_id):
# Vulnerable: Doesn't verify session ownership
session = self.sessions.get(session_id)
if session:
session.terminate()
# Any user can terminate any session
// Vulnerable: C program without ownership verification
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
void vulnerable_kill(pid_t pid) {
// Vulnerable: No ownership check
kill(pid, SIGKILL);
// Kills any process if permissions allow
}
int vulnerable_socket_auth(int socket_fd) {
// Vulnerable: Doesn't verify socket owner
char password[256];
read(socket_fd, password, sizeof(password));
// Attacker could create socket and receive password
// intended for another process
return verify_password(password);
}
int vulnerable_device_access(const char *device_path) {
// Vulnerable: No ownership verification for special device
int fd = open(device_path, O_RDWR);
if (fd >= 0) {
// User gains access to device they may not own
ioctl(fd, PRIVILEGED_OPERATION, NULL);
close(fd);
}
return 0;
}
// Vulnerable: Java without ownership verification
public class VulnerableResourceManager {
public void terminateThread(long threadId) {
// Vulnerable: No ownership verification
Thread thread = findThread(threadId);
if (thread != null) {
thread.interrupt();
}
// Can interrupt threads owned by other components
}
public void deleteUserFile(String userId, String fileId) {
// Vulnerable: Uses userId from request without verification
File file = fileRepository.findById(fileId);
fileRepository.delete(file);
// Doesn't verify that userId actually owns the file
}
}
Fixed Code (Python)
# Fixed: Process killing with ownership verification
import os
import signal
def get_process_owner(pid):
"""Get the UID of the process owner from /proc"""
try:
with open(f'/proc/{pid}/status', 'r') as f:
for line in f:
if line.startswith('Uid:'):
return int(line.split()[1]) # Real UID
except (FileNotFoundError, PermissionError, ValueError):
return None
return None
def secure_kill_process(process_id):
"""Kill process only after verifying ownership"""
current_uid = os.getuid()
process_owner = get_process_owner(process_id)
if process_owner is None:
raise ProcessNotFoundError(f"Process {process_id} not found")
# Fixed: Verify ownership before killing
if process_owner != current_uid:
raise PermissionError(
f"Cannot kill process {process_id}: "
f"owned by UID {process_owner}, not current user"
)
os.kill(process_id, signal.SIGKILL)
def secure_delete_file(file_path, requesting_uid):
"""Delete file only after verifying ownership"""
try:
stat_info = os.stat(file_path)
except FileNotFoundError:
raise FileNotFoundError(f"File not found: {file_path}")
# Fixed: Verify ownership
if stat_info.st_uid != requesting_uid:
raise PermissionError(
f"Cannot delete {file_path}: "
f"owned by UID {stat_info.st_uid}, not {requesting_uid}"
)
os.remove(file_path)
class SecureSessionManager:
def terminate_session(self, session_id, requesting_user):
"""Terminate session only if owned by requesting user"""
session = self.sessions.get(session_id)
if session is None:
raise SessionNotFoundError(session_id)
# Fixed: Verify session ownership
if session.owner_id != requesting_user.id:
# Check for admin override
if not requesting_user.has_role('admin'):
raise PermissionError(
f"User {requesting_user.id} does not own session {session_id}"
)
session.terminate()
// Fixed: C program with ownership verification
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
uid_t get_process_owner(pid_t pid) {
char path[256];
struct stat st;
snprintf(path, sizeof(path), "/proc/%d", pid);
if (stat(path, &st) != 0) {
return (uid_t)-1;
}
return st.st_uid;
}
int secure_kill(pid_t pid) {
uid_t current_uid = getuid();
uid_t process_owner = get_process_owner(pid);
if (process_owner == (uid_t)-1) {
fprintf(stderr, "Process %d not found\n", pid);
return -1;
}
// Fixed: Verify ownership
if (process_owner != current_uid) {
fprintf(stderr, "Cannot kill process %d: owned by UID %d\n",
pid, process_owner);
return -1;
}
return kill(pid, SIGKILL);
}
int secure_socket_auth(int socket_fd) {
struct stat socket_stat;
uid_t current_uid = getuid();
// Fixed: Verify socket ownership before receiving sensitive data
if (fstat(socket_fd, &socket_stat) != 0) {
return -1;
}
if (socket_stat.st_uid != current_uid) {
fprintf(stderr, "Socket not owned by current user\n");
return -1;
}
char password[256];
read(socket_fd, password, sizeof(password));
return verify_password(password);
}
int secure_device_access(const char *device_path, uid_t expected_owner) {
struct stat device_stat;
// Fixed: Verify device ownership before access
if (stat(device_path, &device_stat) != 0) {
return -1;
}
if (device_stat.st_uid != expected_owner) {
fprintf(stderr, "Device not owned by expected user\n");
return -1;
}
int fd = open(device_path, O_RDWR);
if (fd >= 0) {
ioctl(fd, PRIVILEGED_OPERATION, NULL);
close(fd);
}
return 0;
}
// Fixed: Java with ownership verification
public class SecureResourceManager {
public void terminateThread(User requester, long threadId) {
Thread thread = findThread(threadId);
if (thread == null) {
throw new ThreadNotFoundException(threadId);
}
// Fixed: Verify thread ownership through thread context
ThreadOwnership ownership = threadRegistry.getOwnership(threadId);
if (!ownership.getOwnerId().equals(requester.getId())) {
throw new UnauthorizedAccessException(
"User " + requester.getId() + " does not own thread " + threadId
);
}
thread.interrupt();
}
public void deleteUserFile(User requester, String fileId) {
File file = fileRepository.findById(fileId)
.orElseThrow(() -> new FileNotFoundException(fileId));
// Fixed: Verify ownership from file record, not request
if (!file.getOwnerId().equals(requester.getId())) {
auditLog.logUnauthorizedAccess(requester, "delete_file", fileId);
throw new UnauthorizedAccessException(
"User does not own file " + fileId
);
}
fileRepository.delete(file);
auditLog.logFileDeletion(requester, fileId);
}
}
The fix verifies that the requesting user owns the target resource before allowing the operation.
Exploited in the Wild
Unix Socket Password Exposure (Unix Systems, Historical)
CVE-2001-0178 documented UNIX socket communications where ownership was not verified, allowing attackers to receive passwords intended for other processes by creating sockets with predictable names.
Special Device Access (Unix Systems, Historical)
CVE-2004-2012 documented special device file access without ownership verification, enabling unauthorized users to gain root access through improperly protected device nodes.
Process Termination Attacks (Multi-user Systems, Ongoing)
Applications that terminate processes without ownership verification have been exploited for denial of service attacks where users kill other users' or system processes.
Tools to Test/Exploit
-
ps/pgrep — Process listing tools for identifying process ownership.
-
stat — File status tool for checking resource ownership.
-
lsof — Tool for listing open files and sockets with ownership information.
CVE Examples
-
CVE-2001-0178 — UNIX socket owner not verified for password transmission.
-
CVE-2004-2012 — Special device owner unchecked, enabling root access.
References
-
MITRE Corporation. "CWE-283: Unverified Ownership." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/283.html
-
OWASP Foundation. "Broken Access Control." OWASP Top 10 2021. https://owasp.org/Top10/A01_2021-Broken_Access_Control/
-
CERT C Secure Coding Standard. "FIO16-C. Canonicalize path names before validating them." https://wiki.sei.cmu.edu/confluence/display/c/FIO16-C