Situación actual: PHP2Shell. Dos vulnerabilidades críticas de PHP (CVSS 9.2) permiten ejecutar código malicioso sin autenticación. Parches desde el 21/10/2026.Qué hacer ahora →

memory_limit y Out-of-Memory: lo que ocurre por dentro

¿Qué pasa cuando un script PHP llega a memory_limit? Mecánica, el nuevo límite de memoria estricto desde los parches de octubre y la relación con CVE-2026-109618.

Actualizado 6 min de lecturaConocimiento de PHP

En resumen: un error de falta de memoria (Out of Memory) en PHP se produce cuando un script quiere solicitar más memoria de la que permite el ajuste memory_limit (por defecto: 128 MB por petición). PHP interrumpe entonces la petición con un error fatal y limpia. Precisamente esa vía de interrupción y limpieza era defectuosa en CVE-2026-109618, una de las dos vulnerabilidades de PHP2Shell. Desde PHP 8.5.12, 8.4.27, 8.3.36 y 8.2.35, memory_limit es un límite flexible, complementado por el límite estricto memory_hard_limit_percent.

¿Qué significa «Allowed memory size exhausted»?

El conocido mensaje de error dice, más o menos: «Allowed memory size of 134217728 bytes exhausted (tried to allocate …)». La primera cifra es el límite configurado en bytes, aquí 128 MB. Un script ha intentado, pues, ocupar memoria por encima de ese límite, por ejemplo al cargar un archivo grande, en una consulta enorme a la base de datos o por un bucle infinito.

Importante para quienes toman decisiones: el límite se aplica por proceso de PHP y por petición, no a todo el servidor. Protege al servidor de que un solo script defectuoso consuma toda la memoria. La carga total resulta únicamente del número de workers que se ejecutan a la vez. Con 20 workers de PHP-FPM con un límite de 256 MB cada uno, son más de 5 GB en cifras.

Cómo cuenta PHP la memoria

PHP gestiona la memoria de las peticiones mediante un administrador de memoria propio, el Zend Memory Manager. Obtiene bloques mayores del sistema operativo y los reparte internamente entre variables, arrays y objetos. Contra este valor reservado comprueba PHP el memory_limit. La memoria que una extensión solicita directamente al sistema operativo no aparece, según el manual, en este recuento.

Puede hacer visibles los valores en el código:

<?php
echo memory_get_usage(), PHP_EOL;       // memoria ocupada actualmente por el script
echo memory_get_usage(true), PHP_EOL;   // reservada por el administrador de memoria; contra esto comprueba memory_limit
$liste = range(1, 200000);
echo memory_get_peak_usage(), PHP_EOL;  // valor máximo hasta ahora
unset($liste);
memory_reset_peak_usage();              // restablecer el valor máximo, desde PHP 8.2

Cómo vuelven a liberar la memoria el conteo de referencias y la recolección de basura lo explica la página Gestión de memoria en PHP.

Qué ocurre por dentro durante el Out-of-Memory

De forma simplificada, una interrupción por memoria transcurre en estos pasos:

  1. El script solicita memoria, por ejemplo para un nuevo elemento de array o al leer los datos de la petición.
  2. El administrador de memoria comprueba si la solicitud supera el límite.
  3. Si es así, PHP provoca un error fatal y abandona de inmediato el procesamiento en curso, incluso en mitad de una tarea a medio hacer.
  4. Las funciones de apagado registradas todavía se ejecutan; muchas aplicaciones registran así el error.
  5. Al final, PHP limpia la petición y libera su memoria. El worker queda después listo para la siguiente petición.

El punto delicado es el paso 5. La limpieza debe saber manejar estructuras de datos que, en el momento de la interrupción, estaban creadas solo a medias. Según la política de seguridad del proyecto PHP, una interrupción por memoria normal no se considera una vulnerabilidad de seguridad mientras el límite rechace la solicitud y solo termine la petición actual. En CVE-2026-109618 se incumplía precisamente esa suposición: según php.net, el estado de falta de memoria podía interrumpir PHP mientras los datos internos de la petición estaban inicializados solo en parte, y la limpieza trataba entonces los datos no válidos como válidos. No publicamos detalles de la explotación; la valoración de la vulnerabilidad figura en CVE-2026-109618.

El nuevo límite de memoria flexible y estricto

Con las versiones de seguridad del 21/10/2026, el proyecto PHP cambió el comportamiento. Según el manual, memory_limit es desde entonces un límite flexible: una solicitud que lo supere puede, en la mayoría de los casos, completarse todavía antes de que llegue el error fatal. Un límite estricto independiente acota hasta dónde puede llegar esto.

Directiva Valor por defecto Modificable Significado
memory_limit 128M INI_ALL Límite de memoria por petición, -1 = sin límite
memory_hard_limit_percent no establecido INI_ALL Límite estricto como porcentaje de memory_limit, nuevo desde 8.5.12, 8.4.27, 8.3.36, 8.2.35
post_max_size 8M INI_PERDIR Tamaño máximo de los datos POST
upload_max_filesize 2M INI_PERDIR Tamaño máximo de un archivo subido

Un ejemplo del manual: con memory_limit=128M y memory_hard_limit_percent=150, el límite estricto está en 192 MB. El manual presenta además la directiva como rasgo identificativo: si una versión de PHP no la conoce, está afectada por CVE-2026-109618 y CVE-2026-109619. Una prueba rápida para cada versión de PHP instalada:

php -r 'var_dump(ini_get("memory_hard_limit_percent"));'
# bool(false) significa: directiva desconocida

En los paquetes de distribuciones con backport, el changelog del paquete sigue siendo la prueba determinante, como se describe en Comprobar correctamente la versión de PHP y el estado del parche. Compruebe además por separado el binario de PHP-FPM, porque puede tener una versión distinta de la de la línea de comandos.

Límites de memoria y PHP2Shell: qué deben tener en cuenta ahora los administradores

Las medidas provisionales de php.net sobre CVE-2026-109618 giran casi todas en torno a la memoria y al tamaño de las peticiones. Reducen el riesgo, pero no sustituyen a la actualización:

; Pool de FPM, p. ej. /etc/php/8.3/fpm/pool.d/www.conf
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M        ; 32M si se necesitan subidas
php_admin_value[upload_max_filesize] = 6M  ; mantener por debajo de post_max_size

Tres puntos son decisivos. Primero, ninguna aplicación, ningún directorio ni ningún otro pool puede volver a fijar un límite finito; php.net exige expresamente este control. Segundo, un servicio con memory_limit=-1 necesita un límite externo, mediante contenedor o cgroup, y según php.net lo mejor es que solo se termine el worker afectado. RLIMIT_AS y RLIMIT_DATA no son adecuados según php.net. Tercero, php.net recomienda límites en el servidor web o en el proxy para el tamaño de la petición, el número de campos, las partes multipart, las cabeceras y la profundidad de anidamiento.

Importante

memory_limit=-1 sin un límite de memoria externo puede paralizar por completo un servidor con mucha carga. Aplique las medidas provisionales solo como conjunto y solo hasta la actualización.

Cómo fijar el límite con systemd figura en Límites de memoria con systemd y cgroups; la solución duradera para el día a día la describe Configurar memory_limit correctamente.

¿Cómo ayuda PHP SOS en concreto?

A través del servicio de parches de PHP procedemos así:

  • Revisar el parque: registramos cada versión de PHP del servidor, por separado para CLI, FPM y módulo de Apache, y comprobamos si se ejecuta la versión corregida.
  • Ordenar los límites de memoria: comprobamos dónde se fija memory_limit y configuramos los límites de pool y de sistema de modo que encajen.
  • Asegurar la transición: donde la actualización aún está bloqueada, aplicamos por completo las medidas de php.net, bloqueadas frente a sobrescritura.
  • Entregar la prueba: recibirá por escrito las versiones, los estados de los paquetes y la configuración antes y después de la intervención.

Preguntas frecuentes

¿Qué significa el mensaje «Allowed memory size exhausted»?

Un script quiso solicitar más memoria de la que permite memory_limit. PHP interrumpe entonces la petición en curso con un error fatal. Las demás peticiones y el propio servidor siguen funcionando.

¿Se aplica memory_limit a todo el servidor?

No, el límite se aplica por proceso de PHP y por petición. Si 20 workers de FPM funcionan con un límite de 256 MB cada uno, en teoría pueden ocupar juntos más de 5 GB. Por eso el límite global debe fijarse mediante el tamaño del pool, systemd o contenedores.

¿Qué es memory_hard_limit_percent?

Una directiva nueva que llegó con PHP 8.5.12, 8.4.27, 8.3.36 y 8.2.35. Establece un límite estricto como porcentaje de memory_limit que nunca se supera. Desde entonces, memory_limit es un límite flexible.

¿Protege memory_limit=-1 frente a PHP2Shell?

Solo en parte. php.net indica este ajuste como medida provisional frente a CVE-2026-109618, expresamente sin protección completa. Exige necesariamente un límite de memoria externo, y la actualización sigue siendo obligatoria.

Fuentes

Contacto inmediato

Cada hora cuenta. Escríbanos ahora.

Describa brevemente el sistema, la versión de PHP y lo que ha observado. Nos pondremos en contacto, aclararemos la situación y trabajaremos en remoto hasta que el incidente quede cerrado y documentado.

Ayuda inmediata