En resumen: memory_limit determina cuánta memoria puede ocupar una única petición PHP; por defecto son 128M. En el funcionamiento normal, fije un valor finito que se ajuste a la aplicación y bloquéelo con php_admin_value. Mientras PHP2Shell no esté parcheado, php.net recomienda temporalmente memory_limit=-1, no sobrescribible y combinado con un límite mediante contenedor o cgroup, no mediante RLIMIT_AS ni RLIMIT_DATA. Tras la actualización vuelve a regir un valor finito.
Un ajuste rutinario que de pronto es un asunto de seguridad
Durante años, memory_limit fue un tornillo de ajuste para desarrolladores. Si un sitio web notifica «Allowed memory size exhausted», se aumenta el valor y el problema queda resuelto. Con PHP2Shell se ha convertido en una cuestión de seguridad, y la recomendación de php.net parece a primera vista paradójica: para la transición, el límite de memoria propio de PHP debe desaparecer por completo.
El trasfondo es CVE-2026-109618. Según el proyecto PHP, un estado de falta de memoria (out-of-memory) puede interrumpir PHP mientras los datos de la petición solo están inicializados parcialmente. La limpieza de la petición puede entonces tratar datos no válidos como válidos. Los detalles técnicos figuran en CVE-2026-109618; lo que ocurre dentro de PHP ante la falta de memoria lo explica memory_limit y Out-of-Memory. Para los responsables cuenta la pregunta: ¿qué valor rige cuándo y dónde debe figurar?
Qué logra memory_limit en el funcionamiento normal
Según el manual de PHP, memory_limit limita la memoria que puede ocupar un script y protege así al servidor de código mal escrito. El valor por defecto es 128M; -1 significa sin límite. Se permiten abreviaturas como 256M o 1G.
Dos propiedades son importantes para la seguridad. Primero, el valor puede cambiarse en cualquier parte, también en tiempo de ejecución con ini_set(). Muchos CMS y tiendas lo aumentan por sí mismos, por ejemplo para importaciones o procesamiento de imágenes. Quien quiera imponer un valor debe fijarlo con php_admin_value; según el manual, los valores así fijados no pueden sobrescribirse con ini_set(). Segundo, el manual recomienda que memory_limit sea mayor que post_max_size.
El valor adecuado depende de la aplicación. Una mirada al log de errores muestra si aparecen avisos de memoria agotada y en qué llamadas. Ha dado buen resultado fijar el valor por sitio web en su propio pool de FPM: más holgado para una tienda con importaciones, más ajustado para un sitio corporativo sencillo. Un valor muy alto para todos los sitios web desperdicia el efecto protector, porque entonces una sola petición defectuosa o abusiva puede acaparar mucha memoria.
Desde PHP 8.5 existe además max_memory_limit. Este ajuste solo puede fijarse al arrancar y limita hasta qué valor puede fijarse memory_limit. Los valores superiores se recortan con una advertencia. El valor por defecto -1 significa sin límite superior.
memory_limit tras PHP2Shell: la medida transitoria de php.net
Para los servidores que aún no se han actualizado a 8.5.12, 8.4.27, 8.3.36 o 8.2.35, ni a un backport confirmado, php.net indica en su aviso de seguridad del 21/10/2026 los pasos siguientes. Reducen el riesgo de vías de ataque concretas, pero según php.net no hacen segura una instalación:
- Fijar
memory_limit=-1, si es posible de modo que las aplicaciones no puedan sobrescribir el valor, por ejemplo conphp_admin_valueen el pool de FPM o en la configuración de Apache. - Comprobar que en ningún sitio se vuelve a fijar un límite finito, ni en otro pool, ni en una configuración de directorio, ni en la aplicación.
- Fijar un límite de memoria mediante contenedor o cgroup, como protección de la disponibilidad, si es posible de modo que, al superarlo, solo se termine el worker afectado.
- No usar
RLIMIT_ASniRLIMIT_DATA. Según php.net, estos límites pueden provocar precisamente el error vulnerable al solicitar memoria.
php.net explica al respecto que -1 elimina la posibilidad de provocar de forma dirigida que se alcance el límite de memoria de PHP, pero que un error de memoria a un nivel más profundo puede seguir alcanzando la ruta vulnerable. El resumen de todas las medidas transitorias figura en Medidas inmediatas si todavía no puede parchear.
; Pool de FPM, p. ej. /etc/php/8.3/fpm/pool.d/www.conf (solo hasta la actualización)
php_admin_value[memory_limit] = -1
# Dónde se fija memory_limit (solo lectura)
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
Cómo fijar el límite de cgroup para el servicio FPM lo describe Fijar límites de memoria con systemd y cgroups. Sin este límite externo, una sola petición puede poner en apuros de memoria a todo el servidor.
Tras cada cambio, reinicie todos los workers de PHP. Un worker en ejecución conserva sus valores antiguos.
Qué rige tras la actualización
Con las versiones corregidas, según el manual de PHP, también ha cambiado el comportamiento de memory_limit. A partir de 8.5.12, 8.4.27, 8.3.36 y 8.2.35 es un límite blando: una solicitud de memoria que lo supere puede, en la mayoría de los casos, completarse todavía antes de que se genere el error. Un nuevo ajuste, memory_hard_limit_percent, fija un límite duro que nunca se supera.
| Ajuste | Valor | Efecto según el manual |
|---|---|---|
memory_hard_limit_percent sin fijar o -1 |
por defecto | límite duro el doble de memory_limit hasta 1G; por encima, memory_limit más 1G |
memory_hard_limit_percent = 150 |
ejemplo | con memory_limit=128M, límite duro de 192M |
memory_limit = -1 |
sin límite | entonces tampoco hay límite duro |
El manual indica un punto práctico de comprobación: si memory_hard_limit_percent no se reconoce, la versión de PHP utilizada está afectada y debe actualizarse. En los backports de las distribuciones, compruebe además el estado mediante el changelog del paquete.
# ¿Conoce el binario de FPM el nuevo ajuste? (adapte el número de versión)
php-fpm8.3 -i | grep -E 'memory_hard_limit_percent|memory_limit'
Tras la actualización, memory_limit=-1 ha cumplido su función. Vuelva a un valor finito adecuado a la aplicación y bloquéelo con php_admin_value. El límite de cgroup puede mantenerse como capa de protección adicional.
¿Cómo ayuda PHP SOS en concreto?
- Averiguamos dónde se fija y se sobrescribe
memory_limiten su servidor, incluidas las aplicaciones. - Aplicamos las medidas transitorias de php.net en el lugar correcto y añadimos un límite de cgroup para el servicio FPM.
- Mediante el servicio de parcheo de PHP llevamos PHP a una versión corregida y reiniciamos todos los workers.
- Después volvemos a fijar un valor finito adecuado y documentamos los ajustes.
Preguntas frecuentes
¿Cuál es el valor por defecto de memory_limit?
Según el manual de PHP, 128M. El valor limita cuánta memoria puede ocupar un único script. Puede cambiarse en php.ini, en la configuración del servidor, en el pool de FPM y en tiempo de ejecución con ini_set(), siempre que no esté bloqueado con php_admin_value.
¿Por qué recomienda php.net memory_limit=-1 ante PHP2Shell?
Una de las vulnerabilidades, CVE-2026-109618, está relacionada con el estado en caso de falta de memoria. Según php.net, memory_limit=-1 elimina la posibilidad de provocar de forma dirigida que se alcance el límite de memoria de PHP, pero no todo error de memoria. La medida no es una protección completa y debe combinarse con un límite de memoria mediante contenedor o cgroup.
¿Puedo fijar el límite con ulimit en su lugar?
No. php.net desaconseja expresamente usar RLIMIT_AS o RLIMIT_DATA como sustituto, porque estos límites pueden provocar precisamente el error vulnerable al solicitar memoria. Se recomienda un límite mediante contenedor o cgroup.
¿Qué rige tras actualizar a una versión corregida de PHP?
Según el manual, en las versiones corregidas memory_limit es un límite blando, complementado por un límite duro mediante memory_hard_limit_percent. La medida transitoria con -1 ha cumplido entonces su función y debería volver a aplicarse un valor finito adecuado a la aplicación.