In short: Four areas matter most for php.ini security: no error messages shown to the outside, secure session cookies, limited uploads, and locked values that applications cannot override. After PHP2Shell, the interim measures from php.net come on top, above all session.upload_progress.enabled=0. A secure configuration never replaces the update, though.
Why php.ini is back in focus after PHP2Shell
The php.ini is PHP's central configuration file. On many servers it was set up once and hardly touched afterwards. With PHP2Shell that has changed: for the two vulnerabilities CVE-2026-109618 and CVE-2026-109619, php.net names interim measures that start exactly here.
The vulnerabilities themselves sit in the PHP interpreter. They are fixed in PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35, released on 21 October 2026. A good configuration still helps in two ways: it can make exploitation harder, and it limits the damage if something does get through.
Many operators also do not know exactly which settings apply on their server. That is the first step.
Which php.ini applies on your server?
Depending on the operating mode, PHP can read different configuration files. The command line, PHP-FPM and Apache with mod_php each have their own folders under /etc/php/<version>/ on Debian and Ubuntu, for example. Anyone who changes only the CLI file changes nothing for the website.
# Configuration files of the command line
php --ini
# Configuration of PHP-FPM (adjust version number)
php-fpm8.3 -i | grep -E "Loaded Configuration|Scan this dir"
# Check individual values of PHP-FPM
php-fpm8.3 -i | grep -E "^(expose_php|display_errors|session.upload_progress.enabled) "
In addition, values can be set in the FPM pool, in the Apache configuration, in .htaccess (mod_php only) or in .user.ini (FPM and CGI). Which version actually runs on the server and whether a backport is included is explained in the article Checking the PHP version and patch status correctly.
Basic settings for better php.ini security
The following values make sense for most production servers. Before using them, test in a test environment that your application copes with all of them.
; No version information in the HTTP header
expose_php = Off
; Log errors, but never show them in the browser
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /var/log/php/error.log
; Do not include files from remote addresses
allow_url_include = Off
; Keep allow_url_fopen enabled only if the application needs it
allow_url_fopen = Off
; Sessions: strict, over HTTPS only, not readable by JavaScript
session.use_strict_mode = 1
session.use_only_cookies = 1
session.cookie_secure = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
; Limit runtime and input
max_execution_time = 30
max_input_time = 60
max_input_vars = 1000
Some applications need allow_url_fopen for updates or interfaces. Switch it off only if you have checked this beforehand. Functions that execute system commands can additionally be blocked; how to do this without side effects is explained in the guide Using disable_functions correctly.
Interim measures from php.net on PHP2Shell
If you cannot patch immediately, php.net names several settings that reduce the risk. They are explicitly not complete protection, but a bridge until the update.
; Disable session upload progress (also because of CVE-2026-115560)
session.upload_progress.enabled = 0
; Limit request size: 8M without uploads, 32M with uploads
post_max_size = 8M
upload_max_filesize = 6M
; PHP 8.5 only: no backtraces on fatal errors
fatal_error_backtraces = 0
In addition, php.net recommends setting memory_limit=-1 in such a way that applications cannot override the value, and drawing the memory limit through a container or cgroup instead, not through RLIMIT_AS or RLIMIT_DATA. This measure belongs in the FPM pool or the server configuration and should be combined with a working cgroup limit. The full overview is at Immediate measures if you cannot patch yet.
session.upload_progress.enabled=0 takes effect only from php.ini, the FPM pool or the server configuration. Set via ini_set() or .user.ini, the measure does not apply. Then restart all workers.
Locking values against being overridden
Many applications set their own values, for example for memory or uploads. With php_admin_value and php_admin_flag you fix settings so that neither ini_set() nor .user.ini can change them. In the FPM pool it looks like this:
; /etc/php/8.3/fpm/pool.d/meine-seite.conf (Auszug)
php_admin_flag[display_errors] = off
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M
php_admin_value[upload_max_filesize] = 6M
php_admin_value[error_log] = /var/log/php/meine-seite.error.log
With Apache and mod_php the same logic applies, using php_admin_value and php_admin_flag in the VirtualHost configuration. Then reload the service and cross-check the active value:
sudo systemctl reload php8.3-fpm
# Process start time: is it after the change?
ps -eo pid,lstart,cmd | grep "[p]hp-fpm"
A reload restarts the PHP-FPM workers. After a PHP update, however, a complete restart of all PHP processes is necessary so that no old process keeps running in memory. With several websites on one server, a separate pool per website is also worthwhile; more on this in the guide open_basedir and isolation per website.
Common mistakes and a short checklist
Most problems with php.ini arise not from wrong values but from values in the wrong place. Typical is the changed CLI file while the website runs through PHP-FPM. Just as often, the restart is skipped after a change, or a hosting panel overwrites your own setting the next time it saves.
A second classic is visible error messages on the live website. They reveal paths, database names or versions and make orientation easier for attackers. Especially after a move or a fresh installation, display_errors is often back to On.
Check these points after every change and after every PHP update:
- Which configuration file does the web operating mode read, and does it contain your values?
- Are
display_errorsandexpose_phpswitched off, and is the error log writable? - Is
session.upload_progress.enabledset to0, via php.ini or pool? - Are upload and request sizes limited to suit the application?
- Do all PHP processes have a start time after the last change?
Record the result with a date. That way you can later prove which setting applied when.
How does PHP SOS help?
- We determine which configuration is actually active in which operating mode.
- We implement a tuned baseline configuration and the PHP2Shell interim measures, tested with your application.
- We lock security-relevant values against being overridden and restart all workers in a controlled way.
- We document settings and check results so that later changes remain traceable.
What lasting protection looks like is described in the service Server hardening for PHP web servers.
Frequently asked questions
Which php.ini does my web server actually use?
Often it is not the same as on the command line. PHP-FPM, Apache with mod_php and the CLI usually have their own configuration folders. Check the active file via the relevant operating mode, for example with php-fpm -i or a test file placed briefly.
Does a secure php.ini replace the PHP update?
No. The settings reduce the attack surface and make exploitation harder, but they do not close a vulnerability in the PHP interpreter. The interim measures from php.net on PHP2Shell, too, are explicitly not complete protection.
What is the difference between php_value and php_admin_value?
Values set with php_value can be changed again by the application at runtime. Values set via php_admin_value in the FPM pool or in the Apache configuration, by contrast, are locked against the application, including ini_set() and .user.ini.
Do I have to restart after changing php.ini?
Yes. PHP-FPM and Apache with mod_php read the configuration only at startup. The new values apply only after a restart or reload of all affected services.