Current situation: PHP2Shell. Two critical PHP vulnerabilities (CVSS 9.2) allow malicious code without login. Patches since 21 October 2026.What to do now →

Using PHP disable_functions correctly

With disable_functions you block risky PHP functions. How to define the list to suit your application without taking the website down.

Last updated 5 min readGuides

In short: With PHP disable_functions you block functions through which PHP executes system commands, such as exec, shell_exec or proc_open. This makes the next step harder for attackers after a break-in. The setting works only from php.ini or the FPM pool, must suit the application and does not replace an update.

Why disable_functions makes sense right now

PHP2Shell is about remote code execution without authentication. The two vulnerabilities CVE-2026-109618 and CVE-2026-109619 sit in the PHP interpreter itself and are fixed in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35. The update is the only way to close them.

Hardening starts one layer later. Anyone who can execute code on a server once usually wants to go further: start system commands, download tools, set up a permanent backdoor. Many of these steps run through a few PHP functions. If they are blocked, the path becomes more laborious and more conspicuous.

disable_functions is therefore no substitute for patches but a building block for the case that something gets through despite all precautions. That applies to future vulnerabilities just as much as to PHP2Shell.

What PHP disable_functions achieves and what it does not

The setting removes the named functions from the runtime environment. If a script calls a blocked function, PHP aborts with an error. The block applies to any code running in this PHP process, including planted code.

You should know the limits:

  • The setting is not a sealed protective space. PHP extensions, flaws in the interpreter or programs outside PHP can bypass it.
  • It does not prevent an attacker from reading or writing files that the PHP user has access to. File permissions and isolation are responsible for that.
  • It works only from php.ini or as php_admin_value. It cannot be set with ini_set(), .user.ini or .htaccess.

disable_functions brings the most together with a clean php.ini, separate users per website and restrictive file permissions. The basics are in the guide Configuring php.ini securely.

Which functions you should block

For typical websites with no need for system commands, the following list has proved its worth. It covers functions for starting processes and controlling running processes.

Group Functions Typical legitimate use
Executing commands exec, shell_exec, system, passthru Image processing, backups via script
Opening processes proc_open, popen Composer, PDF tools, mail delivery
Controlling processes proc_nice, proc_terminate, proc_get_status Queues, background jobs
Process management pcntl_exec, pcntl_fork Mostly only on the command line
Signals and permissions posix_kill, posix_setuid Rarely in web operation

As a configuration it looks like this:

; php.ini of the web operating mode, e.g. /etc/php/8.3/fpm/php.ini
disable_functions = exec,shell_exec,system,passthru,proc_open,popen,proc_nice,proc_terminate,proc_get_status,pcntl_exec,pcntl_fork,posix_kill,posix_setuid

If the list does not apply to all websites on the server, set it per FPM pool. After reloading, check which list actually applies in that pool:

; /etc/php/8.3/fpm/pool.d/meine-seite.conf (Auszug)
php_admin_value[disable_functions] = exec,shell_exec,system,passthru,proc_open,popen

Test the application beforehand: how to avoid outages

Anyone who sets the list unchecked risks that image resizing, PDF invoices or mail delivery suddenly stop working. So search the code beforehand for the affected functions:

# Where and how often are the functions used in the code?
grep -rnoE "\b(exec|shell_exec|system|passthru|proc_open|popen|pcntl_exec)\s*\(" /var/www/meine-seite --include="*.php" \
  | cut -d: -f1 | sort | uniq -c | sort -rn | head -30

Hits do not automatically mean the function is needed in operation. Many libraries first check whether a function is available and otherwise fall back. What matters is a test in a staging environment covering all important processes: ordering, invoicing, form delivery, image upload, scheduled tasks.

If an application strictly requires one of these functions, check the vendor's system requirements on its official site. Often the task can be moved to a separate pool or a command-line script that is not reachable via the web.

Enabling the setting and checking its effect

After the change, PHP must reread the configuration. Then check the value in your website's operating mode, not on the command line:

sudo systemctl reload php8.3-fpm
php-fpm8.3 -i | grep "^disable_functions"
# Check the error log for calls of blocked functions
sudo grep -i "has been disabled" /var/log/php/*.log | tail -20

The messages in the error log are valuable later on as well. If calls of blocked functions suddenly appear there although your application does not use them, that may point to planted code. How to proceed then is described in the guide Detecting and removing webshells.

Typical mistakes when using disable_functions

In practice, hardening rarely fails because of the technology but because of small things. These mistakes are particularly common:

  • Wrong file changed: The list is only in the command line's php.ini; the website runs through PHP-FPM and stays unprotected.
  • No restart: The file is correct, but the running processes still work with the old configuration.
  • Blocked too broadly: Functions such as ini_set or mail are blocked too, and important processes fail unnoticed. Errors then often show up only days later, for example when order confirmations stop arriving.
  • Set once, never checked: After a move, a change of PHP version or a reinstallation via the hosting panel, the list has vanished.
  • A false sense of security: The block is understood as a replacement for updates. It does not close a vulnerability in the interpreter, though.

So include checking the active value in your routine after every PHP update. A quick look is enough, costs hardly any time and prevents a hardening measure from being silently lost.

Tip

With several websites on one server: create a separate pool with its own list for each website. In addition, open_basedir limits the directories PHP may access.

How does PHP SOS help?

  • We check your application's code and processes for the use of critical functions.
  • We define a suitable block list for each website and test it before going live.
  • We combine the block with pools, file permissions and logging into a coherent hardening concept.
  • We document the settings and monitor the error log for conspicuous calls.

How this works as a complete package is described in the service Server hardening for PHP web servers.

Frequently asked questions

Can I set disable_functions via ini_set() or .htaccess?

No. The setting works only from php.ini or as php_admin_value in the FPM pool or the Apache configuration. It cannot be set at runtime, and the application cannot re-enable blocked functions either.

Does disable_functions protect against PHP2Shell?

No. PHP2Shell affects the PHP interpreter itself; the vulnerability is closed only by the update. Blocked functions can, however, limit an attacker's room for manoeuvre after a successful exploitation.

Why does php -i show a different list than my website?

The command line often reads its own php.ini. For the website, the configuration of PHP-FPM, mod_php or LiteSpeed counts. Therefore check the value in the operating mode through which your website runs.

Which applications need proc_open or exec?

That depends on the application. Typical are image processing via external programs, PDF generation, mail delivery via sendmail or tools such as Composer. Check this in the code and in the vendor's system requirements.

Sources

Immediate contact

Every hour counts. Write to us now.

Briefly describe your system, PHP version and observation. We will get back to you, clarify the situation and work remotely until the incident is closed and documented.

Immediate help