Stop leaking sensitive info. Removing meta generator, query strings (?ver=6.7), and setting X-Frame-Options. A 2000-word guide for Devs.
EN

How to fully hide WordPress version & harden HTTP headers (2026 security guide)

5.00 /5 - (24 votes )
Last verified: March 1, 2026
Experience: 10+ years experience
Table of Contents

In the world of cybersecurity, there is a concept known as “Reconnaissance”.

Before a hacker (or an automated bot) attacks your site, they scan it. They look for low-hanging fruit. If your website proudly announces: “Hello! I am running WordPress 5.8.1!”, you are practically rolling out the red carpet for them. Because they know exactly which vulnerabilities existed in 5.8.1.

In this comprehensive security guide, we will go beyond simple “Hide Version” plugins. We will dive into Security by Obscurity (and why it is only the first layer of defense), and then we will implement real, robust server-level hardening using HTTP Headers, login protection, and automated monitoring.


Part 1: Understanding “Security Through Obscurity”

What is Security Through Obscurity?

Security through obscurity is the practice of hiding information about your system to make it harder for attackers to find vulnerabilities. While controversial in security circles, when combined with proper security measures, it adds an extra layer of defense.

The Debate:

  • Critics say: “A system should be secure even if attackers know everything about it”
  • Practitioners say: “Why make it easier for attackers by broadcasting your vulnerabilities?”

The Truth: Security through obscurity is not sufficient on its own, but it is a valuable first layer of defense. Think of it as removing the welcome mat from your front door—it won’t stop a determined burglar, but it might make opportunistic ones move on to an easier target.

Why Hiding WordPress Version Matters

WordPress core vulnerabilities are publicly documented. When a security patch is released, the changelog explicitly states which versions are affected. By displaying your version number, you’re essentially telling attackers:

  1. Which known vulnerabilities might exist on your site
  2. Whether you’ve applied the latest security patches
  3. What specific exploit code might work against you

Common Version Leakage Points:

  • HTML meta generator tag
  • RSS/Atom feed generator tags
  • Script and style query strings (?ver=6.7.1)
  • Readme.html file in root directory
  • WordPress REST API responses

Part 2: Removing WordPress Version Information

The Generator Meta Tag

By default, WordPress injects a meta tag into the <head> of your HTML:

<meta name="generator" content="WordPress 6.7.1" />

This is useless for SEO and dangerous for security.

The Fix (PHP snippet)

Do not install a heavyweight plugin just for this. Add this cleaned-up code to your functions.php:

/**
 * Remove WordPress Version from Head and Feeds
 */
remove_action('wp_head', 'wp_generator');
remove_action('rss2_head', 'the_generator');
remove_action('commentsrss2_head', 'the_generator');
remove_action('wp_head', 'wlwmanifest_link'); // Windows Live Writer (Legacy)
remove_action('wp_head', 'rsd_link'); // Really Simple Discovery

/**
 * Remove Version from Scripts and Styles
 */
function wppoland_remove_version_scripts_styles($src) {
    if (strpos($src, 'ver=')) {
        $src = remove_query_arg('ver', $src);
    }
    return $src;
}
add_filter('style_loader_src', 'wppoland_remove_version_scripts_styles', 9999);
add_filter('script_loader_src', 'wppoland_remove_version_scripts_styles', 9999);

/**
 * Remove Version from RSS Feeds
 */
add_filter('the_generator', '__return_empty_string');

Why this matters: It breaks the logic of simple “Script Kiddie” scrapers. If a bot is scanning 1 million sites looking for “WordPress 5.X”, your site will return a blank stare. The bot moves on.

Important Note: This is Security by Obscurity. It’s the first layer, not the only layer. A determined attacker can still fingerprint WordPress through other methods (REST API endpoints, file structure, etc.).

Additional Version Removal Methods

Remove from REST API

/**
 * Remove WordPress version from REST API headers
 */
add_filter('rest_api_init', function() {
    remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');
}, 15);

add_filter('rest_pre_serve_request', function($value) {
    header('X-Powered-By: WordPress');
    return $value;
});

Remove Readme and License Files

/**
 * Block access to readme.html and license.txt
 */
function wppoland_block_readme_access() {
    if (strpos($_SERVER['REQUEST_URI'], 'readme.html') !== false ||
        strpos($_SERVER['REQUEST_URI'], 'license.txt') !== false) {
        wp_die('Access denied', '403 Forbidden', array('response' => 403));
    }
}
add_action('init', 'wppoland_block_readme_access');

Or via .htaccess:

<FilesMatch "^(readme\.html|license\.txt)$">
  Order deny,allow
  Deny from all
</FilesMatch>

Part 3: HTTP Security Headers (The Real Defense)

Hiding the version is like taking the house number off your door. It helps, but it doesn’t lock the door. HTTP Security Headers are the deadbolts.

In 2026, browsers are strict. If you don’t send the right headers, you are vulnerable to XSS (Cross-Site Scripting), Clickjacking, and data leaks.

1. X-Frame-Options (Anti-Clickjacking)

This header tells the browser: “Do not allow anyone to put my site inside an <iframe>.” This prevents hackers from creating a fake site that loads your bank/login page in an invisible frame and capturing your clicks.

Implementation (.htaccess):

<IfModule mod_headers.c>
  Header always append X-Frame-Options SAMEORIGIN
</IfModule>

Nginx:

add_header X-Frame-Options "SAMEORIGIN" always;

Options:

  • DENY - Page cannot be displayed in a frame
  • SAMEORIGIN - Page can only be displayed in a frame on the same origin
  • ALLOW-FROM uri - Page can only be displayed in a frame on the specified origin (deprecated)

2. X-Content-Type-Options

Prevents “MIME Sniffing”. If a hacker uploads a .jpg file that actually contains executable JavaScript, this header tells the browser: “The server said it’s an image, so treat it as an image, don’t execute it.”

Implementation:

<IfModule mod_headers.c>
  Header set X-Content-Type-Options nosniff
</IfModule>

Nginx:

add_header X-Content-Type-Options "nosniff" always;

3. Strict-Transport-Security (HSTS)

This is critical for SSL. It forces the browser to always use HTTPS, even if the user types http://. It prevents “Man-in-the-Middle” attacks on public Wi-Fi.

Implementation (Only do this if you have valid SSL!):

<IfModule mod_headers.c>
  Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</IfModule>

Nginx:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

What the parameters mean:

  • max-age=31536000: Browser remembers for 1 year
  • includeSubDomains: Apply to all subdomains (e.g., blog.yoursite.com)
  • preload: Submit to browser preload lists (optional but recommended)

Warning: Once you set this header, browsers will refuse to connect via HTTP for the specified duration. Make sure HTTPS is working perfectly before implementing HSTS.

4. Content-Security-Policy (CSP)

This is the most powerful header. It tells the browser: “Only execute scripts from these trusted sources.”

Basic Implementation:

<IfModule mod_headers.c>
  Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://www.google-analytics.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;"
</IfModule>

Breaking it down:

  • default-src 'self': By default, only load resources from your own domain
  • script-src 'self' 'unsafe-inline': Allow scripts from your domain and inline scripts (needed for WordPress)
  • img-src 'self' data: https:: Allow images from your domain, data URIs, and any HTTPS source
  • style-src 'self' 'unsafe-inline': Allow styles from your domain and inline styles

Warning: CSP can break your site if misconfigured. Test in “report-only” mode first:

Header set Content-Security-Policy-Report-Only "default-src 'self'; report-uri /csp-report.php"

5. Referrer-Policy

Controls how much information is sent when a user clicks a link to another site.

Implementation:

<IfModule mod_headers.c>
  Header set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>

Nginx:

add_header Referrer-Policy "strict-origin-when-cross-origin" always;

This sends the full URL to same-origin requests, but only the origin (domain) to cross-origin requests.

Options:

  • no-referrer - Never send referrer information
  • no-referrer-when-downgrade - Don’t send referrer when going from HTTPS to HTTP
  • origin - Only send the origin
  • strict-origin - Only send origin, never when downgrading
  • same-origin - Full URL for same origin, no referrer for cross-origin
  • strict-origin-when-cross-origin - Full URL for same origin, origin only for cross-origin

6. Permissions-Policy (formerly Feature-Policy)

Disables browser features you don’t use (camera, microphone, geolocation).

Implementation:

<IfModule mod_headers.c>
  Header set Permissions-Policy "camera=(), microphone=(), geolocation=()"
</IfModule>

Nginx:

add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

Common directives:

  • camera=() - Disable camera access
  • microphone=() - Disable microphone access
  • geolocation=() - Disable geolocation
  • payment=() - Disable payment API
  • usb=() - Disable USB access

7. X-XSS-Protection

While largely superseded by CSP, this header provides additional XSS protection for older browsers.

<IfModule mod_headers.c>
  Header set X-XSS-Protection "1; mode=block"
</IfModule>

Part 4: Disable XML-RPC

xmlrpc.php is a legacy API file. In the modern era of REST API, it is obsolete. However, it is the #1 target for Brute Force attacks because it allows a hacker to try 500 passwords in a single HTTP request (the “multicall” method).

How to kill it:

Method 1: .htaccess

<Files xmlrpc.php>
  order deny,allow
  deny from all
</Files>

Method 2: functions.php

add_filter('xmlrpc_enabled', '__return_false');

Method 3: Nginx

location = /xmlrpc.php {
    deny all;
    access_log off;
    log_not_found off;
}

Exception: If you use Jetpack or WordPress mobile app, you need XML-RPC. In that case, use a plugin like “Disable XML-RPC Pingback” to block only the dangerous methods.


Part 5: Login Hardening

The /wp-admin/ and /wp-login.php endpoints are under constant attack. Here’s how to protect them.

1. Limit Login Attempts

By default, WordPress allows unlimited login attempts. A bot can try 10,000 passwords.

Solution: Install “Limit Login Attempts Reloaded” Or add this code:

function wppoland_limit_login_attempts() {
    $ip = $_SERVER['REMOTE_ADDR'];
    $attempts = get_transient('login_attempts_' . $ip);

    if ($attempts >= 5) {
        wp_die('Too many login attempts. Try again in 15 minutes.');
    }
}
add_action('wp_login_failed', function() {
    $ip = $_SERVER['REMOTE_ADDR'];
    $attempts = get_transient('login_attempts_' . $ip) ?: 0;
    set_transient('login_attempts_' . $ip, $attempts + 1, 15 * MINUTE_IN_SECONDS);
});

2. Two-Factor Authentication (2FA)

Even if a hacker gets your password, they can’t log in without the 2FA code.

Recommended Plugins:

  • WP 2FA (Official WordPress.org plugin)
  • Two Factor Authentication (by miniOrange)
  • Duo Two-Factor Authentication

3. Change the Login URL

By default, everyone knows your login is at /wp-login.php. Change it.

Plugin: WPS Hide Login

This changes the URL to something like /my-secret-login/. Bots scanning for /wp-login.php get a 404.

4. Disable User Enumeration

By default, you can discover usernames by visiting /?author=1.

Fix:

// Disable user enumeration
add_action('template_redirect', function() {
    if (is_author()) {
        wp_redirect(home_url(), 301);
        exit;
    }
});

// Block REST API user endpoint
add_filter('rest_endpoints', function($endpoints) {
    if (isset($endpoints['/wp/v2/users'])) {
        unset($endpoints['/wp/v2/users']);
    }
    if (isset($endpoints['/wp/v2/users/(?P<id>[\d]+)'])) {
        unset($endpoints['/wp/v2/users/(?P<id>[\d]+)']);
    }
    return $endpoints;
});

Part 6: Database Security

1. Change Table Prefix

By default, WordPress uses wp_ as the table prefix. This makes SQL injection easier.

During Installation: Set a custom prefix like xyz_ or prod_.

After Installation: Use a plugin like “Change Table Prefix” or manually update via PHPMyAdmin (advanced).

2. Disable File Editing

WordPress allows admins to edit theme/plugin files from the dashboard. If a hacker gets admin access, they can inject malware.

Disable it in wp-config.php:

define('DISALLOW_FILE_EDIT', true);

3. Secure wp-config.php

This file contains your database credentials. Protect it.

Move it one directory up: WordPress will still find it, but it’s outside the web root.

Or set strict permissions:

chmod 400 wp-config.php

Part 7: File Permissions

Often overlooked. If your file permissions are wrong, a hacker who compromises one plugin can rewrite your entire core.

The Golden Rules:

  • Directories: 755 (Read/Execute for everyone, Write only for owner)
  • Files: 644 (Read for everyone, Write only for owner)
  • wp-config.php: 400 or 440 (Read ONLY for owner/server)

Set them all at once:

find /path/to/wordpress -type d -exec chmod 755 {} \;
find /path/to/wordpress -type f -exec chmod 644 {} \;
chmod 400 wp-config.php

Part 8: Security monitoring

We do not recommend installing security plugins. Prefer server-level monitoring (log analysis, fail2ban, hosting WAF), regular backups, and hardening (strong passwords, updates, limited login attempts). Security is built through configuration and server measures, not plugins.


Part 9: Complete Security Checklist

Immediate Actions (Do Today)

  • Remove WordPress version from HTML/feeds
  • Remove version strings from CSS/JS
  • Set X-Frame-Options header
  • Set X-Content-Type-Options header
  • Set Strict-Transport-Security (HSTS) if using SSL
  • Disable XML-RPC (if not needed)
  • Install Limit Login Attempts
  • Change default “admin” username

Short-term Actions (This Week)

  • Implement Content-Security-Policy
  • Set Referrer-Policy
  • Enable Two-Factor Authentication
  • Change login URL
  • Disable user enumeration
  • Set correct file permissions (755/644)

Long-term Actions (This Month)

  • Change database table prefix (if possible)
  • Disable file editing in dashboard
  • Secure wp-config.php (400 permissions)
  • Install security monitoring plugin
  • Set up automated backups
  • Schedule regular security scans

FAQ

Q: Is hiding the WordPress version enough for security? A: No. While it helps prevent automated attacks, determined attackers can still fingerprint WordPress through other means. It should be combined with proper hardening measures.

Q: Will removing version strings break my site?

Q: Can security headers break my site?

Q: Should I disable XML-RPC if I use Jetpack?

Q: What’s the most important security measure?

Q: How often should I scan for malware?

Q: Is 2FA really necessary?


Summary: The Layered Security Approach

Security is not a product; it is a process.

  1. Hide info (remove version strings) - Security through obscurity
  2. Harden connection (HSTS, Headers, CSP) - Browser-level protection
  3. Close doors (Disable XML-RPC, limit logins) - Reduce attack surface
  4. Lock files (Permissions, disable editing) - Contain breaches
  5. Monitor (Security plugins, logs) - Detect and respond

Do this, and you are safer than 99% of WordPress sites out there.

Remember: Security is layered. No single measure is perfect, but together they create a fortress. Start with the basics (updates, strong passwords), add obscurity (hide version), then implement hardening (headers, permissions), and finally monitoring.

The goal isn’t to be unhackable—that’s impossible. The goal is to be a harder target than the next site, causing attackers to move on to easier prey.

Is hiding WordPress version enough for security?
No. Hiding the version is 'security through obscurity' - a first layer of defense, not sufficient on its own. You must combine it with proper hardening: security headers, 2FA, regular updates, and strong passwords.
What are the most important HTTP security headers for WordPress?
Critical headers: X-Frame-Options (prevents clickjacking), Content-Security-Policy (prevents XSS), Strict-Transport-Security/HSTS (forces HTTPS), X-Content-Type-Options (prevents MIME sniffing), and Referrer-Policy.
Should I disable XML-RPC in WordPress?
Yes, unless you use Jetpack, mobile apps, or external publishing tools. XML-RPC is a common attack vector for brute force attacks. Block it via .htaccess or use a security plugin.
Do security headers affect website performance?
No. HTTP security headers have zero impact on page load speed. They are simply metadata sent with each request that browsers use to enforce security policies.
Can hiding WordPress version break my site?
No. Removing the generator meta tag and version query strings from assets is completely safe and has no functional impact on your website.

Need an FAQ tailored to your industry and market? We can build one aligned with your business goals.

Let’s discuss

Related Articles