21 Oct 2026 Two critical RCE bugs in PHP core (CVE-2026-109618, CVE-2026-109619). Fixed in 8.2.35 / 8.3.36 / 8.4.27 / 8.5.12. Is my PHP patched? →
Checklamp
Exposed file · phpinfo

phpinfo() on a public URL: the full picture of your server

Published · updated

A single leftover file can publish the exact PHP build, every loaded extension, absolute paths, database hostnames and the environment variables of the process. It is the most complete reconnaissance page a server can offer.

Passive. Public responses only, nothing is attacked. No account. The result is on the page. Honest: if a value is hidden, we say so instead of guessing.
Reading public responses — usually 5–20 seconds

What the page actually contains

  • The exact PHP build — PHP Version 8.2.29. Unlike a header, it cannot be absent or approximate.
  • Loaded extensions and their versions — which tells an attacker which known bugs apply.
  • ini paths and values — where configuration lives, how large uploads may be, whether errors are displayed.
  • Environment variables — often DB_HOST, DB_USER, sometimes DB_PASSWORD, cloud keys and SMTP credentials.
  • Absolute paths, server software, the document root — the map for every later step.

With the build and the environment together, an attacker has both the vulnerability to try and, frequently, the credentials to skip it.

Where the leftovers come from

  1. Hosting “check” pages. Providers ship info.php or phpinfo.php to verify the stack and never remove them.
  2. Migrations. A test file created to prove the new server works, then forgotten in the deploy.
  3. Monitoring and panels. Old monitoring agents, /server-status and /server-info from Apache's mod_status and mod_info.
  4. Debug toolbars and framework pages left on in production — they can print the same values without the word phpinfo appearing anywhere.

Find them

# снаружи: обычные имена, что опрашивают боты
for p in phpinfo.php info.php test.php php_info.php server-info server-status; do
  printf '%-16s %s\n' "$p" "$(curl -s -o /dev/null -w '%{http_code}' "https://example.com/$p")"
done

# на сервере: ищем вызов по содержимому, а не по имени
grep -rl --include='*.php' 'phpinfo()' /var/www 2>/dev/null
find /var/www -name 'phpinfo*.php' -o -name 'info.php' -o -name 'test.php' 2>/dev/null

Check the result against the real page: a 200 can be the site's catch-all page rather than a phpinfo. The body must contain PHP Version and phpinfo() in the title. Our checker reports this as a critical finding, separately from the version header, because a hidden X-Powered-By next to an open info.php is a false sense of safety.

Close it, then assume it was read

  1. Delete the file. Not rename, not restrict — delete. A test page has no runtime purpose.
  2. Rotate what the page printed. Any credential that appeared in the environment section: database, SMTP, cloud keys. This is the step people skip and regret.
  3. Turn off expose_php so the build is not advertised in headers either, and set display_errors = Off in production.
  4. Block the patterns so the next leftover fails closed: deny phpinfo.php, info.php, /server-info, /server-status at the web server, and disable mod_info if it is not needed.
  5. Read the log. Requests for /phpinfo.php from addresses that are not yours, with a 200 in the same line, mean the page was harvested.

After the cleanup

Re-run the check: the finding should disappear and the build row should move to “not disclosed”. Then keep the release pipeline honest — a request to /phpinfo.php that returns 200 should fail the deploy, the same way an exposed .env should. A checksum baseline catches the next file that appears without a deploy.

Questions

Does deleting the file fix the leak if it was public for weeks?

It stops future reads. The leak already happened: rotate the credentials the page exposed and check access logs and admin activity.

Cloudflare hides my server — is a public phpinfo still a problem?

A CDN hides the origin only if direct requests to the origin are blocked. Otherwise the file is reachable by IP, and search engines or bots that find the IP skip the CDN entirely.

What is the difference between /server-info and phpinfo()?

/server-info lists Apache modules and configuration; phpinfo() prints the PHP side, including environment variables. Both are reconnaissance, and both should be closed.

Can I keep phpinfo but password-protect it?

You can, and it is still a liability: authentication on a diagnostic page is one misconfiguration away from public. Delete it and use the panel or the CLI when you need the same facts.