Last month, a friend's side project got hacked. The attacker uploaded a PHP shell through a file upload form and executed it. The root cause? Every directory on the server was set to chmod 777.
He told me:
"I kept getting permission denied errors during deployment, so I just 777'd everything."
Sound familiar? Let's fix that.
What chmod Actually Does
chmod (change mode) controls who can read, write, and execute files on Linux. Every file has three permission sets:
- Owner — the user who created the file
- Group — users in the file's group
- Others — everyone else
Each gets a combination of:
| Permission | Symbol | Value | Meaning |
|---|---|---|---|
| Read | r |
4 | View contents |
| Write | w |
2 | Modify/delete |
| Execute | x |
1 | Run as program |
| None | - |
0 | No access |
Add the values to get each digit. So 7 = 4+2+1 (rwx), 5 = 4+1 (r-x), 4 = 4 (r--).
Three digits = owner, group, others. That's it. That's the whole system.
The chmod Cheat Sheet You'll Actually Use
Here's what you need 90% of the time:
chmod 755 script.sh # Scripts & directories
chmod 644 index.html # Regular files (HTML, CSS, images)
chmod 600 .env # Secrets (SSH keys, credentials)
chmod 700 ~/.ssh/ # Private directories
What each one means:
755 (rwxr-xr-x) - Owner can do everything. Everyone else can read and execute but not modify. Use for:
- Shell scripts
- Directories
- Application binaries
644 (rw-r--r--) - Owner can read/write. Everyone else read-only. Use for:
- HTML, CSS, JS files
- Configuration files (non-secret)
- Images and static assets
600 (rw-------) - Owner only. Nobody else can even read the file. Use for:
-
.envfiles - SSH private keys (
~/.ssh/id_rsa) - Database credentials
- API tokens
700 (rwx------) - Like 600 but with execute (for directories). Use for:
-
~/.ssh/directory - Home directories
- Private application folders
I built a free interactive chmod calculator that lets you toggle permissions visually and see the numeric + symbolic notation in real time. Useful when you can't remember if you need 644 or 755.
Why chmod 777 Is Dangerous
777 means everyone can read, write, and execute. Here's why that's a problem:
chmod 777 /var/www/html/
What you think happens: "My deployment script stops getting permission errors."
What actually happens:
- Any user on the system can modify your files
- A web server vulnerability lets attackers write to your directories
- Uploaded files can be executed as code
- Attackers can replace your files with malicious versions
Real-world attack flow:
1. Attacker finds file upload endpoint
2. Uploads malicious.php (or .sh, .py, etc.)
3. Because directory is 777, the file is writable AND executable
4. Attacker visits malicious.php → full server access
5. Game over
If the directory was 755, the uploaded file would be owned by the web server user but not executable by default. The attack chain breaks.
Symbolic Mode: The Safer Way to Change Permissions
Instead of setting all permissions at once (numeric), you can add/remove specific ones:
# Add execute permission for owner only
chmod u+x deploy.sh
# Remove write from group and others
chmod go-w config.yml
# Add read for everyone
chmod a+r README.md
# Remove all permissions from others
chmod o-rwx secret.key
Why this is safer: chmod u+x script.sh only adds execute for the owner. It doesn't touch group or others permissions. With numeric mode, you have to know and set ALL permissions at once.
# These do the same thing, but symbolic is clearer:
chmod 755 script.sh # What was it before? Who knows.
chmod u+x script.sh # Just adding execute for owner. Clear.
Common Scenarios with Exact Commands
Deploying a web app
# Set directory permissions
find /var/www/myapp -type d -exec chmod 755 {} \;
# Set file permissions
find /var/www/myapp -type f -exec chmod 644 {} \;
# Make scripts executable
chmod 755 /var/www/myapp/scripts/*.sh
# Lock down .env
chmod 600 /var/www/myapp/.env
Setting up SSH keys
chmod 700 ~/.ssh/
chmod 600 ~/.ssh/id_rsa # Private key (SSH REQUIRES this)
chmod 644 ~/.ssh/id_rsa.pub # Public key
chmod 600 ~/.ssh/authorized_keys
chmod 644 ~/.ssh/known_hosts
SSH will refuse to use your key if the private key has permissions looser than 600. This is intentional - it's protecting you.
Not sure what your current numeric permission translates to?
Paste the number into the ToolZip Chmod Calculator to see
the exact read/write/execute breakdown.
Docker volumes
# Container needs read/execute on the mounted directory
chmod -R 755 ./docker-data/
# But secrets inside should be locked down
chmod 600 ./docker-data/certs/*.pem
CI/CD pipeline
# Make all scripts in your pipeline executable
chmod +x ./scripts/*.sh
chmod +x ./hooks/pre-commit
Quick Security Audit
Run these commands on your server right now:
# Find all 777 files (fix every single one)
find / -perm -777 -type f 2>/dev/null
# Find all 777 directories
find / -perm -777 -type d 2>/dev/null
# Find SUID files (programs that run as root)
find / -perm -4000 -ls 2>/dev/null
# Check your web root specifically
ls -la /var/www/
If find / -perm -777 returns anything in your web root, fix it immediately.
The Permission Decision Flowchart
When you're not sure what permission to use:
Is it a secret (passwords, keys, tokens)?
→ 600
Is it a directory?
→ 755 (or 700 if private)
Is it an executable script?
→ 755
Is it a regular file?
→ 644
Should nobody but the owner access it?
→ 600 (file) or 700 (directory)
Are you tempted to use 777?
→ Stop. Use 755 and fix the actual problem.
Tools That Help
- ToolZip Chmod Calculator - Toggle permissions visually, see numeric + symbolic notation, common presets for quick reference
- ToolZip Hash Generator - Verify file integrity after permission changes with MD5/SHA-256 checksums
- ToolZip Cron Expression Generator - Schedule automated permission audits with cron jobs
-
ls -la- Your best friend for checking current permissions -
stat filename- Detailed file information including permissions in octal
TL;DR
| Use Case | Permission | Command |
|---|---|---|
| Regular files | 644 | chmod 644 file.html |
| Scripts & directories | 755 | chmod 755 script.sh |
| Secrets & credentials | 600 | chmod 600 .env |
| Private directories | 700 | chmod 700 ~/.ssh/ |
| Never in production | Don't. |
What To Do Right Now
If you're running a Linux server, SSH into it and run this:
find / -perm -777 -type f 2>/dev/null | head -20
If that returns anything — especially in /var/www/ — you have a
problem. Fix it with the permission values from the cheat sheet
above before someone else finds it first.
Stop chmod 777-ing everything. Use 755 for scripts and directories, 644 for files, 600 for secrets. That covers 95% of cases.
If you want to play around with permissions without risk, try the chmod calculator - toggle checkboxes and see exactly what each number means.
Originally published at toolzip.xyz/blog/chmod-permissions-explained
Top comments (0)