Qartvelo Guard Docs For system administrators
Early upload guard
Hold uploads sent to any PHP script with auto_prepend_file, set up per hosting panel, and remove it safely.
The plugin already holds every upload that goes through WordPress. The early guard is an optional extra for system administrators: it also holds uploads sent to any other PHP script on the site, such as an old contact form, a forgotten file manager or a backdoor someone planted, before that script can touch the file.
What auto_prepend_file is
auto_prepend_file is a PHP setting that names a file PHP runs before every PHP request. The guard uses it to load a small file, wpcybersec-guard.php, from your WordPress folder. That file runs before WordPress and does nothing unless the request carries uploaded files, so normal page views cost nothing.
When a request does carry files, the guard computes each file's SHA-256 fingerprint:
- Files you approved before pass.
- Every other file is copied into the quarantine and the request is refused with HTTP 403 and the message "This upload is waiting for administrator approval (Qartvelo Guard). After approval, send it again and it will go through."
- If the guard cannot check a file (disk full, file larger than 256 MB, quarantine full), it refuses the upload rather than letting it through.
Held uploads appear on the Reports page within about 10 minutes, or as soon as an administrator opens an admin page. Under Settings > Advanced > Early guard, "When an upload is held" can be changed from "Block the request" to "Remove the file and continue", which lets the script run without the file.
WordPress's own upload endpoints (the media uploader, plugin and theme uploads and the REST media route) are skipped by the guard by default, because the plugin's upload checks already handle them. These skips only apply to logged-in requests.
Install it with one click
Open Settings > Advanced > Early guard (or step 6 of the setup wizard) and press Install and switch on the early guard. The plugin then:
- Writes the guard files:
wpcybersec-guard.phpnext to wp-config.php and a configuration in the data folder. - Adds the setting to
.htaccess(when PHP runs as an Apache or LiteSpeed module) or to.user.ini(PHP-FPM, CGI or OpenLiteSpeed) in the WordPress folder. - Makes a live test request to your own site. If the site stops answering, everything is undone automatically.
The button is not shown when your server needs the setting in its own configuration, or when another prepend file is already in place. Then use the steps for your panel below.
What the status means
| Status | Meaning |
|---|---|
| Active | PHP loads the guard. |
| Active (confirmed by a live test) | The current page cannot tell by itself (for example in WP-CLI), but the last test request found the guard running. |
| Installed, not loaded yet | The files exist, but PHP does not load them yet. After a .user.ini change this is normal for up to 5 minutes. |
| Not installed | The guard is off. |
Use Test again to repeat the live test.
Set it up by hand
The plugin shows every line below with the real path of your site filled in; copy it from Settings > Advanced > Early guard. In the examples here, /var/www/example.com stands for your WordPress folder. First press Install the guard files (or Only install the guard files), so the file the setting points to exists.
cPanel
- Open Software > MultiPHP INI Editor, switch to Editor Mode and select the domain of the site.
- Add this line at the end and click Save:
auto_prepend_file = "/var/www/example.com/wpcybersec-guard.php"
cPanel writes it wherever the site's PHP handler reads it, so it works with PHP-FPM, CGI and LiteSpeed alike. On LiteSpeed, the account's PHP processes keep running; restart them as root with:
touch /home/ACCOUNT/.lsphp_restart.txt
CyberPanel and OpenLiteSpeed
OpenLiteSpeed ignores php_value lines in .htaccess. In CyberPanel open Websites > List Websites, click Manage next to the site and open vHost Conf. Put the line inside the braces of the phpIniOverride block, then Save:
phpIniOverride {
php_value auto_prepend_file /var/www/example.com/wpcybersec-guard.php
}
Keep any php_admin_value open_basedir line already in that block. lsphp keeps running in detached mode, so restarting OpenLiteSpeed alone is not enough. As root, restart the site's PHP processes, or all of them with killall lsphp:
touch /home/example.com/.lsphp_restart.txt
systemctl restart lsws
Turning CyberPanel's "open_basedir Protection" on or off rewrites the vHost file, so check afterwards that the line is still there. On plain OpenLiteSpeed, the same line goes into WebAdmin > Virtual Hosts > this site > General > php.ini Override.
About the one-click button on OpenLiteSpeed. It writes the setting to .user.ini, which lsphp reads only when user ini files are switched on (LSPHP_ENABLE_USER_INI=on in the lsphp external app's environment), and only after lsphp restarts. The Early guard card then shows the restart line for your site. As root, restart the PHP user's processes (or all of them), then press Test again:
touch /home/example.com/.lsphp_restart.txt
killall lsphp
If the test still says the guard is not loaded, add the vHost Conf line above instead, then run this and press Test again:
systemctl restart lsws && killall lsphp
Plesk
As the Plesk administrator open Websites & Domains > your domain > PHP Settings, add this line under "Additional directives" and click OK (customers cannot edit this field, so ask your host):
auto_prepend_file = "/var/www/vhosts/example.com/httpdocs/wpcybersec-guard.php"
The same from the command line:
echo 'auto_prepend_file = "/var/www/vhosts/example.com/httpdocs/wpcybersec-guard.php"' > /root/qartvelo-guard-php.ini
plesk bin site --update-php-settings example.com -additional-settings /root/qartvelo-guard-php.ini
aaPanel
aaPanel keeps its own .user.ini in the site folder (with the site's open_basedir line) and locks it with chattr +i. As root, unlock it, add the line and lock it again; keep the open_basedir line:
chattr -i /www/wwwroot/example.com/.user.ini
grep -q '^auto_prepend_file' /www/wwwroot/example.com/.user.ini || echo auto_prepend_file=/www/wwwroot/example.com/wpcybersec-guard.php >> /www/wwwroot/example.com/.user.ini
chattr +i /www/wwwroot/example.com/.user.ini
cat /www/wwwroot/example.com/.user.ini
Switching "Anti-XSS attack" off and on again in the site's settings writes the file anew with only the open_basedir line, so add the guard line again afterwards.
DirectAdmin
As the DirectAdmin administrator open Admin Level > Custom HTTPD Configurations, choose the domain, then the php-fpm configuration. Add this line in the second text area (CUSTOM2) and save:
php_admin_value[auto_prepend_file] = /home/USER/domains/example.com/public_html/wpcybersec-guard.php
Without administrator access, create .user.ini in the WordPress folder with File Manager (DirectAdmin reads .user.ini files by default) and put the php.ini line from the cPanel section in it, with your path.
nginx with PHP-FPM
nginx ignores .htaccess and .user.ini only applies to PHP-FPM itself, so the strongest option is the PHP-FPM pool of the site. php_admin_value cannot be changed by .user.ini or by PHP code:
php_admin_value[auto_prepend_file] = /var/www/example.com/wpcybersec-guard.php
systemctl reload php8.3-fpm
Or add it to the location ~ \.php$ block of the site next to the other fastcgi_param lines and reload nginx. PHP_VALUE replaces any other PHP_VALUE in the same block, and a shared pool may keep it for other sites, so prefer the pool setting when the pool is shared:
fastcgi_param PHP_VALUE "auto_prepend_file=/var/www/example.com/wpcybersec-guard.php";
On PHP-FPM, a .user.ini file in the WordPress folder also works; PHP reads it again within 5 minutes:
; BEGIN Qartvelo Guard Guard
auto_prepend_file = "/var/www/example.com/wpcybersec-guard.php"
; END Qartvelo Guard Guard
Apache
When PHP runs as an Apache module (mod_php), LiteSpeed Enterprise or CloudLinux mod_lsapi, add this to the .htaccess file in the WordPress folder. Each line is wrapped in IfModule, so other servers ignore it instead of failing. The plugin's version of the block covers every PHP module name; this is the short form:
# BEGIN Qartvelo Guard Guard
<IfModule php_module>
php_value auto_prepend_file "/var/www/example.com/wpcybersec-guard.php"
</IfModule>
<IfModule LiteSpeed>
php_value auto_prepend_file "/var/www/example.com/wpcybersec-guard.php"
</IfModule>
# END Qartvelo Guard Guard
With Apache and PHP-FPM, use the PHP-FPM pool line or .user.ini instead.
Other panels
The plugin has steps for HestiaCP, VestaCP, CloudPanel, CWP, ISPConfig, Virtualmin, RunCloud, SpinupWP, Laravel Forge, Ploi, Cloudways, Hostinger, GridPane, FASTPANEL, ISPmanager, DDEV and several managed hosts. They appear on the Early guard card when the plugin detects the panel or you choose it. See Hosting panels.
When the WordPress front controller (index.php) is in another folder than WordPress, as with Bedrock or WordPress in a subfolder, the plugin shows both folders; add the line in both.
Conflicts with other prepend files
PHP accepts only one auto_prepend_file. If another file is already set, the one-click button is hidden and the card explains your two options.
Wordfence and other firewalls on the same site
The Wordfence firewall uses wordfence-waf.php this way. Both can run:
- Point auto_prepend_file at
wpcybersec-guard.phpinstead. The guard remembers the other file and includes it first, so the firewall keeps working. - Or add this line at the top of the other prepend file, so it loads the guard too:
if ( file_exists( '/var/www/example.com/wpcybersec-guard.php' ) ) { include_once '/var/www/example.com/wpcybersec-guard.php'; }
"That file belongs to another WordPress site"
This error means PHP runs a prepend file from a different WordPress installation before every request, usually a wordfence-waf.php left over from copying a site. Your site then depends on the other site and runs its firewall with the other site's settings. The plugin never chains such a file. To fix it:
- Remove the auto_prepend_file line that points to it. Look in
.user.iniand.htaccessin this site's folder, in the PHP settings of the hosting panel, in the web server's settings for this site and in the main php.ini of the PHP version. - Restart PHP.
- If this site uses Wordfence, run Wordfence > Firewall > Optimize the Wordfence Firewall again, so it creates this site's own file.
- Install the early guard.
A real case on CyberPanel. A site copied from another one kept the original site's Wordfence line, /home/othersite.com/public_html/wordfence-waf.php. It sat in the main php.ini of lsphp, so it ran for every site on that PHP version. To find where the line is set, as root:
grep -rn auto_prepend_file /usr/local/lsws/lsphp*/etc/
grep -n auto_prepend_file /home/example.com/public_html/.user.ini /home/example.com/public_html/.htaccess
grep -n auto_prepend_file /usr/local/lsws/conf/vhosts/example.com/vhost.conf
Removing it from a shared php.ini removes it for the original site too. Give that site its firewall back in its own settings: in CyberPanel open Websites > List Websites > Manage next to the original site, then vHost Conf, and add the line inside the phpIniOverride block. Or run Wordfence > Firewall > Optimize the Wordfence Firewall again on that site.
phpIniOverride {
php_value auto_prepend_file /home/othersite.com/public_html/wordfence-waf.php
}
Then restart lsphp and install the guard on this site:
systemctl restart lsws && killall lsphp
Remove it safely
Press Uninstall on the Early guard card. This switches the guard off, imports any uploads still waiting and deletes its configuration. It does not remove the auto_prepend_file line you or your panel added, so do that next, in this order:
- Remove the auto_prepend_file line from where it was added.
- Wait until PHP no longer uses it: up to 5 minutes for .user.ini, or reload PHP.
- Delete
wpcybersec-guard.php. The plugin deletes it for you when nothing points to it any more.
Deactivating the plugin switches the guard off too: the file stays, but without its configuration it does nothing. If you delete the plugin with "Delete all plugin data" turned on, the plugin also removes its own marked blocks from .user.ini and .htaccess. Lines you added by hand in a panel stay. See Uninstall.