A security-focused guide to chmod for sysadmins — covering permission models, SUID/SGID auditing, and fixing dangerous world-writable files in web server directories.
What is chmod?
The chmod command changes the access permissions of files and directories on Linux. It controls who — the owner, group, or all other users — can read, write, or execute a given file. On production servers, permission misconfigurations are one of the most exploitable classes of vulnerability: a world-writable file in a web root allows any process running under the web server account to overwrite application code, a SUID binary owned by root can escalate privileges if exploited, and incorrect directory permissions can expose sensitive configuration files to any local user. Understanding and auditing permissions with chmod is not optional — it is a baseline hardening requirement.
Syntax
chmod [options] mode file
chmod 755 /var/www/html/index.php
chmod -R 644 /etc/nginx/conf.d/
chmod u+x,go-wx script.sh
chmod a-s /usr/local/bin/suspicious_binaryMode can be expressed in octal (e.g., 755) or symbolic notation (e.g., u+x). Octal is preferred in scripts for precision. The -R flag applies changes recursively to all files and subdirectories. Symbolic mode uses u (owner), g (group), o (others), a (all), combined with + (add), - (remove), = (set exact).
Key Options and Flags
| Flag / Parameter | Description | Security Note |
|---|---|---|
-R | Apply permission change recursively to all files and subdirectories | Use with caution — applying executable bits to all files in a directory including data files is a common mistake |
-v | Verbose mode — print each file as it is processed | — |
--reference=FILE | Set permissions identical to those of a reference file | — |
4000 (SUID) | Set-User-ID bit — process runs with owner's privileges regardless of who executes it | SUID on root-owned binaries is a privilege escalation vector — audit with find regularly |
2000 (SGID) | Set-Group-ID bit — process runs with group's privileges; on directories, new files inherit the group | SGID on directories can cause unintended group access to newly created files |
1000 (Sticky) | Sticky bit — on directories, only file owner can delete their own files (used on /tmp) | Required on shared writable directories to prevent users from deleting each other's files |
Common Use Cases
Find and Fix All 777 Permissions in a Web Root
World-writable files (777) in a web directory are a critical vulnerability. Any process running on the server — including a compromised web application — can overwrite them. The correct approach is to find all such files, reduce them to 644 for regular files and 755 for directories, then verify no legitimate process was relying on write access for others.
find /var/www/html -perm -0002 -type f -exec chmod o-w {} \;
find /var/www/html -perm -0002 -type d -exec chmod o-w {} \;Audit and Remove SUID/SGID Bits from Unexpected Binaries
SUID binaries run with the file owner’s privileges — if owned by root, they execute as root regardless of who invokes them. An attacker with write access to a SUID binary, or the ability to exploit a vulnerability within one, can escalate to root. Regularly audit all SUID binaries outside expected system paths and remove the bit from anything that does not require it.
find / -perm /4000 -type f 2>/dev/null
find / -perm /6000 -type f 2>/dev/null
chmod a-s /path/to/unexpected_suid_binarySet Secure Permissions on Configuration Files
Configuration files containing passwords, API keys, or connection strings should be readable only by their owning service account and root. A common pattern is 640 (owner read/write, group read, others nothing) for service config files, and 600 for private key files. Applying these consistently reduces exposure if one service account is compromised.
chmod 600 /etc/ssl/private/*.key
chmod 640 /etc/mysql/mysql.conf.d/mysqld.cnf
chmod 700 /root/.sshSecurity Relevance: Permissions as Attack Surface
File permissions are the Linux kernel’s primary access control mechanism. Misconfigured permissions are responsible for a significant proportion of privilege escalation paths on compromised systems. An attacker who gains access as the www-data user can escalate to a more privileged user if they find a world-writable file owned by that user, a SUID binary with a known exploit, or a config file readable by all that contains credentials. The real-world cost of a single world-writable file in a web root is not just defacement — it is full server compromise if the injected file is executed. Regular permission audits using find / -perm -0002 -type f and find / -perm /4000 should be part of every server’s baseline hardening checklist. Treat permission hardening as a first-day task when provisioning a server, not an afterthought.
- Never set 777 permissions on files in web server directories — use 644 for files, 755 for directories
- Any SUID binary outside /bin, /usr/bin, /usr/sbin that you did not deliberately install warrants immediate investigation
- Applying chmod -R 755 to a directory containing private keys or config files with secrets will expose them to all local users
- Config files with 644 permissions are readable by all users on the system — use 640 or 600 for files containing credentials
- The sticky bit is NOT a security feature on files — only on directories (primarily /tmp)
Practical Examples
Recursively set correct web root permissions (files 644, directories 755)
find /var/www/html -type f -exec chmod 644 {} \;
find /var/www/html -type d -exec chmod 755 {} \;This is the standard hardening pattern for a web root. Files are owner-read/write, world-readable only. Directories are traversable by all but writable only by owner. The web server process (www-data) reads but cannot write, preventing content injection via a compromised web app.
Audit all SUID root binaries on the system
find / -user root -perm -4000 -type f -ls 2>/dev/null | sortThis lists every file owned by root with the SUID bit set — the highest-risk class of binary on the system. Compare output against a known-good baseline. Any unexpected entry is a high-priority investigation item, as it represents a potential root escalation path.
Remove world-read from all private key files
find /etc/ssl /home /root -name '*.key' -o -name 'id_rsa' -o -name 'id_ed25519' 2>/dev/null | xargs chmod go-rwxPrivate keys readable by other users or the web server process are a critical vulnerability. This command finds common private key files and strips all group and other permissions. Run after any deployment that touches key material.
Troubleshooting Common Issues
Problem: chmod -R changes permissions on symlinks pointing outside the directory
Solution: Use chmod -R --no-dereference or avoid applying chmod to symlinks directly. Better: use find -not -type l to exclude symlinks from the scope.
Problem: Changed permissions are not taking effect for the web server
Solution: Verify the effective user the web server runs as with ps aux | grep nginx or ps aux | grep apache. The file’s group ownership also matters — use chown www-data:www-data combined with chmod 640 rather than relying on world-readable bits.
Problem: SUID bit set but binary does not run as expected owner
Solution: The SUID bit is silently ignored on shell scripts by the Linux kernel as a security measure. It only functions on compiled ELF binaries. Also verify the filesystem is not mounted with the nosuid option using cat /proc/mounts | grep nosuid.
Summary
Correct file permissions are one of the most effective and underutilized defenses on Linux servers. The chmod command is the primary tool for enforcing the principle of least privilege at the filesystem level. Combine it with find for auditing at scale, apply it systematically during server provisioning, and revisit it after any deployment that modifies directory structures or installs new binaries.
- Web root files should be 644 (files) and 755 (directories) — world-writable is never acceptable
- Audit SUID binaries regularly with
find / -user root -perm -4000 -type f 2>/dev/null— unexpected results require immediate investigation - Config files containing credentials should be 600 or 640, not 644 — world-readable config is a credential exposure risk
Related Commands
chown for file ownership management • find command for security audits • stat for file metadata inspection • chattr to make files immutable
Is Your Server Configured with Least-Privilege Permissions?
INTRAM audits file system permissions as part of every managed Linux server deployment. We harden web roots, audit SUID binaries, and enforce consistent permission policies across your infrastructure.
Get a Security Audit