PHP is an open source general-purpose server-side scripting language originally designed for Web development to produce dynamic Web pages. It is one of the first developed server-side scripting languages to be embedded into an HTML source document rather than calling an external file to process data. The code is interpreted by a Web server with a PHP processor module which generates the resulting Web page. It also has evolved to include a command-line interface capability and can be used in standalone graphical applications.
If you are new to PHP and want to get some idea of how it works, try the introductory tutorial.
After that, check out the online manual.
What's New
PHP 8.5.12 fix two critical vulnerabilities that can allow unauthenticated remote code execution. All PHP users are strongly encouraged to update immediately.
Who is at risk: all PHP installations serving web requests, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. We consider the risk highest for mod_php, with a demonstrated exploit where an unauthenticated request can trigger the attack before any application code runs.
The vulnerabilities:
- RCE via OOM corruption, CVE-2026-109618 (GHSA-w8hw-w9fx-j79w): out-of-memory handling can interrupt PHP while internal request data is only partially initialized. Request cleanup may then treat the invalid data as valid.
- RCE via stale global state, CVE-2026-109619 (GHSA-6wmf-4rv5-p3rp): request-owned internal state can survive after its backing memory has been freed. A later request handled by the same worker may use that stale state before normal initialization resets it.
How to update:
- Update to PHP 8.5.12
- Linux distributions and LTS vendors received the patches in advance, so check your vendor for updated packages.
- PHP 8.1 and older no longer receive updates from the PHP project. Some distributions and LTS vendors provide backported fixes, so contact your vendor for details, or upgrade to a supported version.
- Given the severity of these vulnerabilities, the PHP security team provided minimal source-backports for PHP 7.4, PHP 8.0, and PHP 8.1 to help people building from source or without access to an LTS vendor.
- If you cannot update immediately: while only an update is a complete solution, the following measures reduce exposure to specific attack paths but do not make an installation safe.
RCE via OOM corruption (CVE-2026-109618):
- Set memory_limit=-1, preferably in a way applications can't override, such as php_admin_value in the FPM pool or Apache configuration, and check that no pool, directory or application setting puts a finite limit back. This removes the controllable PHP memory limit failure, but an underlying allocation failure can still reach the vulnerable path.
- Set a low post_max_size. For applications that don't require file uploads, set post_max_size = 8M. If file uploads are necessary, set post_max_size = 32M. Keep upload_max_filesize below post_max_size. Consider enforcing limits at the web server or proxy level for decoded request size, input field count, multipart part count, header count, and nesting depth. These limits must also cover requests without a usable Content-Length.
- Use a container or cgroup limit as an availability boundary, preferably with a policy that kills only the affected worker. Do not substitute RLIMIT_AS or RLIMIT_DATA, as these can cause the vulnerable allocation failure.
RCE via stale global state (CVE-2026-109619):
- Set session.upload_progress.enabled=0 and restart every worker. Use php.ini, an FPM pool or server configuration that applies before request parsing. Do not rely on ini_set() or FPM .user.ini. This blocks the confirmed session paths but not other variants.
- On PHP 8.5, set fatal_error_backtraces=0 and restart every worker. This blocks the confirmed fatal backtrace path only.
- Remove invalid or deprecated settings applied per request that emit diagnostics before initialization. Hiding diagnostics with error_reporting, display_errors or @ does not help.
- Fix attacker-reachable fatal errors and execution timeouts, including failures in callbacks, upload or import processing and cleanup.
The PHP development team announces the immediate availability of PHP 8.5.12. This is a security release fixing two critical vulnerabilities (CVE-2026-109618, CVE-2026-109619) that can allow unauthenticated remote code execution. All PHP 8.5 users are strongly encouraged to update immediately.
There are no complete mitigations, updating is the only safe choice. See the security advisory for details.
Version 8.5.12:
Core:
- Fixed GHSA-w8hw-w9fx-j79w, GHSA-6wmf-4rv5-p3rp (Avoid state corruption via bailout).
- Fixed bug GH-23644 (Optimizer leaves a constant-vs-constant comparison unfolded, crashing the VM in zval_undefined_cv).
- Fixed OSS-Fuzz 532353396 (assertion failure with static type).
- Fix GH-23662 (Avoid NAN warning in print_r()).
- Fix GH-21999: GC inconsistency with lazy object, var_dump(), and object comparison.
- Fixed OSS-Fuzz #536440507 (Immutable class incorrect assertion).
- Fixed AVX being reported as supported when the OS has not enabled AVX state.
- Fixed GH-23980 (ZEND_ASSERT violation @ ZEND_INCLUDE_OR_EVAL).
- Fixed use-after-free when a dl()-loaded extension declares a frameless function and a later request calls it.
- Fixed System V shared memory emulation for Windows attaching segments past the end of their mapping.
- Fixed exception thrown by destructor during GC in a Fiber not being rethrown into the frame that triggered the GC.
BCMath:
- Fixed BcMath\Number results that truncate to zero keeping a negative sign and comparing less than zero.
BZ2:
- Fixed double close of the descriptor and use-after-free of the inner stream when bzopen() is given a stream resource.
CLI:
- Fix GH-22567 (Windows ZTS CLI SAPI should refresh its TSRMLS cache during request activation).
- Fixed bug GH-23764 (Built-in server leaks a file descriptor on every HEAD request for a static file).
- Fixed crash in the built-in server when a client is reset before being accepted.
- Fixed the built-in server truncating an error page and leaking its unsent part after a partial socket write.
DOM:
- Fixed use-after-free when re-constructing a DOMXPath whose php:function registrations are freed while still reachable from the cycle collector.
- Fixed Dom\HTMLDocument::getElementById() not finding ids of SVG and MathML elements.
- Fixed Dom\HTMLDocument giving attributes the namespace of their element when a fragment is parsed with an xlink, xml or xmlns context element.
- Fixed bug GH-23887 (Dom\HTMLCollection::namedItem() assertion failure, hang, or missed first element).
- Fixed DOMXPath and Dom\XPath losing the context node and in-scope namespaces of an evaluation after a php:function() callback evaluated another expression on the same object.
FFI:
- Fixed crashes with FFI callbacks created from __call() trampolines and array callables whose object is released.
FTP:
- Fixed bug GH-23619 (cryptic error on servers that don't support TLS session resumption on data connection).
GD:
- Fixed undefined behavior with GD2 images with 'INT_MAX'-sized chunks.
- Fixed undefined behavior with GIFs with problematic LZW compression data.
Intl:
- Fixed cloning IntlDateFormatter and MessageFormatter losing PHP-side state such as dateType, timeType, calendar and the message pattern.
- Fixed a crash when converting with a cloned UConverter that uses toUCallback/fromUCallback.
- Fixed Collator attribute and strength methods not rejecting an unconstructed Collator.
- Fixed crash in intl_error_set_custom_msg() without an active call frame.
- Fixed grapheme_strstr() and grapheme_stristr() returning incorrect substrings when supplementary characters precede the match.
- Fixed grapheme_strstr() and grapheme_strpos() missing canonically equivalent matches, and grapheme searches reporting ICU errors for empty haystacks.
- Fixed grapheme_strrpos() and grapheme_strripos() skipping overlapping matches when using a negative offset.
- Fixed IntlDateFormatter::parse(), localtime() and parseToCalendar() treating the offset as UTF-16 code units instead of bytes.
Lexbor:
- Merge patches lexbor/lexbor@8a14bc0 and lexbor/lexbor@f67ce4b, fixing a heap buffer overflow in :lexbor-contains() parsing and buffer overflows in malformed decode replay.
- Merge patches lexbor/lexbor@859f100, lexbor/lexbor@a36e09a, lexbor/lexbor@b0f7412, lexbor/lexbor@1b215a8, lexbor/lexbor@385afff, lexbor/lexbor@e6c068f, lexbor/lexbor@327a8b6, lexbor/lexbor@917742f and lexbor/lexbor@e89c258, fixing dropped usernames containing an at sign, uninitialized memory in IDNA buffer growth, the encoding of a space before a query or fragment in an opaque path, a query or fragment lost after a dot segment in a path, replacement file drive paths, the output encoding used for percent-encoding, the URLSearchParams tail pointer and fragment serialization without a query.
MBString:
- Fixed bug GH-23106 (mb_strpos() reads past the end of a haystack ending in a truncated UTF-8 sequence).
- Fixed mbstring functions emitting surrogates in UTF-8 output and flagging it as valid UTF-8.
MySQLi:
- Fix GH-22854: Fixed failed assertion when accessing mysqli property after failed reconnection.
MySQLnd:
- Fixed field_count not resetting on OK packet.
- Fixed memory leak when closing a prepared statement after its connection was killed.
Opcache:
- Fixed OSS-Fuzz #546798343 (Heap-buffer-overflow in optimizer with FCCs and inlining).
- Fixed bug GH-23693 (Tracing JIT produces wrong results for a guard on a loop-invariant addition).
- Fixed OSS-Fuzz #5674034779193344 (Read of uninitialized memory in is_cacheable_stream_path()).
- Fix zend_analyze_calls() call_stack buffer overrun.
- Fixed bug GH-23628 (Tracing JIT reads undefined property slots of lazy proxy objects instead of forwarding to the real instance).
- Fixed bug GH-23679 (Tracing JIT writes a parent private property into a child's shadowing public property).
- Fix multiple incorrect DCE due to unsound escape analysis.
- Fixed bug GH-24063 (OPcache optimizer folds '$cond ? -0.0 : 0.0' into a single '-0.0' constant).
- Fixed crash when a file cache is reused with a different set of extensions declaring frameless functions.
- Fixed bug GH-23991 (JIT generates invalid IR for multiple recursive calls).
- Fix SCCP evaluation of isset()/empty() on dimension of non-escaping object.
- Fixed bug GH-20890 (Segfault in zval_undefined_cv with non-simple property hook with minimal tracing JIT).
OpenSSL:
- Fixed stream_socket_enable_crypto() leaving the socket non-blocking after a handshake timeout.
- Fixed feof() on a TLS stream staying false after a close_notify on Windows.
PCNTL:
- Fixed pcntl_signal_dispatch() dropping the queued signals when it runs while an exception is pending.
- Fixed pcntl_signal_dispatch() dropping the signals queued behind a handler that throws.
- Fixed bug GH-23986 (/proc/self paths resolve to the parent process after pcntl_fork()).
PDO:
- Fixed PDOStatement::getColumnMeta() reading out of bounds for an invalid column index.
- Fixed PDOStatement::bindColumn() registering a binding for a column name that is not in the result set.
- Fixed PDOStatement::execute() leaving the previous result available after a failed execution.
- Fixed a use-after-free when bindValue()/execute()/closeCursor() is called from a bound parameter's __toString() during execute().
- Fixed bug GH-23962 (Destroying a persistent PDO instance rolls back a transaction still in use by another instance).
- Fixed PDO::setAttribute() installing a PDO::ATTR_STATEMENT_CLASS class whose constructor arguments it rejects.
- Fixed PDO::ATTR_STATEMENT_CLASS constructor_args type errors reporting "array given" regardless of the value passed.
- Fixed PDOStatement::bindParam() and bindColumn() leaking the driver options value.
- Fixed PDOStatement not reporting its bound parameters and columns to the cycle collector.
- Fixed PDOStatement::setFetchMode() not applying changes atomically.
PDO_DBLIB:
- Fixed bug GH-23741 (segfault after a failed query inside a PDO transaction). Errors raised by beginTransaction(), commit(), rollBack() and lastInsertId() are now reported instead of being dropped.
PDO_Firebird:
- Fixed bug GH-23758 (PDO_Firebird returns null for non-null empty BLOBs).
PGSQL:
- Fixed pg_lo_write() rejecting data containing null bytes.
- Removed pg_service(), unavailable with any released libpq.
Readline:
- Fixed a heap over-read in the interactive shell prompt when cli.prompt is set to an empty string.
Reflection:
- Fixed bug GH-23842 (ReflectionProperty::skipLazyInitialization() copies invalid constant defaults with OPcache).
Session:
- Fixed session_start() continuing after a failed create_sid() when session.use_strict_mode rejects the supplied ID.
- Fixed exceptions from user-defined create_sid() handlers being replaced by return-value validation errors.
SimpleXML:
- Fixed reconstructing a SimpleXMLElement freeing a child element that another variable still references.
SOAP:
- Fixed bug GH-22895 (Heap use-after-free while encoding a Traversable with an illegal key).
- Fixed memory leak when load_wsdl_ex() failed to load.
SQLite:
- Fixed a crash when SQLite3::close() is called from a userland callback.
Standard:
- Fixed sha1_file() returning a digest for incomplete data after a stream read failure.
- Fixed iptcembed() corrupting JPEG headers when called recursively from an output handler.
- Fixed proc_open() leaking descriptor zero when descriptor setup fails.
- Fixed three Windows-only proc_open() defects: an uninitialized PROCESS_INFORMATION, an indeterminate comspec pointer after a failed lookup, and an unchecked CreateFileA() failure.
- Fix persistent stream context lifetime during shutdown (Levi Morrison)
- Fix wordwrap() ignoring an existing break at the end of the string (Nicolas Grekas)
- Fixed convert.quoted-printable-decode decoding lowercase hex digits to the wrong byte.
- Fixed chown() and lchown() failing to resolve user names in ZTS builds when getpwnam_r() needs a larger buffer.
Tidy:
- Fixed a use-after-free when a tidyNode is used after its document is reparsed.
Zlib:
- Fixed inflate_init() dropping the preset dictionary for raw streams with a non-default window.
Read the complete release notes here.
