WordPress wp-admin 403 on load-styles.php / load-scripts.php (Wordfence WAF / auto_prepend_file)

Summary

After a WordPress or plugin update, some sites suddenly see a broken wp-admin screen:

  • Login works, but the admin dashboard looks unstyled, blank, or half-loaded.
  • Browser DevTools → Network shows 403 Forbidden for:
    • wp-admin/load-styles.php
    • wp-admin/load-scripts.php
  • Disabling plugins from wp-admin, or even renaming wp-content/plugins, does not fix the 403.

In many cases, the root cause is Wordfence Web Application Firewall (WAF) still being loaded via auto_prepend_file in .htaccess and/or .user.ini, even after the plugin is disabled.

 

Symptoms

  • WordPress admin loads partially or without CSS/JS.
  • In your browser’s DevTools → Network tab:
    • wp-admin/load-styles.php and/or wp-admin/load-scripts.php show 403 Forbidden.
  • Apache error log shows lines similar to:
    [authz_core:error] AH01630: client denied by server configuration: /home/USER/public_html/wp-admin/load-styles.php
    [authz_core:error] AH01630: client denied by server configuration: /home/USER/public_html/wp-admin/load-scripts.php
  • Renaming wp-content/plugins or disabling plugins from the dashboard does not resolve the error.

 

Root Cause

When Wordfence WAF is enabled in Extended Protection mode, it is not just a normal WordPress plugin. It also injects itself into PHP via auto_prepend_file.

Specifically, Wordfence:

  1. Adds an auto_prepend_file directive to your PHP configuration via:
    • .htaccess (Apache)
    • .user.ini (per-directory PHP settings)
  2. Points that directive to a bootstrap file such as:
    # In .htaccess
    php_value auto_prepend_file /home/USER/public_html/wordfence-waf.php
    
    ; In .user.ini
    auto_prepend_file = "/home/USER/public_html/wordfence-waf.php"
    

This forces every PHP request (frontend, wp-admin, AJAX, cron, etc.) to load wordfence-waf.php before WordPress. Even if you disable or remove the Wordfence plugin, the WAF bootstrap can still:

  • Block specific paths (e.g. load-styles.php, load-scripts.php, wp-cron.php), or
  • Fail due to outdated/mismatched code after a WordPress or PHP upgrade.

Because this runs at the PHP / Apache level, simply disabling the plugin in wp-admin is not enough.

 

How to Confirm It’s Wordfence / auto_prepend_file

1. Check Apache / PHP error logs

Look in your virtual host or global Apache error log for lines like:

[authz_core:error] AH01630: client denied by server configuration: /home/USER/public_html/wp-admin/load-styles.php
[authz_core:error] AH01630: client denied by server configuration: /home/USER/public_html/wp-admin/load-scripts.php

If you see 403s on these WordPress core endpoints and normal plugin disabling doesn’t help, suspect WAF / auto_prepend_file.


2. Check .user.ini in the document root

  1. Via SSH or file manager, go to your site root (for example /home/USER/public_html).
  2. Open .user.ini and look for a line similar to:
    auto_prepend_file = "/home/USER/public_html/wordfence-waf.php"


3. Check .htaccess for Wordfence WAF

  1. In the same directory, open .htaccess.
  2. Search for a Wordfence WAF block, for example:
    # Wordfence WAF
    # <IfModule mod_php7.c>
    php_value auto_prepend_file /home/USER/public_html/wordfence-waf.php
    # </IfModule>

If these exist, Wordfence WAF is still being injected into every PHP request, even if the plugin is deactivated.

 

Fix: Properly Decommission Wordfence WAF

Warning: Only do this if you intend to disable Wordfence WAF. If you still want Wordfence, use its own UI to reconfigure Extended Protection.


Step 1: Disable Wordfence plugin (if possible)

  1. Log in to wp-admin.
  2. Go to PluginsInstalled Plugins.
  3. Deactivate Wordfence Security.

If wp-admin is completely broken, you can skip this step and go directly to editing files.

Step 2: Remove auto_prepend_file from .user.ini

  1. In your WordPress document root, open .user.ini.
  2. Find the Wordfence line:
    auto_prepend_file = "/home/USER/public_html/wordfence-waf.php"
  3. Comment it or remove it, for example:
    ; auto_prepend_file = "/home/USER/public_html/wordfence-waf.php"
  4. Save the file.

Step 3: Remove auto_prepend_file from .htaccess

  1. In the same directory, open .htaccess.
  2. Look for the Wordfence WAF block, e.g.:
    # Wordfence WAF
    <IfModule mod_php7.c>
        php_value auto_prepend_file /home/USER/public_html/wordfence-waf.php
    </IfModule>
  3. Comment it out or remove it:
    # Wordfence WAF disabled
    # <IfModule mod_php7.c>
    #     php_value auto_prepend_file /home/USER/public_html/wordfence-waf.php
    # </IfModule>
  4. Save the file.

Step 4: Clear opcode cache / restart PHP (optional but recommended)

  • If you’re using PHP-FPM / LSAPI / FastCGI, restart PHP-FPM or LiteSpeed / Apache.
  • Alternatively, ask your hosting provider to clear PHP opcache for that account.

Step 5: Test wp-admin

  1. Open /wp-admin/ in your browser.
  2. Open DevTools → Network, then reload the page.
  3. Verify:
    • wp-admin/load-styles.php returns 200 OK.
    • wp-admin/load-scripts.php returns 200 OK.
    • The admin interface looks normal again (CSS/JS loaded).

If you previously added any temporary overrides (for example a wp-admin/.htaccess that unconditionally allowed those files), you can remove them once everything works normally.

 

Optional: Cleaning Up Wordfence Files

If you are completely done with Wordfence, you can also:

  • Delete or rename:
    • wp-content/plugins/wordfence/
    • wp-content/wflogs/ (log directory)
  • Remove wordfence-waf.php from your document root if it is no longer referenced anywhere.

Preventing Future Issues

  • Be aware that security plugins with WAF / “Extended Protection” can modify:
    • .htaccess
    • .user.ini
    • Global PHP behavior via auto_prepend_file
  • Disabling the plugin from the dashboard does not automatically remove these low-level hooks.
  • If you see strange 403s or “client denied by server configuration” on core WordPress files like load-styles.php, load-scripts.php, or wp-cron.php, always check for:
    • auto_prepend_file lines in .user.ini and .htaccess.
    • Leftover WAF bootstrap files such as wordfence-waf.php.

Summary

Issue: WordPress admin broken, load-styles.php / load-scripts.php returning 403, even after disabling plugins.

Cause: Wordfence WAF still injected via auto_prepend_file in .htaccess / .user.ini, loading wordfence-waf.php on every request and blocking those endpoints.

Fix:

  1. Disable Wordfence plugin (if possible).
  2. Remove auto_prepend_file references to wordfence-waf.php from .htaccess and .user.ini.
  3. Reload PHP / Apache and retest wp-admin — the 403s on load-styles.php / load-scripts.php should disappear.

Comments

  Add Comment

Confirm Submission

Please enter the text from the image in the box provided; this helps us to prevent spam.