whiteweb.security / guides / PHP config exposed
config.php / db.php High severity ~6 min read

My PHP configuration file got exposed. What should I do?

PHP configuration files — config.php, db.php, database.php, settings.php — typically store database credentials, API keys, and application secrets as PHP variables. When these files are served as plain text instead of being executed by PHP, every credential inside is readable to anyone who requests the URL.

PHP files should never be served as plain text — this is a server misconfiguration.

Normally, PHP files are executed by the PHP interpreter and the output (HTML, JSON, etc.) is sent to the browser — the source code is never visible. If the raw PHP source was served, your web server's PHP handler is not configured for that file extension or path. Fix the misconfiguration first, then rotate credentials.

// the 60-second version

  • Fix the PHP handler misconfiguration so .php files are executed, not served as text.
  • Change the database password and rotate every other credential in the file.
  • Move config files above the web root so they can never be directly requested.
  • Check access logs for the exposure window and investigate suspicious activity.

01Understand what your PHP config file contains

PHP configuration files vary in structure, but they almost universally contain database connection credentials as PHP variables:

typical PHP config file contentsconfig.php
// Database credentials — fully exposed as plain text define('DB_HOST', 'localhost'); define('DB_USER', 'webapp'); define('DB_PASS', 'hunter2'); define('DB_NAME', 'production_db'); // API keys — also exposed define('STRIPE_SECRET_KEY', 'sk_live_...'); define('SENDGRID_API_KEY', 'SG...');

Beyond the obvious credentials, also look for: salts for password hashing (if these are exposed, rainbow tables can be precomputed for your specific salt), admin panel URLs or secret tokens used to protect admin access, and any OAuth client secrets for third-party integrations.

If your database port is publicly reachable (MySQL on port 3306, PostgreSQL on 5432), the exposed credentials may allow direct database access from the internet — not just through your application. Check your firewall rules immediately.

02Block access and fix the PHP handler

First, determine why PHP source is being served as text. The most common causes are a missing or broken fastcgi_pass directive in Nginx, or PHP-FPM not running. Check whether PHP is executing at all:

diagnose PHP handlerbash
# check if PHP-FPM is running systemctl status php8.2-fpm # check nginx config has PHP handling grep -n "fastcgi_pass\|\.php" /etc/nginx/sites-enabled/default

A correct Nginx PHP handler block looks like this:

correct PHP handler in nginx/etc/nginx/sites-enabled/…
location ~ \.php$ {
    include        snippets/fastcgi-php.conf;
    fastcgi_pass   unix:/run/php/php8.2-fpm.sock;
}

While fixing the PHP handler, also add an explicit deny rule for config file names as a belt-and-suspenders measure:

deny direct access to config files/etc/nginx/sites-enabled/…
location ~* (config|database|db|settings|credentials)\.php$ { deny all; return 404; }

03Change the database password immediately

Connect to the database as an administrative user and change the application user's password:

change the database user passwordMySQL / MariaDB
-- connect as root ALTER USER 'webapp'@'localhost' IDENTIFIED BY 'new-strong-random-password'; FLUSH PRIVILEGES; -- also restrict to only allow local connections if not already -- (check with: SELECT Host, User FROM mysql.user;)

Then update the config file with the new password, and restart your application to confirm it still connects. Also revoke and replace any API keys present in the file through each provider's dashboard.

04Move config files above the web root

The safest long-term fix is to store configuration files in a directory that the web server cannot serve. Place them one level above /var/www/html/:

move config outside web rootbash + PHP
# move config to a directory above the web root mkdir -p /var/www/config mv /var/www/html/config.php /var/www/config/config.php chmod 640 /var/www/config/config.php chown www-data:www-data /var/www/config/config.php
include config from outside web rootPHP
// In your application entry point: require_once dirname(__DIR__) . '/config/config.php'; // Or use an absolute path: require_once '/var/www/config/config.php';

The web server can only serve files inside the document root (e.g., /var/www/html/). A file at /var/www/config/ is readable by the PHP process (which runs as www-data) but cannot be requested via HTTP.

05Review access logs and check for exploitation

Determine the exposure window and look for suspicious activity in that period:

find requests to the config filebash
# find 200 responses for config file requests grep -E "(config|database|db|settings)\.php" /var/log/nginx/access.log \ | grep " 200 " # check MySQL general log for unusual queries (if enabled) tail -100 /var/log/mysql/mysql.log

If the database port was publicly accessible and credentials were exposed, also check your database logs for connections from external IP addresses. Any legitimate connections from your application server should come from localhost or a known internal IP.

Consider switching from PHP define constants to loading credentials from environment variables using $_ENV['DB_PASS'] or getenv('DB_PASS'). Set these in your web server config or a .env file loaded via a library like PHP dotenv — keeping the actual values out of any file that lives in the repository.

Was this guide useful?

These playbooks are free to read and share. If a heads-up ever saved you a bad week, you can say thanks — or jump into the other guides.