Laravel File Permissions: How to Fix World-Writable Files and Secure Your Filesystem
Files with 777 or 666 permissions let any user on the server read, write, or execute them. Set restrictive permissions to prevent unauthorized modification.
Unix file permissions control which users and processes can read, write, or execute files. The three permission groups — owner, group, and others — each have read (4), write (2), and execute (1) bits. A permission of 777 grants all three operations to all three groups, including "others" — any user on the system. On a shared hosting server, "others" means every other customer. On a compromised server, "others" means the attacker's code running in any process.
World-writable PHP files are particularly dangerous because they can be modified to inject malicious code. An attacker who gains access to any process on the server — through a compromised plugin on a co-hosted WordPress site, a vulnerability in another tenant's application, or a compromised SSH key — can overwrite your application files, .env, or configuration. PHP files are executed on the next request, making this a route to persistent code execution.
The root cause is almost always a "chmod 777 to fix permissions" shortcut. When a developer encounters a permission error — usually the web server cannot write session files or cache — the path of least resistance is chmod -R 777 storage/. This solves the immediate problem but creates a persistent security weakness. The correct solution is proper group ownership (chown :www-data storage/ with chmod 775) that gives the web server write access to storage/ specifically without granting write access to application code files.
The Problem
World-writable files (permissions 777 or 666) allow any user on the server to read, modify, or execute them. On shared hosting or compromised servers, this means an attacker who gains access to any account can modify your application code, configuration, or data. The most dangerous cases are writable .env files (credential theft), writable PHP files (code injection), and writable config files (application takeover).
How to Fix
-
1
Set correct permissions for Laravel directories
Apply the recommended Laravel permissions:
# Directories: 755 (owner: rwx, group: rx, others: rx) find /var/www/yourapp -type d -exec chmod 755 {} \;# Files: 644 (owner: rw, group: r, others: r) find /var/www/yourapp -type f -exec chmod 644 {} \;# Storage and cache need to be writable by the web server chmod -R 775 storage/ bootstrap/cache/# .env should be readable only by the owner chmod 600 .env -
2
Set correct ownership
Files should be owned by your deploy user, with the web server group:# Set ownership (replace 'deploy' and 'www-data' with your users) chown -R deploy:www-data /var/www/yourapp# Storage needs web server write access chown -R deploy:www-data storage/ bootstrap/cache/Common web server users: - Ubuntu/Debian with Nginx: www-data - Ubuntu/Debian with Apache: www-data - CentOS with Nginx: nginx - Laravel Forge: forge
-
3
Find and fix world-writable files
Search for overly permissive files:
# Find all world-writable files find /var/www/yourapp -perm -o+w -type f -not -path '*/storage/*' -not -path '*/bootstrap/cache/*'# Find all 777 directories find /var/www/yourapp -perm 777 -type dFix any results by applying the correct permissions from step 1.
How to Verify
Run the permission check:
find /var/www/yourapp -perm -o+w -type f -not -path '*/storage/*' -not -path '*/bootstrap/cache/*' -not -path '*/node_modules/*'
This should return no results. Also verify .env permissions:
stat -c '%a %n' .env # Should show 600 .env
Run php artisan stackshield:scan --check=SS022 to verify.
Prevention
Set a umask in your deployment script (umask 022). Use a deployment tool like Envoyer or Forge that sets permissions correctly. Never use chmod 777 as a quick fix — diagnose the actual permission issue instead. Add a permission check to your deployment script.
Frequently Asked Questions
Why does Laravel need storage/ to be writable?
Laravel writes session files, cache data, compiled views, and log files to storage/. The web server process needs write access to these directories. Use 775 with proper group ownership rather than 777.
Is chmod 777 ever acceptable?
No. There is always a better solution. If you need a directory writable by the web server, use proper group ownership (chown :www-data) with 775 permissions. If you need a file writable by a cron job, run the cron as the correct user.
How do I quickly audit file permissions across my entire Laravel installation?
Run find /var/www/yourapp -perm -o+w -type f -not -path "*/storage/*" -not -path "*/bootstrap/cache/*" -not -path "*/node_modules/*" to find world-writable files outside legitimate writable directories. Run find /var/www/yourapp -perm 777 -type d for world-writable directories. Both should return no results. Add these checks to your deployment pipeline as a post-deploy verification step.
What permissions should the public/ directory have?
The public/ directory should be 755 (owner: rwx, group: rx, others: rx) with files at 644. The web server needs read access to serve static files but should never need write access to public/. Uploaded files should be stored in storage/app/public/ and served via the storage symlink, not written directly to public/uploads/.
Is it safe to run the web server as root to avoid permission issues?
Never. Running a web server as root means any vulnerability — a file inclusion bug, a code execution flaw, or a compromised package — executes with full system privileges. The web server user should be www-data or nginx with minimal filesystem permissions. Permission issues should always be resolved through correct ownership and group configuration, not by elevating the web server's privileges.
Related Guides
Laravel .env File Exposed: How to Block Public Access and Rotate Leaked Credentials
Your Laravel .env file is publicly accessible, leaking database credentials, APP_KEY, and API keys. Block it in Apache and Nginx, then rotate every compromised secret.
How to Fix an Exposed Laravel Storage Directory
Your Laravel storage directory is publicly accessible, exposing logs, cache files, and uploaded data. Learn how to restrict access.
Laravel Writable Config Files: How to Set Read-Only Permissions on Configuration
Config files writable by the web server can be modified by an attacker who gains limited access. Set them to read-only to prevent configuration tampering.
Is your Laravel app exposed right now?
34% of Laravel apps we scan have at least one critical issue. Most teams don't find out until something breaks. Our free scan checks your live application in under 60 seconds.