WordPress OSINT, maintenance or security needs? Reach out!
TLDWP

WordPress Security Guide

Understanding security exposures and missing headers detected by our scanner. Click any item to learn what it means, why it matters, and how to fix it.

Exposed Files

Debug Log High Severity

Path: /wp-content/debug.log

What is it?

When WordPress debugging is enabled, PHP errors, warnings, and notices are written to a file called debug.log. This file is meant for developers to troubleshoot issues during development.

Why is it dangerous?

  • Reveals server file paths (helps attackers map your system)
  • Shows which plugins/themes have errors (identifies weak points)
  • May contain database query errors (can expose table structure)
  • Can contain sensitive data logged by poorly coded plugins
  • Signals to attackers that debugging is enabled

How to fix it

Option 1: Disable debugging in wp-config.php:

define('WP_DEBUG', false);
define('WP_DEBUG_LOG', false);

Option 2: Block access via .htaccess (Apache):

<Files debug.log>
    Order allow,deny
    Deny from all
</Files>

Option 3: Block access via Nginx:

location ~* debug\.log$ {
    deny all;
}

Option 4: Delete the file if you don't need it:

rm wp-content/debug.log

Error Log High Severity

Path: /error_log or /error.log

What is it?

The PHP error log captures runtime errors from your server. It's similar to debug.log but is created by PHP itself rather than WordPress.

Why is it dangerous?

  • Contains full server file paths
  • May reveal database connection errors with credentials
  • Shows PHP version and configuration details
  • Exposes application logic through stack traces

How to fix it

Move error logs outside the web root in php.ini:

error_log = /var/log/php/error.log

Or block access via .htaccess:

<Files ~ "^error[_\.]?log$">
    Order allow,deny
    Deny from all
</Files>

PHP Info Medium Severity

Common paths: /info.php, /phpinfo.php, /php.php, /i.php

What is it?

A PHP file containing phpinfo() which outputs detailed information about your server's PHP configuration. Often left behind after initial server setup or debugging.

Why is it dangerous?

  • Reveals exact PHP version (allows targeting known vulnerabilities)
  • Shows all loaded PHP modules
  • Displays server paths and environment variables
  • May expose database hostnames and internal IPs
  • Shows email configuration (SMTP settings)

How to fix it

Simply delete the file:

rm info.php phpinfo.php php.php i.php

If you need phpinfo for debugging, protect it:

<Files "phpinfo.php">
    Require ip 127.0.0.1
    Require ip YOUR.IP.ADDRESS
</Files>

Install.php Critical Severity

Path: /wp-admin/install.php

What is it?

The WordPress installation script. On a properly configured site, this should not be accessible after initial setup.

Why is it dangerous?

  • An attacker could potentially reinstall WordPress
  • If database tables are dropped, the installer becomes active again
  • Can be used to create a new admin account
  • Indicates the site may have configuration issues

How to fix it

Block access via .htaccess:

<Files install.php>
    Order allow,deny
    Deny from all
</Files>

Or via Nginx:

location = /wp-admin/install.php {
    deny all;
}

XML-RPC Medium Severity

Path: /xmlrpc.php

What is it?

XML-RPC is a remote procedure call protocol that allows external applications to communicate with WordPress. It was used for features like pingbacks, the mobile app, and remote publishing.

Why is it dangerous?

  • Brute force amplification: Attackers can try hundreds of passwords in a single request
  • DDoS attacks: Can be used in pingback-based DDoS attacks
  • Username enumeration: Reveals valid usernames
  • Most sites don't need it (REST API replaced most functions)

How to fix it

Block access via .htaccess:

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

Or disable via plugin or functions.php:

add_filter('xmlrpc_enabled', '__return_false');

Note: If you use the WordPress mobile app or Jetpack, you may need XML-RPC enabled.

Exposed Directories Medium Severity

Common paths: /backup/, /dev/, /staging/, /old/, /test/

What is it?

Directories that are publicly accessible and may contain sensitive files, backups, or development code that shouldn't be exposed to the internet.

Why is it dangerous?

  • Backup folders: May contain database dumps with all your data
  • Dev/staging folders: Often have debugging enabled and weaker security
  • Old folders: May contain outdated, vulnerable WordPress versions
  • Directory listing shows all files to attackers

How to fix it

Disable directory listing in .htaccess:

Options -Indexes

Or remove/protect the directories:

# Delete if not needed
rm -rf /var/www/html/backup/

# Or password protect
<Directory "/var/www/html/backup">
    AuthType Basic
    AuthName "Restricted"
    AuthUserFile /etc/apache2/.htpasswd
    Require valid-user
</Directory>

Security Headers

Security headers are HTTP response headers that tell browsers how to behave when handling your site's content. They add an extra layer of protection against common attacks.

HSTS (Strict-Transport-Security) Medium Severity

What is it?

HSTS tells browsers to only connect to your site via HTTPS, even if the user types http:// or clicks an HTTP link.

Why is it important?

  • Prevents SSL stripping attacks (man-in-the-middle)
  • Protects users on public WiFi
  • Ensures all traffic is encrypted

How to add it

Apache (.htaccess):

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

Nginx:

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

CSP (Content-Security-Policy) Medium Severity

What is it?

CSP tells the browser which sources of content (scripts, styles, images, etc.) are allowed to load. It's a powerful defense against cross-site scripting (XSS) attacks.

Why is it important?

  • Blocks malicious scripts injected by attackers
  • Prevents unauthorized content from loading
  • Stops clickjacking attempts

How to add it

Start with a report-only policy to test:

Content-Security-Policy-Report-Only: default-src 'self';

Basic production policy:

Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';

Note: CSP requires careful configuration. Test thoroughly before enabling.

X-Content-Type-Options Low Severity

What is it?

This header prevents browsers from "sniffing" the content type and interpreting files differently than declared.

Why is it important?

  • Prevents MIME-type confusion attacks
  • Stops browsers from executing uploaded files as scripts

How to add it

Apache:

Header always set X-Content-Type-Options "nosniff"

Nginx:

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

X-Frame-Options Medium Severity

What is it?

Controls whether your site can be embedded in frames/iframes on other sites.

Why is it important?

  • Prevents clickjacking attacks
  • Stops attackers from embedding your site in a malicious page

How to add it

Apache:

Header always set X-Frame-Options "SAMEORIGIN"

Nginx:

add_header X-Frame-Options "SAMEORIGIN" always;

Referrer-Policy Low Severity

What is it?

Controls how much referrer information is sent when users click links to other sites.

Why is it important?

  • Protects user privacy
  • Prevents leaking sensitive URLs (e.g., password reset links)

How to add it

Apache:

Header always set Referrer-Policy "strict-origin-when-cross-origin"

Nginx:

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

Permissions-Policy Low Severity

What is it?

Controls which browser features (camera, microphone, geolocation, etc.) your site can use. Formerly known as Feature-Policy.

Why is it important?

  • Limits attack surface by disabling unused features
  • Prevents malicious scripts from accessing sensitive APIs

How to add it

Apache:

Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"

Nginx:

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