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.
Configuration files in config/ define your application's behavior: database connections, mail credentials, cache drivers, file storage backends, queue connections, and security settings. If these files are writable by the web server process, an attacker who gains limited code execution — through a file upload vulnerability, a deserialization attack, or a compromised Composer package — can modify them to redirect connections to attacker-controlled infrastructure.
The defense-in-depth principle is at work here. No single security control is perfect. A web application might have file upload validation, but a zero-day in an image processing library could bypass it. If config files are writable, a successful exploit of any vulnerability immediately escalates to configuration takeover. If config files are read-only (owned by the deploy user, not the web server user), the attacker's access is significantly limited even after initial compromise. Restrictive file permissions minimize the blast radius of other vulnerabilities.
This vulnerability class is particularly relevant in shared hosting environments and VPS setups where deployment is done manually. When a developer runs composer install or php artisan commands as the web server user, the created files inherit that user's ownership, making them writable by the web server. Proper deployment practice runs deployment commands as a dedicated deploy user with the web server in the same group — achieving the necessary read access for the web server without granting write access.
The Problem
If your config/ directory or individual configuration files are writable by the web server user (www-data, nginx, etc.), an attacker who gains limited code execution — through a file upload vulnerability, deserialization attack, or compromised dependency — can modify your application configuration. They could change the database connection to their own server, redirect mail to their address, disable security features, or add their own service credentials.
How to Fix
-
1
Set config files to read-only
Make config files readable but not writable by the web server:
chmod 644 config/*.php chmod 755 config/# Verify ls -la config/ # Files should show -rw-r--r-- (644) # Directory should show drwxr-xr-x (755)The web server needs to read config files but never write them.
-
2
Set correct ownership
Config files should be owned by your deploy user, not the web server:
chown -R deploy:www-data config/# deploy user can read/write (for deployments) # www-data group can only read (for serving)This way, even if the web server process is compromised, it cannot modify configuration.
-
3
Use config:cache in production
Cached configuration is loaded from a single compiled file, reducing filesystem access:
php artisan config:cacheThis creates bootstrap/cache/config.php. In production, Laravel reads this cached file instead of scanning the config/ directory. This also provides a small performance benefit.
Run php artisan config:cache as part of every deployment.
How to Verify
Check file permissions:
find config/ -type f -perm -o+w
This should return no results. Also verify the web server user cannot write:
sudo -u www-data touch config/test.php 2>&1
# Should output: Permission denied
Run php artisan stackshield:scan --check=SS057 to verify.
Prevention
Set permissions in your deployment script. Use config:cache to minimize filesystem access. Never run artisan commands as the web server user in production. Include permission checks in your deployment pipeline.
Frequently Asked Questions
What about .env — should it be read-only too?
Yes. The .env file should be 600 (owner read/write only) or 640 (owner read/write, group read). The web server needs to read it (or it is read once during config:cache), but it should never be writable by the web server process.
Does config:cache make config files completely unnecessary?
No. The config files are still needed for: (1) generating the cache (config:cache reads them), (2) local development (where you typically do not cache config), and (3) re-caching after .env changes. Keep them in your deployment but with read-only permissions.
What if my deployment process needs to modify config files?
Config files should not be modified during deployment. If you are templating config values directly into PHP files during deployment, this is an anti-pattern. Use .env variables and config() references instead. Configuration should come from environment variables read at runtime, not from deployment-time file modification that requires the files to be writable.
Is it safe to run php artisan config:cache as the www-data user?
No. Artisan commands that write to the filesystem (config:cache, route:cache, view:cache) should be run as the deploy user, not as the web server user. When run as www-data, the cached files are owned by www-data, which means the web server can later overwrite them — creating the exact writable-config vulnerability this guide addresses. Run all deployment commands as your deploy user.
Which config files are most dangerous if writable by the web server?
The highest-risk config files are: config/database.php (allows redirecting all queries to an attacker's database), config/mail.php (allows capturing all outbound email), config/filesystems.php (allows redirecting file storage to attacker-controlled location), and config/logging.php (allows hiding attacker activity by redirecting logs). Any config file that defines an external connection endpoint is high-value for post-compromise escalation.
Related Security Terms
Related Guides
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.
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.
Laravel Debug Mode in Production: How to Disable APP_DEBUG and Stop Leaking Secrets
APP_DEBUG=true in production exposes stack traces, environment variables, and database credentials to anyone who triggers an error. Here is how to disable it safely and verify the fix.
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.