In short: memory_limit defines how much memory a single PHP request may use; the default is 128M. In normal operation, set a finite value that suits the application and lock it with php_admin_value. As long as PHP2Shell is not patched, php.net temporarily advises memory_limit=-1, non-overridable and combined with a limit via container or cgroup, not via RLIMIT_AS or RLIMIT_DATA. After the update, a finite value applies again.
A routine setting that is suddenly a security topic
For years, memory_limit was a tuning knob for developers. If a website reports “Allowed memory size exhausted”, the value is raised and the problem is solved. With PHP2Shell this has become a security question, and php.net's recommendation looks paradoxical at first glance: for the interim, PHP's own memory limit is to be dropped entirely.
The background is CVE-2026-109618. According to the PHP project, an out-of-memory condition can interrupt PHP while request data is only partially initialized. Cleaning up the request can then treat invalid data as valid. Technical details are under CVE-2026-109618; what happens inside PHP when memory runs out is explained in memory_limit and out-of-memory. For operators, the question is: which value applies when, and where must it be set?
What memory_limit does in normal operation
According to the PHP manual, memory_limit limits the memory a script may use and thus protects the server from badly written code. The default is 128M; -1 means no limit. Shorthand such as 256M or 1G is allowed.
Two properties matter for security. First, the value can be changed anywhere, even at runtime with ini_set(). Many CMS and shops raise it themselves, for example for imports or image processing. Anyone who wants to enforce a value must set it with php_admin_value; according to the manual, values set this way cannot be overridden with ini_set(). Second, the manual recommends that memory_limit be larger than post_max_size.
Which value fits depends on the application. A look at the error log shows whether messages about exhausted memory occur and on which requests. It has proven worthwhile to define the value per website in its own FPM pool: more generous for a shop with imports, tighter for a simple company site. A blanket very high value for all websites wastes the protective effect, because a single faulty or abused request can then tie up a lot of memory.
Since PHP 8.5 there is also max_memory_limit. This setting can only be set at startup and limits how high memory_limit may be set at all. Higher values are capped with a warning. The default -1 means no upper limit.
memory_limit after PHP2Shell: the interim measure from php.net
For servers not yet updated to 8.5.12, 8.4.27, 8.3.36 or 8.2.35 or a confirmed backport, php.net names the following steps in the security announcement of 21 October 2026. They reduce the risk of individual attack paths but, according to php.net, do not make an installation safe:
- Set
memory_limit=-1, if possible so that applications cannot override the value, for example withphp_admin_valuein the FPM pool or in the Apache configuration. - Check that no finite limit is set again anywhere, neither in another pool, nor in a directory configuration, nor in the application.
- Set a memory limit via container or cgroup, to protect availability, if possible so that only the affected worker is terminated when it is exceeded.
- Do not use
RLIMIT_ASorRLIMIT_DATA. According to php.net, these limits can trigger exactly the vulnerable error during memory allocation.
php.net explains that -1 removes the ability to trigger the PHP memory limit on purpose, but that a memory error at a lower level can still reach the vulnerable path. The overview of all interim measures is under Immediate measures if you cannot patch yet.
; FPM pool, e.g. /etc/php/8.3/fpm/pool.d/www.conf (only until the update)
php_admin_value[memory_limit] = -1
# Everywhere memory_limit is set (read-only)
grep -rn 'memory_limit' /etc/php/ /etc/apache2/ 2>/dev/null
grep -rn --include='*.php' -E "ini_set\s*\(\s*['\"]memory_limit" /var/www | head -20
grep -rn --include='.user.ini' 'memory_limit' /var/www
How to set the cgroup limit for the FPM service is described in Setting memory limits with systemd and cgroups. Without this outer limit, a single request can push the whole server into a memory shortage.
Restart all PHP workers after every change. A running worker keeps its old values.
What applies after the update
With the fixed versions, the behavior of memory_limit has also changed according to the PHP manual. From 8.5.12, 8.4.27, 8.3.36 and 8.2.35 it is a soft limit: a memory request that exceeds it may in most cases still be completed before the error is triggered. A new setting, memory_hard_limit_percent, defines a hard limit that is never exceeded.
| Setting | Value | Effect according to the manual |
|---|---|---|
memory_hard_limit_percent not set or -1 |
default | hard limit twice as high as memory_limit up to 1G, above that memory_limit plus 1G |
memory_hard_limit_percent = 150 |
example | with memory_limit=128M hard limit 192M |
memory_limit = -1 |
no limit | then there is no hard limit either |
The manual names a practical checkpoint: if memory_hard_limit_percent is not recognized, the PHP version in use is affected and must be updated. For distribution backports, additionally check the status via the package changelog.
# Does the FPM binary know the new setting? (adjust the version number)
php-fpm8.3 -i | grep -E 'memory_hard_limit_percent|memory_limit'
After the update, memory_limit=-1 has served its purpose. Return to a finite value that suits the application, and lock it with php_admin_value. The cgroup limit can remain as an additional layer of protection.
How does PHP SOS help?
- We determine where
memory_limitis set and overridden on your server, including in applications. - We implement php.net's interim measures in the right place and add a cgroup limit for the FPM service.
- Through the PHP patch service we bring PHP to a fixed version and restart all workers.
- Afterwards we set a suitable finite value again and document the settings.
Frequently asked questions
What is the default value of memory_limit?
According to the PHP manual, 128M. The value limits how much memory a single script may use. It can be changed in php.ini, in the server configuration, in the FPM pool and at runtime with ini_set(), unless it is locked with php_admin_value.
Why does php.net advise memory_limit=-1 for PHP2Shell?
One of the vulnerabilities, CVE-2026-109618, is related to the state when memory runs out. According to php.net, memory_limit=-1 removes the ability to trigger the PHP memory limit on purpose, but not every memory error. The measure is not complete protection and must be combined with a memory limit via container or cgroup.
May I set the limit with ulimit instead?
No. php.net expressly advises against using RLIMIT_AS or RLIMIT_DATA as a substitute, because these limits can trigger exactly the vulnerable error during memory allocation. A limit via container or cgroup is recommended.
What applies after the update to a fixed PHP version?
According to the manual, in the fixed versions memory_limit is a soft limit, supplemented by a hard limit via memory_hard_limit_percent. The interim measure with -1 has then served its purpose, and a finite value that suits the application should apply again.