Most hacked WordPress sites I’ve cleaned up didn’t fall to a clever attack. A vulnerable plugin let someone upload a file, and because the web server could write almost anywhere, that file ended up everywhere.
The principle: the web server reads, it doesn’t write
Code files, meaning WordPress core, themes and plugins, should be owned by a deploy user, not the web server user. The web server only needs write access to a short list of folders.
# Code owned by the deploy user: the web server can read, not write
chown -R deploy:deploy /var/www/site
find /var/www/site -type d -exec chmod 755 {} \;
find /var/www/site -type f -exec chmod 644 {} \;
# Only the folders WordPress must write to
chown -R deploy:www-data /var/www/site/wp-content/uploads
find /var/www/site/wp-content/uploads -type d -exec chmod 775 {} \;
find /var/www/site/wp-content/uploads -type f -exec chmod 664 {} \;Which folders need write access
- wp-content/uploads, for media.
- Cache folders used by your caching plugin.
- Log or config folders used by security and firewall plugins.
- Nothing in themes or plugins.
The trade-off
With locked-down code folders, one-click updates from the dashboard stop working. That’s the point: updates go through your deploy process and get tested on staging first.
Belt and braces
- Block PHP from running inside the uploads folder at the web server.
- Make wp-config.php readable only by the users that need it.
- Schedule a check that ownership hasn’t drifted after manual fixes.
Permissions won’t stop every attack, but they turn “the whole server is compromised” into “one folder needs cleaning.”

