
Joomla Security Hardening: Protect Your Site in Depth
Most Joomla sites do not get hacked because of a clever, targeted attack. They get hacked because of an old extension, a weak password, or a setting that nobody ever changed. Security hardening is the work of closing those easy doors before someone walks through them.
This article explains how to harden a Joomla site step by step. It covers the basics for owners and editors, the daily setup for administrators, and the technical details for developers. You will learn how to keep the core and extensions updated, protect user accounts with strong passwords and multi-factor authentication, tune the security settings in the Global Configuration, harden the web server, send the right HTTP security headers, watch your logs, and understand the protections Joomla already builds in for you.
Security is not a product you install. It is a set of habits, and Joomla gives you the tools for almost all of them.
The goal is simple: help you harden your Joomla site with confidence, using mostly what is already on board.
1. The Basics
1.1 What is Security Hardening?
Security hardening means reducing the number of ways an attacker can get into your site, and limiting the damage when something still goes wrong. It is not one magic switch. It is a series of small decisions in four layers:
| Layer | Examples |
|---|---|
| Server | PHP version, HTTPS, file permissions, .htaccess rules. |
| Joomla core | Updates, Global Configuration, session settings, security headers. |
| Extensions | Updates, removing what you do not use, choosing trustworthy developers. |
| People | Strong passwords, multi-factor authentication, limited permissions. |
Every layer matters. A fully patched Joomla behind a weak Super User password is still an open door.
1.2 How Joomla Sites Really Get Compromised
Year after year, the same causes top the list:
- Outdated extensions with known vulnerabilities.
- Outdated Joomla core versions.
- Weak or reused passwords on administrator accounts.
- Leftover files: old backups, test copies, abandoned components.
- Compromised hosting neighbours on badly isolated shared servers.
Notice what is not high on the list: exotic zero-day attacks. Most break-ins use problems that were already fixed in an update the site never installed. That is good news, because it means the most effective hardening steps are also the simplest ones.
1.3 Security is a Process
You harden a site once, but you keep it secure every week: install updates, review accounts, check logs, verify backups. This article follows that order, from the steps with the biggest impact to the finer details.
Back to top2. Keep Everything Updated
2.1 Core Updates
Updating Joomla is the single most effective security measure you can take. Joomla announces security fixes in its release notes, which means every release also tells attackers exactly what was broken in the previous version. From the moment a security release is out, unpatched sites become targets.
You update via System → Update → Joomla. Since Joomla 6, the update system verifies downloads with TUF (The Update Framework): the update metadata is cryptographically signed, so a manipulated update server or a poisoned download cannot slip you a fake Joomla package.
Joomla can also update itself since version 5.4. In the Joomla Update options you can register the site for automated updates, so patch releases install in the background without waiting for you. Note the scope: this updates Joomla itself and nothing else - your third-party extensions never update automatically and remain your job (section 2.2). The service requires that your site is reachable from the internet, and you can have Joomla check for a recent backup first with the backupcheck option. For a site that is not updated every week by a human, automated updates are a strong safety net.
Automated updates are not the only professional strategy, though. On my own sites, and on client sites with a maintenance contract, I deliberately keep them off: I want to control the moment an update runs. When I update manually and something odd shows up on the site afterwards, the update is my first suspect - a connection that is easy to miss when updates install silently in the background.
To keep manual updates workable across many sites, I use YourSites, a commercial site management platform that installs as a Joomla extension on a site of my own. From that single dashboard I monitor and update all the Joomla, WordPress, and ClassicPress sites I maintain - and because it is self-hosted, no client data ever leaves my own server, which keeps the setup GDPR-friendly. Pick the strategy that matches how the site is looked after: automated updates for a site nobody checks weekly, controlled central updates when a professional watches over it.
2.2 Extension Updates
Extensions are the number one attack vector, so treat their updates as seriously as core updates. Check System → Update → Extensions regularly. Enable the Task - Update Notification plugin together with the Task Scheduler, and Joomla emails you when a new core version is available, even when nobody logs in to the backend.
The backend is not your only channel. Most serious developers run a newsletter and mail their users about security updates - subscribe for every extension you rely on. A central dashboard such as YourSites (section 2.1) tracks extension updates across all your sites at once. And being active in the Joomla community pays off more than people expect: volunteers and developers talk to each other, so word of an issue often reaches you before the formal release does.
The pace here has changed. AI-assisted code analysis has made it cheap and fast to scan large amounts of extension code for security flaws, and both sides use it. Developers and security researchers now find and fix vulnerabilities in third-party extensions at a much higher rate than before, which is why you see so many extension security releases lately. Attackers use the same techniques to find sites that have not installed those fixes yet. The result: the safe window between a security release and active exploitation keeps shrinking, so install extension updates quickly instead of "when I get around to it".
A frequent stream of security fixes from a developer is usually a good sign, not a bad one. It means someone is actively auditing the code and responding. The extension to worry about is the one that never publishes a security fix at all.
Two selection habits prevent most of this trouble in advance: install extensions only from reliable developers with a track record, and prefer extensions that plug into Joomla's own update mechanism, so new versions appear in System → Update → Extensions automatically. The official Joomla Extension Directory (JED) marks those listings with "Uses Joomla! Update System" - treat a listing without that mark as a warning sign.
2.3 PHP and the Server Stack
An outdated PHP version stops receiving security fixes, no matter how current your Joomla is. Run a PHP version that is actively supported, and update MariaDB/MySQL and the web server as well. As a bonus, newer PHP versions are usually faster.
You do not have to guess those support dates. The official PHP supported versions page shows exactly when each PHP branch stops receiving bug fixes and when the security-fixes-only period ends. For the rest of the stack, endoflife.date tracks the same dates for MariaDB, MySQL, and practically every other component you run. Put the relevant dates in your calendar and plan the upgrade before support ends, not after your host forces the switch.
2.4 Before You Update
Updates are much less scary with a routine: make a backup, read the release notes, update, and test the site. If you maintain a business-critical site, test the update on a copy of the site first.
Back to top3. Protect User Accounts
3.1 Strong Password Rules
Joomla lets you enforce password strength for all users. Open Users → Manage → Options → Password Options and set:
| Option | Meaning |
|---|---|
minimum_length |
Minimum password length. Make this at least 12. |
minimum_integers |
Minimum number of digits. |
minimum_symbols |
Minimum number of symbols. |
minimum_uppercase / minimum_lowercase |
Minimum upper and lower case characters. |
Length beats complexity: a long passphrase is stronger and easier to remember than a short cryptic string. Joomla stores every password as a salted bcrypt hash, never as plain text, and silently re-hashes old hashes with stronger settings when a user logs in.
3.2 Multi-Factor Authentication
Even a strong password can leak. Multi-factor authentication (MFA) asks for a second proof after the password, and Joomla ships five methods in the multifactorauth plugin group:
| Plugin | Second factor |
|---|---|
| Verification Code (TOTP) | A 6-digit code from an authenticator app. |
| Passkeys (WebAuthn) | A hardware key, fingerprint, or device passkey. The strongest option. |
| YubiKey | A YubiKey hardware token in OTP mode. |
| Code by Email | A one-time code sent by email. Better than nothing. |
| Fixed Code | A static second code. For testing only, not real security. |
Users set up their methods on their own profile, and Joomla stores the enrolled methods in the #__user_mfa table. In Users → Manage → Options you can enforce MFA for specific user groups; start with every group that can log in to the backend. Joomla also throttles failed MFA attempts (the mfatrycount and mfatrytime options), so a second factor cannot be brute-forced quietly.
3.3 Super User Hygiene
- Keep the number of Super Users as small as possible, ideally one or two.
- Never use a Super User account for daily content editing. Use an Administrator or Editor account instead.
- Do not name the account
admin, and do not reuse its password anywhere else. - Give every person their own account. Shared accounts make logs useless and offboarding impossible.
- Remove or block accounts of people who left. Check the user list a few times per year.
3.4 Give Everyone the Minimum They Need
Joomla's access control lets you give an editor exactly the rights to edit articles and nothing more. Someone who cannot install extensions cannot install a malicious one, even if their account is stolen. The principle is called least privilege: every account gets the smallest set of permissions that still lets the person do their job.
Back to top4. Global Configuration Settings That Matter
4.1 Force HTTPS
In System → Global Configuration → Server, set Force HTTPS (force_ssl) to Entire Site. Every password, session cookie, and API token then travels encrypted. There is no good reason left to serve any page over plain HTTP; certificates are free with Let's Encrypt.
4.2 Hide Errors in Production
Set Error Reporting (error_reporting) to None and keep Debug System (debug) off on a live site. Error messages and debug output reveal file paths, database queries, and version details, exactly the reconnaissance an attacker wants. Turn them on only while you are actively troubleshooting, then off again.
4.3 Sessions and Cookies
| Setting | Advice |
|---|---|
session_handler |
Keep Database unless you have a reason (such as Redis) to change it. |
| Session Lifetime | As short as practical. 15-30 minutes for the backend is reasonable. |
session_metadata |
Keep enabled: it powers the "who is online" data and lets you spot sessions that should not be there. |
shared_session |
Keep disabled unless you truly need one login for site and administrator. Separate sessions limit damage. |
cookie_domain / cookie_path |
Leave empty unless you know you need them; a wrong value can leak cookies to sibling domains. |
4.4 Other Switches Worth Knowing
- Site Offline (
offline): use it during maintenance so half-finished states are not public. The Task - Site Status plugin can schedule it. - Frontend Editing (
frontediting): disable module and menu editing from the frontend if editors do not use it. - Mass Mail (
massmailoff): disable mass mailing if unused; a hijacked backend then cannot spam from your domain. - CAPTCHA (
captcha): enable one for registration and contact forms to stop bot signups and form spam.
4.5 The Secret Key
Your configuration.php contains a $secret value that Joomla uses for token and HMAC calculations, for example the API tokens of the Web Services API. Treat the whole file like a password: never paste it in a forum post, a ticket, or a public repository.
5. Server Hardening
5.1 Activate the Shipped Rules
Joomla ships a ready-made Apache configuration as htaccess.txt. Rename it to .htaccess (needed for SEF URLs anyway) and you get several protections for free:
Options -Indexes: nobody can browse your folder listings looking for interesting files.- A
X-Content-Type-Options "nosniff"header: browsers stop guessing file types, which blocks a class of content-smuggling attacks. - A content security rule for uploaded SVG files, which can otherwise carry scripts.
- Blocking rules that reject requests with obvious attack patterns in the URL before Joomla even runs.
On IIS the equivalent file is web.config.txt. On nginx you translate the rules into your server block, because nginx does not read .htaccess files.
5.2 Extra Protection for the Backend
The /administrator login page is the most attacked URL of any Joomla site. Bots hammer it with password guesses all day. Popular countermeasures, roughly in order of effort:
- Enforce MFA for all backend users (see section 3). This neutralises password guessing.
- Add HTTP Basic authentication or an IP allowlist on the
/administratorfolder at the server level, so bots never reach the Joomla login at all. - Use a firewall or fail2ban-style tool at the server or hosting level to block IPs after repeated failures. Joomla core does not lock accounts after failed logins, so rate limiting belongs at this layer or in a security extension.
5.3 Choose Your Hosting Wisely
On cheap shared hosting without proper isolation, a compromised neighbour site can sometimes reach your files. Ask your host how accounts are isolated (for example PHP-FPM pools per user and open_basedir restrictions), whether they run a web application firewall, and how quickly they patch the stack. A few euros per month buy a lot of security here.
5.4 PHP Hardening Settings
A few php.ini settings close doors that Joomla itself cannot close. On managed hosting some of these are preset; on your own server, set them yourself:
| Setting | Recommended | Why |
|---|---|---|
display_errors |
Off |
PHP errors on screen leak paths and code details. Log them instead (log_errors = On). |
expose_php |
Off |
Stops PHP from announcing its version in every response header. |
allow_url_include |
Off |
Blocks including remote files, the classic remote-file-inclusion attack. |
open_basedir |
your site's paths | Confines PHP file access to the site's own directories. |
disable_functions |
e.g. exec, shell_exec, system, passthru, proc_open, popen |
Removes shell-execution functions most sites never need, a favourite tool of uploaded malware. |
Test the site after changing open_basedir or disable_functions: a few extensions legitimately use the stricter functions, and it is better to discover that on a staging copy than in production.
5.5 Database Account Hardening
The database credentials in configuration.php deserve the same care as a Super User account:
- Give every site its own database and its own database user. One shared DB account across sites means one hacked site exposes them all.
- Grant that user only the privileges Joomla needs on its own database - never global privileges like
GRANT,SUPER, orFILE, and no access to other databases. - Use a long generated password. You never type it; it lives only in
configuration.php. - Disable remote database access unless you truly need it. A database that only listens on localhost cannot be attacked from the internet.
5.6 A Web Application Firewall
A web application firewall (WAF) inspects requests before they reach Joomla and drops known attack patterns: SQL injection attempts, malicious uploads, aggressive bots. Common options are Cloudflare (as a proxy in front of your site, including rate limiting and bot protection) and ModSecurity with the OWASP Core Rule Set on your own Apache or nginx.
A WAF is a supporting layer, not a substitute for updates: it can "virtually patch" a fresh extension vulnerability and buy you time, but the real fix is still installing the update. If your host offers a WAF, switch it on; if you run your own server, ModSecurity plus the Core Rule Set is the standard starting point.
Back to top6. HTTP Security Headers
6.1 The Built-in HTTP Headers Plugin
Joomla ships a System - HTTP Headers plugin (plg_system_httpheaders) that sends modern browser security headers without touching server configuration. Enable it under System → Plugins and configure:
| Header | What it protects against |
|---|---|
X-Frame-Options |
Clickjacking: other sites cannot show your pages in a hidden frame. |
Strict-Transport-Security (HSTS) |
Protocol downgrades: browsers refuse to ever load your site over plain HTTP again. Options for max-age, subdomains, and preload. |
Referrer-Policy |
Leaking full URLs of your pages to other sites you link to. |
Cross-Origin-Opener-Policy |
Other windows keeping a scriptable handle on your pages. |
Content-Security-Policy (CSP) |
Cross-site scripting: the browser only executes scripts you explicitly allow. |
6.2 Rolling Out a Content Security Policy
CSP is the most powerful header and the easiest to break your site with, because templates and extensions load scripts from many places. The plugin supports a safe rollout path:
- Enable CSP in Report-Only mode. The browser reports violations in its console but blocks nothing.
- Browse the site and the backend, collect what would break, and add the needed directives.
- Switch from report-only to enforcing once the console stays clean.
The plugin can also generate nonces and script hashes for inline scripts, so you can avoid the dangerous unsafe-inline keyword. Test HSTS with a short max-age first; the preload option is close to irreversible, so enable it only when you are sure every subdomain runs HTTPS forever.
7. Files, Folders, and Permissions
7.1 Sane File Permissions
On a typical Linux host, files should be 644 and folders 755, owned by the account PHP runs as. Never use 777; it lets every process on the server write to your files. If an extension only works with 777, that extension is telling you something about its quality.
You can go one step further and make configuration.php read-only (444). Joomla will ask to relax it when you save the Global Configuration, and you set it back afterwards.
7.2 No Leftovers in the Web Root
Old backups (site-backup.zip), database dumps (dump.sql), phpinfo files, and forgotten test copies (/old/, /backup/) are gifts to attackers, who scan for exactly these names. Keep backups outside the web root, and delete what you no longer need. The Task - Check Files plugin can scan for oversized files on a schedule, which also catches stray archives.
7.3 Move What Does Not Belong in Public
Joomla lets you relocate the tmp and log folders via Path to Temp Folder and Path to Log Folder in the Global Configuration. Point both outside the web root so their contents can never be downloaded. Log files in particular can leak paths and usernames.
Since Joomla 5, new installations can go further and serve the whole site from a dedicated public folder: only the entry points and assets live in the web root (JPATH_PUBLIC), while the application code, configuration, logs, and temp files sit one level above it, out of the web server's reach. If you start a new project, consider this layout from day one.
7.4 Upload Settings
In Content → Media → Options, keep the list of allowed extensions as short as your editors need. Be careful with SVG uploads: SVG is an XML format that can embed scripts. If you must allow it, the shipped .htaccess contains a rule that stops uploaded SVGs from running scripts.
8. Reduce the Attack Surface
8.1 Uninstall What You Do Not Use
Every installed extension is code that can contain a vulnerability, even when disabled. Go to System → Manage → Extensions and uninstall (not just disable) extensions you do not use. Fewer extensions also mean faster updates and fewer conflicts.
8.2 Choose Extensions Like a Skeptic
- Prefer extensions from developers who publish changelogs and respond to security reports.
- Check the Vulnerable Extensions List (VEL) on the Joomla website before and after installing.
- Avoid abandoned extensions: no update in years is a red flag, not a sign of stability.
- Never install nulled or pirated commercial extensions. They are a well-known malware channel.
8.3 Disable Unused Entry Points
- If you do not use the Web Services API, disable the plugins in the
api-authenticationgroup and the Web Services plugin group. - If you never use HTTP Basic authentication for the API, keep that plugin disabled and rely on tokens (see section 12).
- Disable frontend user registration (Users → Options → Allow User Registration) if the site does not need visitor accounts.
8.4 About Security by Obscurity
Renaming the database prefix, hiding version numbers, or masking the login URL raises the effort for casual scanners a little, but stops no determined attacker. Do these things if they are cheap for you, but never count them as real protection. Updates, MFA, and least privilege do the heavy lifting.
Back to top9. Monitoring, Logging, and Scheduled Tasks
9.1 Action Logs: Who Did What
The User Actions Log (com_actionlogs with the System - User Actions Log plugin) records backend activity: logins, extension installs, article edits, configuration changes. Check it under Users → User Actions Log. After an incident, this log answers the crucial question "what happened, and with which account?". The Task - Delete Action Logs plugin prunes old entries on a schedule so the table does not grow forever.
9.2 Log Failed Logins
The System - Log plugin writes failed login attempts to a log file (it subscribes to the onUserLoginFailure event). A sudden burst of failures in that file is your early warning of a password-guessing attack. The Task - Rotate Logs plugin keeps log files from growing unbounded.
9.3 Put the Task Scheduler to Work
The Task Scheduler (com_scheduler) runs maintenance jobs that quietly support your security posture:
| Task plugin | Security value |
|---|---|
updatenotification |
Emails you when a Joomla update is available. |
rotatelogs |
Rotates log files. |
deleteactionlogs |
Prunes the user actions log. |
sessiongc |
Cleans up expired sessions. |
checkfiles |
Finds oversized files, such as forgotten archives. |
globalcheckin |
Checks in items left locked by disappeared users. |
Trigger the scheduler reliably with a real cron job or the web cron URL, not only with backend visits.
9.4 Watch from the Outside
Complement the internal logs with an external uptime monitor and, ideally, a periodic malware scan of the rendered site. Google Search Console warns you when Google flags your site; that warning should never be the first time you hear about a hack, but do connect it anyway.
Back to top10. Backups: Your Safety Net
10.1 Hardening Includes Recovery
No hardening removes risk completely, so a tested backup is part of security. A good backup routine follows the 3-2-1 rule: three copies of your data, on two different kinds of storage, one of them away from the web server. A backup that only lives on the hacked server gets encrypted or deleted together with the site.
10.2 What a Joomla Backup Must Contain
- All files, including
configuration.php, templates, and theimagesfolder. - A dump of the complete database.
Tools like Akeeba Backup package both into one restorable archive and can ship it to off-site storage automatically. Whatever tool you use: test a restore at least once, on a separate location. An untested backup is a hope, not a plan.
10.3 Backups After an Incident
Keep several generations of backups. If a site was compromised weeks before you notice, yesterday's backup contains the backdoor too, and you will be glad to have an older, clean one to compare against.
10.4 When the Worst Happens: Incident Response
If you discover a hack, resist the urge to start deleting suspicious files right away. Work through four phases in order:
- Contain: take the site offline and rotate every credential - Joomla passwords, API tokens, the database password, hosting, FTP and SSH accounts. Assume they are all known.
- Investigate: use the action logs, the failed-login log, and the server access logs to find out when and how the attacker got in. Note the timestamps of modified files.
- Eradicate: restore a backup from before the compromise, or clean the files against a fresh Joomla download and a clean extension set. Then update everything, because the original hole is usually still there.
- Recover and learn: bring the site back online, watch the logs closely for a few weeks, and fix the root cause - the outdated extension, the weak password, the missing MFA.
The most common mistake is skipping step 2: a site that is cleaned without knowing the entry point is usually reinfected within days through the same door.
Back to top11. Under the Hood (Developer View)
11.1 What Joomla Already Protects
Joomla's core defends against the classic web attacks, and knowing how helps you keep that protection intact:
| Attack | Core defence |
|---|---|
| SQL injection | The database API with prepared statements and parameter binding. |
| Cross-site scripting (XSS) | Input filtering (InputFilter), output escaping, and the CSP header plugin. |
| Cross-site request forgery (CSRF) | A per-session form token, checked on every state-changing request. |
| Password theft from the database | Salted bcrypt hashes; plain passwords are never stored. |
| Timing attacks on tokens | Constant-time comparisons via Crypt::timingSafeCompare(). |
11.2 CSRF Tokens in Your Own Code
Every form that changes data needs the token. In the form layout:
<?php echo Joomla\CMS\HTML\HTMLHelper::_('form.token'); ?>
And in the controller that receives the request:
$this->checkToken(); // throws on a missing or invalid token
Skip this and any website can submit your form on behalf of a logged-in user.
11.3 Query Safely
Never concatenate user input into SQL. Bind it:
use Joomla\Database\ParameterType;
$query = $db->getQuery(true)
->select($db->quoteName('id'))
->from($db->quoteName('#__content'))
->where($db->quoteName('created_by') . ' = :userId')
->bind(':userId', $userId, ParameterType::INTEGER);
11.4 Escape on Output
Filtering input is not enough; escape at the moment of output, in the layout:
<?php echo $this->escape($item->title); ?>
The rule of thumb: filter input, escape output, and let the database layer quote values. Each defence covers cases the others miss.
11.5 Check Permissions, Not Assumptions
In components, verify authorisation explicitly before acting:
$user = $this->getUserFactory()->loadUserById($userId);
if (!$user->authorise('core.edit', 'com_example')) {
throw new \Exception(Text::_('JERROR_ALERTNOAUTHOR'), 403);
}
Hiding a button is cosmetics; the check in the code is the security.
11.6 Where Security Data Lives
| Table | Role |
|---|---|
#__users |
Accounts, bcrypt password hashes, block and activation flags. |
#__user_mfa |
Enrolled multi-factor authentication methods per user. |
#__action_logs |
The user actions log entries. |
#__session |
Active sessions (with the database session handler). |
#__extensions |
Which extensions and plugins are enabled. |
12. Securing the Web Services API
12.1 Tokens, Not Passwords
The Joomla API authenticates with the api-authentication plugin group. Prefer the Token plugin over Basic authentication: a token can be revoked on its own, while a leaked Basic password compromises the whole account. A typical call:
curl -H "X-Joomla-Token: <token>" \
https://example.test/api/index.php/v1/users
12.2 Keep the Token Circle Small
By default only Super Users may authenticate with a token. The allowedUserGroups parameter of the User - Joomla API Token plugin widens this; widen it as little as possible, and create a dedicated low-privilege user for each integration instead of handing out a Super User token. An API user has exactly the same permissions as the same user on the website, so least privilege applies here too.
12.3 If You Do Not Use the API
Disable the API and Web Services plugins entirely. An entry point that is switched off cannot be attacked. You can re-enable them the day you actually need headless access.
Back to top13. SEO and Metadata
Security and SEO are more connected than they look. A hacked site is an SEO disaster: search engines detect injected spam links, doorway pages, and malware quickly, flag the site with a warning, and rankings that took years to build disappear in days. Cleaning up the blocklist status afterwards takes far longer than the hack itself did.
The positive side: HTTPS is a confirmed ranking signal, and the redirect to HTTPS consolidates your URLs. Security headers like HSTS make browsers trust your domain. And an updated, fast, stable site is exactly what search engines want to send visitors to. Every hour spent on hardening quietly protects your search traffic as well.
Back to top14. Common Mistakes and Pitfalls
14.1 "The Site Works, So I Will Not Touch It"
Symptom: a site runs for years without updates because everyone is afraid to break it.
Fix: the longer you wait, the riskier the eventual update becomes, and the longer known vulnerabilities stay open. Update in small, frequent, backed-up steps instead of one giant risky leap.
14.2 Debug Mode Left On in Production
Symptom: visitors see database queries, file paths, or PHP notices at the bottom of pages.
Fix: turn off Debug System and set Error Reporting to None in the Global Configuration. Investigate errors in the log files instead.
14.3 Backups Stored Inside the Web Root
Symptom: backup.zip or dump.sql is downloadable by anyone who guesses the name, handing out your whole site including configuration.php.
Fix: store backups outside the web root and off the server. Delete stray archives now; scanners look for them constantly.
14.4 Everyone is a Super User
Symptom: five people share two Super User accounts, "because it is easier".
Fix: one account per person, minimum permissions per role, MFA on every backend account. Logs become meaningful and a stolen editor password no longer means a stolen site.
14.5 Extensions Disabled Instead of Uninstalled
Symptom: the extensions list is full of disabled leftovers from experiments years ago.
Fix: uninstall them. Disabled extension files still sit on disk and some remain reachable directly. Uninstalling removes the code and its update worries.
14.6 A CSP That Broke the Site Once, So It Stays Off
Symptom: someone enabled the Content-Security-Policy header, the template broke, and the whole HTTP Headers plugin was switched off forever.
Fix: enable the plugin with the safe headers (X-Frame-Options, Referrer-Policy, HSTS) immediately, and roll out CSP separately in report-only mode until the browser console is clean.
Back to top15. Best Practices
If you remember only a few things from this article, remember these:
- Update Joomla, extensions, and PHP promptly. This single habit prevents most hacks.
- Enforce MFA for every backend account, and keep Super Users to a minimum.
- Force HTTPS on the entire site, and enable the HTTP Headers plugin.
- Uninstall unused extensions; check the Vulnerable Extensions List before adopting new ones.
- Keep error reporting and debug mode off in production.
- Store backups off-site following the 3-2-1 rule, and test a restore.
- Turn on the User Actions Log and the failed-login logging, and actually read them.
- Let the Task Scheduler do the recurring chores: update notifications, log rotation, session cleanup.
- Developers: check CSRF tokens, bind query parameters, escape output, and verify permissions in code.
16. Quick Reference
UPDATES System > Update > Joomla / Extensions
Task - Update Notification plugin + Task Scheduler
Joomla 6 verifies core updates with TUF signing
ACCOUNTS Users > Manage > Options
password rules: minimum_length 12+
MFA plugins: TOTP, Passkeys, YubiKey, Email, Fixed
enforce MFA per group; few Super Users; no shared accounts
CONFIG force_ssl Entire Site
error_reporting None debug Off
session lifetime short shared_session Off
SERVER rename htaccess.txt > .htaccess (-Indexes, nosniff)
files 644 / dirs 755, configuration.php 444
tmp + log folders outside the web root
no backups/dumps in the web root
php.ini: display_errors Off, expose_php Off,
allow_url_include Off, open_basedir set
DB: own user per site, minimal privileges, localhost only
WAF: Cloudflare or ModSecurity + OWASP Core Rule Set
HEADERS System - HTTP Headers plugin
X-Frame-Options, HSTS, Referrer-Policy, COOP
CSP: start Report-Only → fix → enforce
MONITOR Users > User Actions Log (com_actionlogs)
System - Log plugin (failed logins)
Scheduler: rotatelogs, deleteactionlogs, sessiongc
API prefer Token over Basic auth
narrow allowedUserGroups, dedicated API users
unused? disable the API plugins
DEV checkToken() on every form
bind() parameters, escape() output
$user->authorise() before acting
RECOVER 3-2-1 backups, multiple generations, tested restore
hacked? contain > investigate > eradicate > recover
never clean up without finding the entry point
Back to top17. Summary
Hardening a Joomla site is not one heroic action but a stack of sensible habits:
- Updates first: core (signed with TUF, optionally automated), extensions, and PHP. Outdated software causes most hacks.
- Accounts: strong password rules, multi-factor authentication from the built-in plugins, few Super Users, least privilege for everyone.
- Configuration: HTTPS everywhere, errors and debug hidden, short sessions.
- Server: the shipped
.htaccessrules, sane permissions, no leftovers or backups in the web root. - Headers: the HTTP Headers plugin delivers clickjacking, HSTS, and CSP protection without touching the server.
- Visibility: action logs, failed-login logs, scheduled maintenance tasks, and external monitoring.
- Recovery: off-site, multi-generation, tested backups for the day something still goes wrong.
- Code: Joomla's core defends against SQL injection, XSS, and CSRF; developers keep that promise by using tokens, bound parameters, and output escaping.
None of these steps is difficult on its own. Together they turn your site from an easy target into one that attackers skip in favour of softer prey.
If you are not sure where your site stands today, a structured security review is the natural first step: check the versions, the accounts, the settings, and the logs in exactly the order of this article. That kind of methodical audit is precisely the work a Joomla specialist does regularly, and it usually finds the two or three doors that matter before anyone else does.
Back to top

Peter is a Joomla specialist and a Linux admin for fast, secure and scalable websites.












