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

ImpactDetails
ConfidentialityScope: Confidentiality

Read Application Data - Resources with wrong ownership may be readable by unauthorized users.
IntegrityScope: Integrity

Modify Application Data - Incorrectly owned resources can be modified by unauthorized users.
Access ControlScope: 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

  1. MITRE Corporation. "CWE-708: Incorrect Ownership Assignment." https://cwe.mitre.org/data/definitions/708.html
  2. CWE-282: Improper Ownership Management.
  3. CERT C Coding Standard. "FIO01-C. Be careful using functions that use file names for identification."