Percio Castelo.
PT Home
The ultimate WordPress security and hardening checklist: 99 technical measures across 11 critical areas
← Back to blog

The ultimate WordPress security and hardening checklist: 99 technical measures across 11 critical areas

9/11/2026 · 8 min · WordPress · 622 views

WordPress is the most popular content management system on the planet, powering over 40% of the entire web. Precisely due to this massive market share, it is the primary target for automated scans, brute-force zombie botnets, and malware injection campaigns.

An out-of-the-box WordPress deployment is designed for ease of installation and backwards compatibility rather than strict, proactive security. Without a rigorous defense-in-depth hardening methodology, a standard environment exposes critical attack vectors: public user enumeration, arbitrary script execution within upload directories, XML-RPC amplification abuse, and loose web server permissions.

In this technical guide, I have structured and documented The Ultimate WordPress Security and Hardening Checklist, composed of 99 practical measures distributed across 11 core architectural domains.


1. Core & configuration (wp-config.php)#

The wp-config.php file sits at the very foundation of the application. It manages database credentials, cryptographic keys, and runtime debugging parameters.

  1. Rotate security salts periodically

The keys AUTH_KEY, SECURE_AUTH_KEY, LOGGED_IN_KEY, and NONCE_KEY ensure session tokens and cookies are signed with strong entropy. Rotating these keys invalidates all active sessions (mandatory following an incident response event).

   // Example values only — generate your own at https://api.wordpress.org/secret-key/1.1/salt/
   define('AUTH_KEY',         'b!z8#K9*xL2m@1vPq9$J7wZ#rE4tY6uI');
   define('SECURE_AUTH_KEY',  'c@3vB7$mK9#xL1wPq8*J6yZ!rE5tY4uO');
   define('LOGGED_IN_KEY',    'x#9vM2*kL8@1wPq7$J5xZ#rE6tY3uP1b');
   define('NONCE_KEY',        'k*7vQ4#mL9$1wPq6*J4wZ!rE7tY2uA9c');

2. Authentication flow & login security (/wp-login.php)#

The login interface is the primary exposed gateway to the public internet. The objective is to eliminate dictionary attacks and protect credentials against interception.

  1. Block multiple failed login attempts

Deploy IP-based rate limiting to prevent automated password spraying.

  1. Enforce Two-Factor Authentication (2FA/MFA)

Require time-based one-time password (TOTP) apps for all administrative and editorial roles.

  1. Disable detailed login error messages

Prevent WordPress from confirming whether a username exists or only the password was incorrect.

   add_filter('login_errors', function() {
       return 'Invalid credentials. Please verify your details.';
   });
  1. Implement reCAPTCHA v3 or Cloudflare Turnstile

Shield login endpoints against bots without creating friction for legitimate humans.

  1. Mask the default login URL (wp-login.php)

Moving the endpoint to a custom slug filters out over 90% of opportunistic bot scans.

  1. Force strict SSL/TLS for administrative sessions

Ensure no authentication cookies or tokens travel unencrypted.

   define('FORCE_SSL_ADMIN', true);
  1. Enforce short session timeouts

Automatically terminate idle sessions to prevent session hijacking on shared workstations.


3. Administrative dashboard (/wp-admin)#

  1. Disable the built-in file editor

Prevent attackers who compromise administrative credentials from altering theme or plugin PHP code directly through the dashboard:

   define('DISALLOW_FILE_EDIT', true);
  1. Disable plugin and theme installation/updates from the web UI

In production environments driven by automated CI/CD pipelines, disallow runtime file modifications:

    define('DISALLOW_FILE_MODS', true);
  1. Restrict /wp-admin access by trusted IP allowlist

Block direct access to /wp-admin in Nginx or Apache, allowing only office or corporate VPN subnets.

  1. Deploy HTTP Basic Authentication over /wp-admin

An early perimeter defense that prevents malicious HTTP requests from executing expensive PHP-FPM processes.

  1. Disable and remove the default admin username

Assign administrative privileges only to customized, non-guessable usernames.

  1. Enforce the Principle of Least Privilege

Never grant Administrator privileges to content creators or authors who only require Contributor or Editor access.


4. Themes & presentation layer#

  1. Remove inactive and legacy default themes

Retain only the active theme and one patched default theme for emergency fallback.

  1. Always utilize Child Themes for customizations

Keeps core modifications cleanly decoupled and allows rapid patching of the parent theme.

  1. Audit templates for insecure PHP execution (eval, base64_decode)

Obfuscated code in commercial or third-party themes often hides pre-packaged backdoors.

  1. Eliminate exposed debug files and git repositories

Ensure .git, composer.json, and vendor directories cannot be requested over HTTP.


5. Secure development practices#

  1. Disable WP_DEBUG_DISPLAY and safeguard WP_DEBUG_LOG

PHP errors must never reveal server paths or database schemas to web visitors.

    define('WP_DEBUG', true);
    define('WP_DEBUG_DISPLAY', false);
    define('WP_DEBUG_LOG', true);
    @ini_set('display_errors', 0);
  1. Deny web access to dotfiles and sensitive configurations (.env, .git)

In Nginx:

    location ~ /\.(git|env|bak|config) {
        deny all;
        return 404;
    }
  1. Sanitize and escape all input and output data using native APIs

Always sanitize using sanitize_text_field(), absint(), and escape with esc_html().

  1. Verify Nonces on all state-changing actions (wp_verify_nonce)

Eliminate Cross-Site Request Forgery (CSRF) vulnerabilities on form submissions and AJAX endpoints.

  1. Dequeue unnecessary frontend assets and scripts

Remove unused libraries like jQuery Migrate or Dashicons on public pages.

  1. Incorporate Static Application Security Testing (SAST) in CI/CD

Run PHPStan, Semgrep, and PHPCS against WordPress Coding Standards prior to deployment.


6. Plugin management & auditing#

  1. Install plugins exclusively from the official repository or verified vendors

Never use pirated or "nulled" plugins, which represent the #1 vector for backdoor distribution.

  1. Deactivate and permanently delete unused plugins

Inactive plugins remain vulnerable if their internal PHP files are accessible over HTTP.

  1. Maintain a lean active plugin count

Fewer active plugins equal reduced attack surface and faster Time to First Byte (TTFB).

  1. Enable automatic updates for security patches (Minor releases)
  2. Audit third-party dependencies against public vulnerability databases (WPScan / NVD)
  3. Monitor abandoned or delisted plugins from the WordPress directory

If a plugin is removed due to unresolved security issues, replace it immediately.


7. Database layer (MySQL / MariaDB)#

  1. Change the default wp_ table prefix

Mitigates blind SQL Injection attacks that rely on hardcoded table names such as wp_users.

    $table_prefix = 'nx94_';
  1. Enforce least-privilege database user permissions

Retain SELECT, INSERT, UPDATE, DELETE alongside ALTER, CREATE, and INDEX to allow schema upgrades without manual friction. Revoke high-risk privileges (such as DROP and GRANT OPTION) and restrict access strictly to the WordPress database.

  1. Bind MySQL strictly to localhost (127.0.0.1 or Unix socket)
  2. Deploy automated, encrypted offsite backups with immutability guarantees

Store database dumps in write-once-read-many (WORM) cloud storage (e.g. OCI Object Storage with Object Lock).


8. Hosting & infrastructure architecture#

  1. Run modern PHP (PHP 8.2 or newer) with active security support

Obsolete PHP versions (7.x) no longer receive security patches and contain unpatched CVEs.

  1. Enforce filesystem isolation per site (open_basedir and chroot)

Prevents a vulnerability in one virtual host from spreading to other tenants or applications on the same server.


9. Web server & Linux OS hardening#

  1. Configure strict filesystem permissions (644 for files, 755 for directories)
    find /var/www/html/ -type d -exec chmod 755 {} \;
    find /var/www/html/ -type f -exec chmod 644 {} \;
    chmod 640 /var/www/html/wp-config.php && chown root:www-data /var/www/html/wp-config.php
  1. Disable directory listing (Options -Indexes in Apache / autoindex off in Nginx)
  2. Suppress server tokens and version banners (ServerTokens Prod, expose_php = Off)
  3. Deploy modern HTTP security headers:
  • Strict-Transport-Security (HSTS)
  • X-Content-Type-Options: nosniff
  • X-Frame-Options: SAMEORIGIN
  • Referrer-Policy: strict-origin-when-cross-origin
  • Restrictive Permissions-Policy
  1. Deploy an Edge Web Application Firewall (Cloudflare / ModSecurity / Coraza)

Blocks SQLi, XSS, and LFI exploits before requests reach the PHP runtime.


10. Offensive & defensive hardening (depth defense)#

  1. Disable the public REST API user endpoint (stops public author scraping via /wp-json/wp/v2/users).
  2. Block xmlrpc.php completely

XML-RPC is obsolete for most sites and remains the primary channel for brute-force amplification (system.multicall) and DDoS reflection (pingback attacks).

    location = /xmlrpc.php {
        deny all;
        access_log off;
        log_not_found off;
        return 403;
    }
  1. Prevent PHP script execution in /wp-content/uploads/

Even if an attacker bypasses upload validation, the web server denies script execution:

    location ~* /wp-content/uploads/.*\.php$ {
        deny all;
        return 403;
    }
  1. Deny direct PHP execution inside theme and plugin directories (for non-bootstrap endpoints).
  2. Block web requests to sensitive documentation (license.txt, readme.html, wp-config-sample.php).
  3. Relocate wp-config.php one directory above the web document root (natively supported by WordPress).
  4. Block author enumeration via query strings (/?author=1)
    if ($query_string ~* "author=([0-9]+)") {
        return 403;
    }
  1. Filter directory traversal patterns and injection signatures (../, eval(, base64_) in URLs.
  2. Filter bad bots, rogue scrapers, and malicious ASN crawlers.
  3. Prevent public inspection of .htaccess and sensitive hidden files.
  4. Block unauthenticated requests to /wp-admin/admin-ajax.php when not required by the site.
  5. Restrict media library queries so users only view their own uploaded files.
  6. Strip version query strings (?ver=x.x.x) from styles and scripts to hinder automated fingerprinting.
  7. Block comment spam lacking a legitimate Referer header.
  8. Disable PHP easter eggs (expose_php = Off).
  9. Implement automated File Integrity Monitoring (FIM).
  10. Enforce a strict Content Security Policy (CSP) to prohibit unauthorized inline script execution.
  11. Centralize administrative audit logs (user registration, privilege escalation, file changes).

11. Performance, efficiency & resource optimization#

Speed and resilience are intrinsically linked: a highly optimized site easily absorbs traffic spikes that would otherwise exhaust PHP workers.

  1. Enable Gzip and Brotli compression on the web server
  2. Configure long-lived browser caching (Cache-Control and Expires) for static assets
    location ~* \.(jpg|jpeg|png|gif|ico|webp|svg|css|js)$ {
        expires 365d;
        add_header Cache-Control "public, no-transform";
    }
  1. Utilize HTTP/2 or HTTP/3 (QUIC) for multiplexed transfers
  2. Implement Full Page Caching (Redis Object Cache or Nginx FastCGI Cache)

Handles thousands of requests per second from memory without invoking PHP or querying MySQL.

  1. Convert image assets to modern WebP or AVIF formats
  2. Enable native lazy loading for images and embedded iframes
  3. Dequeue native WordPress emoji scripts and styles on the frontend
    remove_action('wp_head', 'print_emoji_detection_script', 7);
    remove_action('wp_print_styles', 'print_emoji_styles');
  1. Dequeue block editor (Gutenberg) styles if using classic or headless themes
  2. Defer or move non-critical JavaScript to the footer
  3. Optimize database overhead (prune post revisions, expired transients, and spam comments)
    define('WP_POST_REVISIONS', 5);
  1. Minify and bundle CSS and JavaScript assets
  2. Distribute static media via a global Content Delivery Network (CDN)
  3. Configure DNS prefetching (dns-prefetch and preconnect) for third-party integrations.

Risk matrix and priority overview#

Architectural DomainCritical Items (High Priority)Implementation EffortRisk Reduction
Core & ConfigurationSalts, file permissions, isolated configLowCritical
Authentication & Login2FA, Rate Limit, Error MaskingMediumHigh
Admin DashboardDisable file editing, IP restrictionsLowHigh
Database SecurityPrefix change, least privilege, backupsMediumCritical
Server HardeningBlock PHP in uploads, disable XML-RPCMediumCritical
Performance & CacheFull page cache, WebP, BrotliMediumHigh

Conclusion: turning hardening into an operational routine#

WordPress security is not a single plugin switch; it is a continuous defense-in-depth practice. By systematically applying these 99 measures, you transform an out-of-the-box installation into an enterprise-hardened environment resilient against modern automated exploits and threat actors.

To review your environment step-by-step and generate compliance audit reports, use the interactive checklist tool:

👉 Access the Interactive WPLista Tool (WordPress Checklist)

Was this article helpful?

Leave a quick reaction to help prioritize future technical guides:

622 reads
Creative Commons Attribution-NonCommercial

This post is licensed under CC BY-NC.

Comments

Join the discussion below.

0 comments