Secure file permissions are the quiet foundation of access control on a website. Get them wrong and you give attackers persistence, lateral movement, and somewhere to stash tooling. Get them right and a compromised plugin, stolen password, or dodgy upload has far less room to spread, because the filesystem simply won’t cooperate.
File permissions are not “security settings”. They’re operating rules.
Keep control over who can change what, because Linux enforces it at the filesystem layer. On Linux hosting (which covers most business hosting), every file and folder has an owner, a group, and a set of permissions. Those permissions decide who can read, write, or execute a file. The web server user (often www data, apache, nginx, or a per account user on managed platforms) is just another user on the system. Your CMS, your FTP/SFTP user, your deployment user, and background processes are also “users”.
Limit write access to the places that genuinely need it, because “the website” doesn’t need to write everywhere. It needs write access in a few specific locations. When everything is writable because it’s convenient, you’re not just smoothing updates. You’re also giving malware the same convenience.
What actually goes wrong in the real world
1) Writable sensitive files
Protect secrets from both disclosure and tampering, because config files are high-value targets. The classic example is a configuration file that holds database credentials or API keys. On WordPress that’s wp-config.php. On Laravel it’s often .env. On many stacks it’s a mix of config files and “temporary” secret dumps that never get cleaned up. If those files are world-readable, you risk disclosure. If they’re writable by the web server, you risk an attacker editing them to add a backdoor, change database endpoints, or inject code via autoloaders.
Reduce easy wins for attackers, because permissions won’t solve every secret management issue, but they do shut down the low-effort paths attackers try first.
2) Shared access that blurs accountability
Keep traceability intact, because shared logins destroy accountability. If multiple people log in via the same FTP account, or you’re using a shared cPanel login across a team, you lose traceability. You also tend to set permissions wider than needed because nobody wants to be the person who “broke the site” by tightening things up. That’s how you end up with 777 folders and a web server that can write into places it should never touch.
Make access rotatable, because access control isn’t just permissions. It’s also who has the keys, and whether you can rotate those keys without taking the business offline.
3) Malware persistence after a cleanup
Stop reinfection at the source, because persistence is usually boring, not brilliant. Most persistent reinfections we see aren’t sophisticated. They’re repetitive. A single writable directory outside the normal upload path, a scheduled task that can be edited by the web user, or a plugin directory left writable so the attacker can drop a loader that survives updates. You remove the visible payload, the loader stays, and it phones home again.
If you want the broader context of how this keeps evolving, website security trends now and in the future is worth a read. The patterns are consistent. The delivery method changes. The “write access in the wrong place” problem stays the same.
Understanding the numbers: 644, 755, 600 and why 777 is a flare gun
Read permissions quickly and correctly, because the numbers are just a compact encoding. Permissions are usually shown as three digits. Each digit is a sum of read (4), write (2), and execute (1). The digits represent owner, group, and everyone else.
Apply sensible defaults, because the meaning differs between files and directories. For files, 644 means the owner can read/write, everyone else can read. For directories, 755 means the owner can read/write/enter, everyone else can read/enter. “Execute” on a directory really means “traverse”. Without it, you can’t access files inside even if you can read the directory listing.
Treat 777 as a red flag, because it means anyone can write. On shared hosting, that’s not just “your team”. That’s any process that can reach the filesystem in the context of the server. It’s effectively permission to persist.
The principle that matters: the web server should write to as little as possible
Contain damage by default, because write access is what turns a bug into a foothold. Most CMS stacks only need write access for uploads, caching, and sometimes updates. The security posture changes drastically depending on whether you allow the application to update itself.
Prefer controlled deployments, because in app updates expand the blast radius. If you allow in app updates, the web server needs to write into plugin/theme/core directories. That’s convenient, but it also means that any remote code execution vulnerability becomes “write arbitrary PHP into the codebase”. If you disable in app updates and deploy changes via SFTP/SSH/CI, you can keep the codebase read only to the web server, which is a major containment win.
Build resilience into infrastructure, because this is an “infrastructure beats heroics” decision. It’s not about trusting your CMS. It’s about limiting blast radius when something upstream fails.
Backups don’t fix write access problems
Build recovery into the foundation, because the moment permissions allow persistence, backups can become a liability as well as a safety net. If malware can write into your backup scope, you can end up with clean looking archives that are already contaminated, and a restore that reintroduces the same foothold.
Protect Technical Integrity by treating backup security as restore infrastructure, not just storage, and by validating what you can actually bring back under pressure. We unpack that restore first approach in Backup Security: Why Restores Matter More Than Backups.
Permissions are one layer, exposure is the other
Cut down what can be written, because file permissions only protect the infrastructure you still expose. A locked down filesystem does not help if old plugins, forgotten endpoints, and test pages are still reachable and feeding attackers reliable entry points that lead to persistence.
Reduce those citations and keep technical integrity intact by decommissioning what you do not use. We break that process down in How to Disable Unused Attack Paths on Your Website, including how to retire plugins, block endpoints, and remove dead pages without breaking legitimate workflows.
Recommended baseline permissions (and where people trip up)
Start from sane defaults, because most small business Linux hosting environments behave similarly, even if they’re not identical.
Directories:
755is a common baseline. It allows traversal and reading, but only the owner can write.Files:
644is a common baseline. Owner can write, others can read.Highly sensitive config files. Aim for
600or640depending on whether a group process needs read access. If your stack requires the web server to read a config file, make sure it can read it, but don’t let it write it unless you have a specific, audited reason.
Get ownership right first, because “perfect” permissions don’t help if the wrong user owns the files. You can set “perfect” permissions and still be insecure if the owner/group is wrong. If the web server user owns the codebase, then 644 still means the web server can write to every file it owns. That’s why we treat ownership as the first class control, and permissions as the second.
Ownership and groups: the part most guides skip
Keep code ownership with your deployment identity, because runtime ownership is a common failure mode. On a well run setup, your deploy user (or your account user) owns the application code. The web server user gets read access, not ownership. Writable directories are the exception, not the rule.
Use groups deliberately, because they let you be precise without making the workflow miserable. Group strategy is where you can be precise without being painful. If you have a deployment pipeline and a separate web server process, you can put them in a shared group and use group permissions intentionally. The aim is algorithmic alignment between how changes are shipped and how the runtime behaves, so you’re not constantly “chmod things until it works”. That’s not a process. That’s a slow motion incident.
CMS-specific realities (WordPress gets its own mention)
Reduce permission sprawl, because WordPress setups often accumulate contradictory ownership over time. WordPress is often run in environments where file ownership is messy, because people set it up through a control panel, then later add SFTP users, then later install a security plugin that changes behaviour. The outcome is usually that WordPress can’t update, so someone makes wp-content writable to “fix it”.
Keep writable paths minimal and justified, because that’s what limits persistence. There’s a safer approach. Keep the core and plugin/theme directories owned by a deploy user and not writable by the web server. Make only wp-content/uploads writable for media. If you need caching, make only the cache directory writable. If you need logs, make only the log path writable. Every writable path should have a reason you can say out loud.
Make permissions easier to reason about, because clean boundaries in your site’s foundation reduce guesswork. This ties directly into website architecture. If your site is structured as an ecosystem with clear boundaries between code, content, and data, permissions become easier to reason about. We covered that systems first thinking in designing a website ecosystem for discoverability.
Stopping persistence: treat writable directories as hostile terrain
Assume compromise is possible, because writable directories are where attackers try to land. If a directory must be writable by the web server, assume an attacker might eventually write to it. Your job is to make that write less useful.
Prevent code execution in upload paths, because “writable + executable” is the dangerous combo. At a minimum, block script execution in upload directories. On Apache that’s often handled with .htaccess. On Nginx it’s usually done in server config. The exact implementation varies, but the intent is consistent. Uploads should store files, not run code.
Eliminate accidental footholds, because “extra” writable locations are where persistence hides. Also watch for “shadow writable” locations. Backup plugins that store zips in web-accessible directories. Old staging folders. Temporary migration directories. Developers leaving a test.php file behind. Permissions won’t save you if you keep dropping live ammo in the foyer.
Shared access: permissions won’t fix people problems, but they can enforce boundaries
Separate identities, because shared access is a governance problem first and a technical problem second. If you have contractors, marketers, and multiple admins, separate accounts are non-negotiable. Use SFTP/SSH users with scoped access where your host supports it. Use a password manager and rotate credentials when someone leaves. If you’re stuck on a platform that only gives you one login, treat that as a platform limitation and compensate with tighter filesystem rules and better monitoring.
Prevent permission drift, because “temporary” changes tend to become permanent. Maintenance frequency matters here because permissions drift over time. Plugins get added. Caches get reconfigured. Someone “temporarily” opens a directory and forgets about it. A practical schedule helps prevent that drift from becoming normal. How often a business website should be maintained covers a cadence that actually holds up under operational pressure.
How to audit permissions without turning it into a week-long project
Start with high impact paths, because writable config and code directories are where incidents escalate. Start with the paths that create the most damage when writable: configuration files, the application code directories, and anything that can execute server side code. Confirm who owns them and whether the web server can write to them.
Document legitimate write paths, because clarity beats guesswork under pressure. Then map the legitimate write paths. Uploads, cache, logs, sessions, and a small number of runtime directories. If you can’t explain why a directory is writable, it probably shouldn’t be.
Verify execution controls, because permissions alone don’t stop an uploaded webshell from running. Finally, verify that writable directories can’t execute scripts. This is where a lot of “we set permissions” efforts fall apart. Attackers don’t need to write into your plugin folder if they can upload a PHP file into a writable uploads directory and execute it.
Where this sits in the bigger security foundation
Strengthen your security foundation, because permissions are one control layer in a broader system. File permissions are a control layer, not a complete security strategy. They work best when combined with least-privilege user access, sensible deployment practices, WAF rules where appropriate, and monitoring that tells you when something changes unexpectedly.
Build technical integrity into operations, because treating your site like infrastructure changes the outcome. If you run your website like a marketing asset only, permissions feel like annoying friction. If you run it like infrastructure, permissions become part of your technical integrity. That shift is usually what separates a one off clean up from a site that stays clean.
Sources & Further Reading
Need help locking down your website access?
We can audit permissions, ownership and writable paths, then manage ongoing security for you.
Get in TouchComments
No comments yet. Be the first to join the conversation!
Leave a Comment
Your email address will not be published. Required fields are marked *