# 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.

**Severity:** medium | **Category:** Infrastructure Security

---

## The Issue

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.

## Steps 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:cache

This 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.

## Verification

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.

