This weakness occurs when software copies, restores, or transfers a file but fails to preserve its original access permissions. The result is that a file may…
This weakness occurs when software copies, restores, or transfers a file but fails to preserve its original access permissions. The result is that a file may become readable, writable, or executable by users who should not have access to it. This can expose sensitive data, allow unauthorized modification, or enable privilege escalation depending on what the file contains and who gains access.
02How It Happens
When a file is copied or restored, the operating system and application must explicitly preserve the original file's permission metadata (ownership, read/write/execute bits, ACLs, or SELinux contexts). If the code performing the copy operation does not explicitly transfer these permissions—or if it uses a default umask that strips them—the new file may inherit overly permissive defaults. This is especially dangerous during backup restoration, file migration, or when moving files between directories or systems where permission inheritance rules differ.
The vulnerability often arises because developers focus on copying file *content* but overlook permission *metadata*. Some APIs copy content by default but require explicit flags to preserve permissions; others silently apply the current process's umask, masking sensitive bits. In multi-user or containerized environments, this can quickly expose private keys, configuration files, or application secrets.
03Real-World Impact
An attacker or unprivileged user may read sensitive files (private keys, database credentials, source code) that were intended to be restricted. In some cases, world-writable files can be modified or replaced, leading to code execution or data corruption. Backup restoration is a common trigger: a database dump or configuration archive restored with default permissions might become readable by all users on the system, or a script restored as world-executable could be hijacked. The impact scales with the sensitivity of the file and the number of users on the system.
04Vulnerable & Fixed Patterns
Vulnerable pattern
import shutil
import os
# Backup a sensitive config file
source = "/etc/app/secrets.conf"
backup = "/tmp/secrets.conf.bak"
# Copy file content only; permissions are NOT preserved
shutil.copy(source, backup)
# Later, restore from backup
shutil.copy(backup, source)
# The restored file may have default permissions (e.g., 0o644)
# instead of the original restrictive permissions (e.g., 0o600)
Why it's vulnerable: shutil.copy() copies file content and basic metadata but does not preserve all permission bits; the new file inherits the current umask. If the original file was readable only by root (0o600), the copy may become world-readable (0o644).
Fixed pattern
import shutil
import os
import stat
source = "/etc/app/secrets.conf"
backup = "/tmp/secrets.conf.bak"
# Copy file and preserve all metadata, including permissions
shutil.copy2(source, backup)
# Alternatively, for explicit control:
shutil.copyfile(source, backup)
src_stat = os.stat(source)
os.chmod(backup, stat.S_IMODE(src_stat.st_mode))
os.chown(backup, src_stat.st_uid, src_stat.st_gid)
Vulnerable pattern
<?php
// Backup a sensitive configuration file
$source = "/var/www/app/config.php";
$backup = "/tmp/config.php.bak";
// Copy file content only
copy($source, $backup);
// Later, restore from backup
copy($backup, $source);
// The restored file inherits the web server's umask,
// potentially becoming world-readable or world-writable
?>
Why it's vulnerable: PHP's copy() function does not preserve the source file's permissions. The destination file is created with the default umask, which may be overly permissive (e.g., 0o644 instead of 0o600).
Use file copy functions that explicitly preserve metadata: shutil.copy2() in Python, or manually call chmod() and chown() after copy() in PHP.
When restoring from backups, verify that restored files have the correct permissions before bringing them into production.
Set a restrictive umask (e.g., 0o077) in your application or deployment scripts so that newly created files default to private permissions.
Document the expected permissions for all sensitive files (keys, configs, credentials) and include permission checks in deployment automation.
Test backup and restore procedures in a staging environment to confirm that permissions are preserved end-to-end.
Use version control or configuration management tools that track and enforce file permissions as part of the deployment process.
06Signs You May Already Be Affected
Check file permissions on sensitive files after a backup restore or file migration. Use ls -la (Linux/macOS) or icacls (Windows) to verify that permissions match the original. Look for unexpected world-readable or world-writable bits on private keys, configuration files, or application secrets. Review backup and restore logs for any warnings about permission mismatches or umask changes.