Incorrect Ownership Assignment
Description
Incorrect Ownership Assignment is a vulnerability where software assigns an owner to a resource that is outside the intended control sphere. When resource ownership is improperly assigned to the wrong user, group, or entity, it creates pathways for unauthorized actors to access, modify, or delete resources they should not have control over. This commonly occurs with file ownership during installation, process ownership after privilege changes, or database object ownership during creation. The misconfigured ownership undermines the security model protecting the resource.
Risk
Incorrect ownership assignment creates privilege escalation and unauthorized access vulnerabilities. Files owned by unprivileged users can be modified to inject malicious code that executes with elevated privileges when the files are later used by system processes. Resources with incorrect group ownership may be accessible to unintended users in that group. Symbolic link ownership issues can enable attackers to manipulate link targets. During logout or session changes, failure to restore proper ownership can leave resources accessible to subsequent users. The risk extends to configuration files, executables, data files, and any resource where ownership determines access rights.
Solution
Set correct ownership immediately upon resource creation. Verify ownership settings during installation and deployment. Use principle of least privilege—assign ownership to the most restricted entity that still allows proper operation. Periodically audit resource ownership and permissions. When handling symbolic links, be explicit about whether operations affect the link or the target. Restore proper ownership after privilege operations complete. Use configuration management tools to enforce correct ownership across systems. Test ownership settings as part of security verification.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Read Application Data - Resources with wrong ownership may be readable by unauthorized users. |
| Integrity | Scope: Integrity Modify Application Data - Incorrectly owned resources can be modified by unauthorized users. |
| Access Control | Scope: Access Control Gain Privileges or Assume Identity - Ownership errors can enable privilege escalation. |
Example Code
Vulnerable Code
// Vulnerable: File created with wrong ownership
#include <stdio.h>
#include <sys/stat.h>
#include <pwd.h>
#include <unistd.h>
void vulnerable_create_config() {
// Create configuration file
FILE* f = fopen("/etc/myapp/config.conf", "w");
if (f) {
fprintf(f, "setting=value\n");
fclose(f);
}
// Vulnerable: File is owned by whoever runs this code
// If run as root, it's root-owned
// If installer runs as different user, ownership is wrong
// Even worse: explicitly setting wrong ownership
struct passwd* nobody = getpwnam("nobody");
if (nobody) {
// Vulnerable: Critical config owned by 'nobody'
// Any process running as 'nobody' can modify it
chown("/etc/myapp/config.conf", nobody->pw_uid, nobody->pw_gid);
}
}
// Vulnerable: Symbolic link ownership confusion
void vulnerable_symlink_chown(const char* path, uid_t uid, gid_t gid) {
// Vulnerable: chown follows symlinks!
// If path is a symlink, this changes ownership of the TARGET
chown(path, uid, gid);
// Attacker creates symlink to /etc/passwd, we change its ownership
}
# Vulnerable: Installation script with wrong ownership
import os
import shutil
def vulnerable_install():
# Create application directory
app_dir = "/opt/myapp"
os.makedirs(app_dir, exist_ok=True)
# Copy binary
shutil.copy("myapp", os.path.join(app_dir, "myapp"))
# Vulnerable: Set ownership to unprivileged user for writability
# But this binary might be executed by root!
os.chown(os.path.join(app_dir, "myapp"), 1000, 1000) # uid 1000
# Attacker (uid 1000) can now replace the binary
# When root runs it, attacker's code executes as root
# Vulnerable: Database ownership (CVE-2003-0265 pattern)
def vulnerable_create_db():
import sqlite3
# Create database with default permissions
db_path = "/var/lib/myapp/data.db"
conn = sqlite3.connect(db_path)
# Vulnerable: Database file created with current user's ownership
# If running as root, file is world-readable
# If running as web user, might be accessible to other web apps
conn.execute("CREATE TABLE secrets (key TEXT, value TEXT)")
conn.close()
#!/bin/bash
# Vulnerable: Installation script with ownership issues
# Vulnerable: Create directories with wrong ownership
mkdir -p /opt/myapp/bin
mkdir -p /opt/myapp/logs
# Vulnerable: Make bin directory owned by regular user
# CVE-2007-4238 pattern - binary can be replaced
chown -R myuser:mygroup /opt/myapp/bin
# Vulnerable: Log directory world-writable
chmod 777 /opt/myapp/logs
# Any user can write or delete logs, potentially hiding attacks
# Vulnerable: Config file with wrong group
chown root:users /etc/myapp.conf
chmod 660 /etc/myapp.conf
# All users in 'users' group can modify config
// Vulnerable: Java file creation with wrong ownership
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
public class VulnerableOwnership {
public void vulnerableCreateFile() throws IOException {
Path path = Paths.get("/tmp/myapp/sensitive.dat");
// Create file - ownership determined by process user
Files.createFile(path);
// Vulnerable: Set ownership to specific user without validation
UserPrincipal user = path.getFileSystem()
.getUserPrincipalLookupService()
.lookupPrincipalByName("daemon");
// Changing to 'daemon' user - but why?
// This service account might be shared by multiple applications
Files.setOwner(path, user);
}
}
Fixed Code
// Fixed: Proper ownership assignment
#include <stdio.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <fcntl.h>
void secure_create_config() {
// Fixed: Drop privileges before creating if running as root
// Or create with explicit ownership
// Get the intended owner
struct passwd* app_user = getpwnam("myapp");
struct group* app_group = getgrnam("myapp");
if (!app_user || !app_group) {
return; // Application user/group must exist
}
// Create file with restrictive permissions
int fd = open("/etc/myapp/config.conf",
O_CREAT | O_WRONLY | O_TRUNC,
S_IRUSR | S_IWUSR); // 600 - owner only
if (fd < 0) return;
// Fixed: Set correct ownership for application
fchown(fd, app_user->pw_uid, app_group->gr_gid);
write(fd, "setting=value\n", 14);
close(fd);
}
// Fixed: Use lchown for symlink-safe ownership change
void secure_symlink_chown(const char* path, uid_t uid, gid_t gid) {
struct stat st;
// Fixed: Check if it's a symlink first
if (lstat(path, &st) == 0) {
if (S_ISLNK(st.st_mode)) {
// Fixed: Use lchown to change link ownership, not target
lchown(path, uid, gid);
} else {
// Regular file - safe to use chown
chown(path, uid, gid);
}
}
}
// Alternative: Refuse to operate on symlinks
void secure_chown_no_symlinks(const char* path, uid_t uid, gid_t gid) {
struct stat st;
if (lstat(path, &st) != 0) return;
if (S_ISLNK(st.st_mode)) {
// Fixed: Don't change ownership through symlinks
fprintf(stderr, "Refusing to chown symlink: %s\n", path);
return;
}
chown(path, uid, gid);
}
# Fixed: Proper installation with correct ownership
import os
import shutil
import pwd
import grp
import stat
def secure_install():
app_dir = "/opt/myapp"
# Get correct user/group
app_user = pwd.getpwnam("myapp")
app_group = grp.getgrnam("myapp")
# Create directory with correct ownership
os.makedirs(app_dir, exist_ok=True)
os.chown(app_dir, app_user.pw_uid, app_group.gr_gid)
os.chmod(app_dir, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP) # 750
# Copy binary
bin_path = os.path.join(app_dir, "myapp")
shutil.copy("myapp", bin_path)
# Fixed: Binary owned by root, not modifiable by app user
os.chown(bin_path, 0, 0) # root:root
os.chmod(bin_path, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP |
stat.S_IROTH | stat.S_IXOTH) # 755
# Create data directory owned by app user
data_dir = os.path.join(app_dir, "data")
os.makedirs(data_dir, exist_ok=True)
os.chown(data_dir, app_user.pw_uid, app_group.gr_gid)
os.chmod(data_dir, stat.S_IRWXU) # 700 - only app user
# Fixed: Secure database creation
def secure_create_db():
import sqlite3
import tempfile
db_path = "/var/lib/myapp/data.db"
db_dir = os.path.dirname(db_path)
# Ensure directory exists with correct permissions
os.makedirs(db_dir, mode=0o700, exist_ok=True)
# Get application user
app_user = pwd.getpwnam("myapp")
os.chown(db_dir, app_user.pw_uid, app_user.pw_gid)
# Create database
conn = sqlite3.connect(db_path)
conn.execute("CREATE TABLE IF NOT EXISTS secrets (key TEXT, value TEXT)")
conn.close()
# Fixed: Set correct ownership and permissions
os.chown(db_path, app_user.pw_uid, app_user.pw_gid)
os.chmod(db_path, stat.S_IRUSR | stat.S_IWUSR) # 600
#!/bin/bash
# Fixed: Secure installation script
# Create directories with correct ownership
mkdir -p /opt/myapp/bin
mkdir -p /opt/myapp/logs
mkdir -p /opt/myapp/data
# Fixed: Binaries owned by root, not modifiable
chown root:root /opt/myapp/bin
chmod 755 /opt/myapp/bin
# Fixed: Logs owned by application user, restricted permissions
chown myapp:myapp /opt/myapp/logs
chmod 750 /opt/myapp/logs # Only owner and group can access
# Fixed: Data directory owned by application user
chown myapp:myapp /opt/myapp/data
chmod 700 /opt/myapp/data # Only application user
# Fixed: Config owned by root, readable by app group
chown root:myapp /etc/myapp.conf
chmod 640 /etc/myapp.conf # root writes, myapp group reads
// Fixed: Java with proper ownership consideration
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
public class SecureOwnership {
public void secureCreateFile(String expectedOwner) throws IOException {
Path path = Paths.get("/var/lib/myapp/data.dat");
// Fixed: Create with restrictive permissions first
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-------");
FileAttribute<Set<PosixFilePermission>> attr =
PosixFilePermissions.asFileAttribute(perms);
Files.createFile(path, attr);
// Fixed: Verify ownership matches expected
UserPrincipal currentOwner = Files.getOwner(path);
if (!currentOwner.getName().equals(expectedOwner)) {
// Only change if necessary and validate the target
if (isValidApplicationUser(expectedOwner)) {
UserPrincipal newOwner = path.getFileSystem()
.getUserPrincipalLookupService()
.lookupPrincipalByName(expectedOwner);
Files.setOwner(path, newOwner);
} else {
throw new SecurityException("Invalid owner: " + expectedOwner);
}
}
}
private boolean isValidApplicationUser(String username) {
// Only allow specific application users
return "myapp".equals(username) || "myapp-worker".equals(username);
}
}
CVE Examples
- CVE-2024-43199: Binaries installed with insecure user/group ownership, allowing modification.
- CVE-2007-4238: Program installed with bin owner, allowing users to modify executable.
- CVE-2007-1716: Resource ownership not restored on logout, enabling privilege escalation.
- CVE-2005-3148: Symbolic links restored with incorrect uid/gid.
- CVE-2005-1064: Ownership changed on symlink targets instead of symlinks themselves.
References
- MITRE Corporation. "CWE-708: Incorrect Ownership Assignment." https://cwe.mitre.org/data/definitions/708.html
- CWE-282: Improper Ownership Management.
- CERT C Coding Standard. "FIO01-C. Be careful using functions that use file names for identification."