Skip to content
Shahid Malla

How to Check and Fix an Exposed .git Folder on a WHMCS Server

A complete step-by-step guide to testing, fixing, and preventing exposed .git repository leaks in WHMCS environments.

· Published · Updated · 7 min read
On this page (9 sections)

To check whether a WHMCS site exposes its .git folder, request https://yourdomain.com/.git/HEAD and /.git/config. If either returns repository content instead of a 403 or 404, anyone can download the Git history and rebuild your code, including any configuration.php that was ever committed. Move .git out of the web root, block it at the web server and rotate the leaked secrets.

Only test servers you own or administer.

Why does an exposed .git folder matter for WHMCS?

Because Git keeps every committed version of every file under .git, and a web server that serves the folder lets a tool fetch those objects and rebuild the project, old versions and deleted files included. A 403 on /.git/ proves little. It usually means directory listing is off, while the individual files inside stay downloadable.

Requesting configuration.php in a browser returns a blank page, because PHP runs it. The danger is the copy in the Git history. These are the variables the WHMCS configuration.php documentation lists that matter most if that copy leaks:

VariableWhat it isWhat a leak gives away
$db_host, $db_name, $db_username, $db_passwordDatabase connection detailsFull access to client, invoice and ticket data wherever the database accepts the connection
$cc_encryption_hashThe key WHMCS needs to decrypt stored dataCombined with a database copy, the encrypted fields become readable
$api_access_keyThe installation's API access keyWith valid API credentials, a way around your API IP restriction, as the API access control page explains
$licenseThe WHMCS license keyYour license identity
$customadminpathThe renamed admin folderThe admin login URL you hid

How do I test whether my .git folder is exposed?

Fetch HEAD and config from outside the server, and read the body, not only the status code.

curl -s -o /dev/null -w "%{http_code}\n" https://yourdomain.com/.git/HEAD
curl -s https://yourdomain.com/.git/HEAD
curl -s https://yourdomain.com/.git/config
  • Exposed: status 200 and a body such as ref: refs/heads/main, or a config file that starts with [core].
  • Blocked: status 403 or 404.
  • Unclear: a 200 with your site's error page. Some sites answer every missing URL that way. That is not an exposure, but it is not proof of protection either.

In the same pass, test the other files scanners look for: /.env, /.svn/entries, and any .zip or .sql backup left in the web root.

How do I see what an attacker could recover?

Run the same kind of tool an attacker would, against your own site, and search what it rebuilds. I use git-dumper. Its own README warns that dumping a repository an attacker controls could lead to code execution on your machine, so if the site may already be compromised, run it in a throwaway virtual machine.

pip install git-dumper
git-dumper https://yourdomain.com/.git ./dumped-repo
cd dumped-repo
git log --all --oneline -- configuration.php     # was it ever committed?
git log --all --oneline -S cc_encryption_hash    # did the hash appear anywhere?

If the tool downloads anything, the folder is exposed. If git log lists commits for configuration.php, its secrets are recoverable even if you deleted the file later. Keep the dump private, because it holds your real secrets, and delete it when you finish.

How do I fix an exposed .git folder?

Move .git out of the web root, then test again. On cPanel the web root is inside the account's home directory, usually /home/USER/public_html. Move the folder rather than deleting it, because deleting it destroys the history.

find /home/USER/public_html -maxdepth 4 -name ".git" -prune
mv /home/USER/public_html/.git /home/USER/git-backup

If you deploy by running git pull inside public_html, that now stops working. Keep a bare repository outside the web root and check out only the files, with a post-receive hook:

#!/bin/sh
# /home/USER/repos/site.git/hooks/post-receive  (make it executable)
git --work-tree=/home/USER/public_html --git-dir=/home/USER/repos/site.git checkout -f main

Which web server rules block .git on Apache, LiteSpeed and Nginx?

Add a rule as a second layer, so a future git clone into the web root cannot expose history again. The right rule depends on the server, because not every server reads every .htaccess directive.

ServerWhere the rule goesWhat the documentation says
Apache.htaccess or the virtual hostRedirectMatch and <FilesMatch> are allowed in .htaccess. <DirectoryMatch> works only in the server or virtual host configuration
LiteSpeed and OpenLiteSpeed.htaccess, as a rewrite ruleOpenLiteSpeed reads only rewrite rules from .htaccess, not other directives
NginxEach server blockNginx ignores .htaccess. Regex locations are checked in the order they appear, and the first match wins

The rewrite rule is the portable option. It works on Apache with mod_rewrite and on both LiteSpeed editions, as the OpenLiteSpeed access control guide shows with its own [F,L] examples:

# .htaccess in the WHMCS root (Apache, LiteSpeed, OpenLiteSpeed)
RewriteEngine On
RewriteRule (^|/)\.(git|svn|hg)(/|$) - [F,L]

On Apache alone, RedirectMatch returns a 404 instead, and FilesMatch covers single files such as .env:

RedirectMatch 404 /\.(git|svn|hg)(/|$)
<FilesMatch "^\.env">
    Require all denied
</FilesMatch>

On cPanel, put virtual host rules such as <DirectoryMatch> in an include file, for example /etc/apache2/conf.d/userdata/ssl/2_4/USER/DOMAIN/block-vcs.conf plus the matching std path, then run /usr/local/cpanel/scripts/rebuildhttpdconf and /usr/local/cpanel/scripts/restartsrv_httpd, as cPanel's include file documentation describes. Direct edits to httpd.conf are lost when it is rebuilt.

On Nginx, place this before any other regex location, such as the one that passes .php files to PHP-FPM, as the location documentation explains. Then reload Nginx and test again.

location ~ /\.(git|svn|hg)(/|$) {
    return 404;
}

What do I rotate if the folder was exposed?

Every secret that ever sat in the repository, because you cannot prove nobody downloaded it. Search the domain's access logs for requests containing /.git/. On cPanel you can download them from Metrics > Raw Access. A hit from an address you do not know confirms a download. No hits proves little, because logs rotate.

What leakedWhat to do
Database passwordChange it for the database user, then update $db_password in configuration.php
Staff logins and API credentialsReset staff passwords and two-factor, remove admin accounts you do not recognize, replace API credentials and set a new $api_access_key
Payment gateway and registrar keysGenerate new keys in each provider's dashboard and enter them in WHMCS
Server and panel accessSSH keys, cPanel, FTP and SMTP passwords, deploy tokens and DNS API tokens found in the repository
$cc_encryption_hashTreat it as known, but do not simply type a new value. WHMCS says the system cannot decrypt your data without the original. Ask WHMCS support for the procedure for your version

How do I remove configuration.php from the repository history?

Stop tracking it, ignore it, then rewrite the history in a fresh clone with git filter-repo. This keeps the secret out of future clones. It does not un-leak anything, which is why the rotation above comes first.

git rm --cached configuration.php
printf 'configuration.php\n.env\n*.sql\n*.zip\n' >> .gitignore
git add .gitignore
git commit -m "Stop tracking configuration.php"

# in a fresh clone:
git filter-repo --sensitive-data-removal --invert-paths --path configuration.php
git remote add origin YOUR-REMOTE-URL
git push --force --all

The git filter-repo documentation says it aborts on a repository that is not a fresh clone and removes the origin remote, which is why you add it back. In recent versions, --sensitive-data-removal also prints instructions for cleaning the server copy and other clones. Everyone with a clone must clone again.

How do I check whether someone already used the leak?

Look for changes you did not make.

  • Compare your files with a clean copy of the same WHMCS release, using diff -rq.
  • List recently changed PHP files with find /home/USER/public_html -type f -name "*.php" -mtime -7.
  • Check the account's cron jobs with crontab -l.
  • Read the Activity Log and Admin Log at Configuration > System Logs for logins and setting changes you cannot explain.

What are the limits of this fix?

  • Blocking is not cleaning. A rule stops future downloads. Anything already downloaded stays leaked until you rotate it.
  • Your tests cover only the paths you try. A backup archive or a second repository in a subfolder can leak the same secrets.
  • History rewrites affect your team. Old clones still hold the file until people delete them.
  • New servers forget old rules. Repeat the test after every migration or web server change.

For the rest of the server, see my WHMCS firewall and server hardening checklist, and if you would rather have an independent review, my WHMCS security audit covers the install and server security hardening covers the machine under it.

Last reviewed 12 October 2026. Disclosure: I sell WHMCS security and development work, so I am not neutral. I am CTO at ElySpace, a freelance developer for Marmaids LLC, and founder of WHMCSPilot and MagizAI.

Share this article

Shahid Malla

Written by

Shahid Malla

Freelance WHMCS developer and web designer with 13+ years of client work. CTO at ElySpace, freelance developer for Marmaids LLC, and founder of WHMCSPilot and MagizAI.

Got a project like this?

Tell me what you need and I will send a written quote within one business day.