How to Upgrade Moodle PHP to 8.3.36 or 8.4.27 Without Breaking Plugins

Moodle 4.5 isn't compatible with PHP 8.4. Discover the right patched version for your LMS, how to validate, and rollback strategies for issues.

by Cleverson Gouvêa

How to Upgrade Moodle PHP to 8.3.36 or 8.4.27 Without Breaking Plugins

Upgrading Moodle PHP is no longer a task you can put off: since October 21, 2026, any LMS running PHP without the PHP2Shell patches is exposed to unauthenticated remote code execution. In this guide, I'll show you which PHP version each Moodle release supports, how to validate without breaking plugins, and how to prepare for rollback before making changes in production.

TL;DR

  • PHP2Shell (CVE-2026-109618 and CVE-2026-109619) has a 9.2 CVSS 4.0 score and doesn't require authentication. The fix was released on 10/21/2026 in versions 8.5.12, 8.4.27, 8.3.36, and 8.2.35.
  • Moodle 4.5 LTS only supports up to PHP 8.3, so the target is 8.3.36. Moodle 5.0 and 5.1 support 8.2 to 8.4: the recommended target is 8.4.27 (or 8.3.36).
  • Before upgrading Moodle PHP in production, separate two operations: a patch within the same branch (8.3.x to 8.3.36) rarely breaks plugins; a branch upgrade (8.1 to 8.3) requires full validation.
  • Adjustments like memory_limit=-1 reduce risk, but don't solve the issue. Only the patched version provides a fix.
  • PHP rollback is inexpensive if you keep the old pool installed. Plan this beforehand, not during an incident.

Why Upgrading Moodle PHP Became Urgent in October 2026

PHP2Shell is the nickname for two core PHP vulnerabilities. CVE-2026-109618 is a memory corruption vulnerability that occurs when a request exceeds its memory limit (out-of-memory): processing is interrupted, leaving internal data partially initialized. CVE-2026-109619 is an outdated global state issue: request information persists after its memory has been freed (use-after-free), contaminating the subsequent request.

Both lead to remote code execution with web process privileges, requiring no username or password. In Moodle, this exposes config.php (containing the database password), moodledata, and all student data.

The Timeline That Matters for LMS Administrators

  • 10/17/2026: Amazon Threat Intelligence recorded an attempted exploit on its honeypot network, four days before public disclosure, according to the Tenable FAQ. The recommendation is to investigate logs starting from this date, not the disclosure date.
  • 10/20/2026: Identifiers leaked on social media, and the PHP security team moved the release up by one day.
  • 10/21/2026: Patched versions were released. Datadog Security Labs began observing widespread, untargeted scanning. watchTowr reported attempts against both CVEs.
  • 10/23/2026: Palo Alto Networks' Unit 42 updated its alert. Cortex Xpanse telemetry indicates over 22.6 million potentially vulnerable exposed instances. On the same day, php.net disclosed CVE-2026-115560, with an unlikely attack vector and a fix planned for the next regular release.

Who Has a Fix and Who Doesn't

PHP Branch Status after PHP2Shell
8.2, 8.3, 8.4, 8.5 Patched in 8.2.35, 8.3.36, 8.4.27, and 8.5.12
7.4, 8.0, 8.1 Only minimal source code backports, for those who compile PHP
5.4 to 7.3 No fix available

If your Moodle still runs on PHP 8.1, there is no official patched package. The only solution is to switch branches, and that's where the risk of breaking plugins lies.

Compatibility Matrix: Moodle 4.5, 5.0, and 5.1 vs. PHP

Before upgrading Moodle PHP, check what your LMS version supports. The official Moodle PHP policy defines a minimum and maximum per branch.

Moodle Security Support (Moodle HQ) Minimum PHP Maximum PHP Post-PHP2Shell Target
4.5 LTS until 10/04/2027 8.1 8.3 8.3.36
5.0 ended on 10/05/2026 8.2 8.4 8.4.27 or 8.3.36, and plan to move off 5.0
5.1 until 04/19/2027 8.2 8.4 8.4.27 (or 8.3.36)
5.2 until 10/04/2027 8.3 8.4 8.4.27
5.3 LTS until 10/01/2029 8.3 8.4 (8.5 in development) 8.4.27

Three practical takeaways for upgrading Moodle PHP without leaving the supported range:

  1. Moodle 4.5 does not run on PHP 8.4. The policy lists 8.4 only from Moodle 5.0 onwards. If you're on 4.5 LTS, you go to 8.3.36, period.
  2. PHP 8.2 is a short-term solution. According to the official PHP calendar, 8.2 receives security fixes only until 12/31/2026. Installing 8.2.35 today solves PHP2Shell but forces another upgrade in two months.
  3. 8.3 is supported until 12/31/2027, and 8.4 until 12/31/2028. For Moodle 5.x, 8.4 provides more longevity.

Patch within the Same Branch or Branch Upgrade?

This decision defines the scope of the work. A patch within the same branch (8.3.30 to 8.3.36) brings only fixes: it doesn't change the language, remove functions, or create deprecations.

A branch upgrade (8.1 to 8.3, or 8.3 to 8.4) changes the language. Plugins written four years ago, custom themes, and homegrown integrations might break. This scenario requires full validation.

For 8.2 or 8.3, apply the patch now and plan the branch upgrade. For 8.1 or lower, there's no patch: the upgrade is mandatory and urgent.

What Breaks Plugins When You Upgrade Your PHP Branch

When upgrading Moodle PHP by switching branches, the core is rarely the problem because it's tested within the official range. What breaks are external components: third-party plugins, themes, and custom code. I've detailed the assessment of each in essential Moodle plugins and how to check compatibility.

version.php Doesn't Specify PHP

A plugin's version.php file declares $plugin->requires (minimum Moodle version) and, in newer plugins, $plugin->supported (range of Moodle branches). Neither of these declares a PHP version. A plugin "compatible with Moodle 4.5" might never have been tested on PHP 8.3. Only real-world testing provides the answer.

Language Changes That Cause the Most Trouble

  • PHP 8.2: Creating dynamic properties on objects now generates a deprecation warning. Older code does this all the time. It doesn't break functionality but clutters the log.
  • PHP 8.4: Parameters with a default null value without the nullable type hint (?string) generate a deprecation warning. Also, IMAP, Pspell, and OCI8 extensions have been moved out of the core and now reside in PECL. If any plugin or integration relies on them, the error is fatal.
  • System extensions: Each branch has its own packages (php8.3-intl, php8.4-intl). Forgetting a package, such as intl, soap, sodium, or redis, is the most common cause of "it worked yesterday" issues.
  • New php.ini: The configuration file for the new branch comes with default values. Moodle requires max_input_vars of at least 5000, while PHP's default is 1000. Without adjustment, large forms (grades, permissions) lose fields without warning.

How to Discover Issues Before Students Do

During validation, enable developer-level debugging and review the PHP-FPM log after each test script. Look for Deprecated, Fatal error, and Uncaught. Each line points to the offending plugin's file and line number.

Validation Environment: The Step Nobody Wants to Pay For, But Everyone Needs

Validation means testing the change on a faithful copy of production before actual deployment. For upgrading Moodle PHP by switching branches, I don't know of any safe shortcut that skips this step.

How to Set Up the Copy

  1. Same operating system and version as the production server.
  2. Dump the production database and copy moodledata. If the filedir is too large, copy the structure and a sample; what's essential are the course files used in the test script.
  3. Disable email. In the copy's config.php, use $CFG->noemailever = true;. Without this, the validation cron job will send deadline notifications to thousands of real students.
  4. Disable outbound integrations that charge or alter data: payment gateways, WhatsApp messaging, ERP synchronization.
  5. Install both PHP versions side-by-side (for example, php8.1-fpm and php8.3-fpm). The virtual host points to one socket or the other.

The Minimum Test Script

  • Local login and via SSO (OAuth2, SAML, LDAP), if applicable
  • Open a course, watch a video, download a file
  • Complete a quiz from start to finish and check the grade
  • Submit an assignment with an upload and grade it as a teacher
  • Export the gradebook
  • Run cron manually: php admin/cli/cron.php
  • Test the Moodle app (web services) and any API integrations
  • Open the most used reports and paid plugins

Before testing, open Site administration > Server > Environment and confirm that everything appears in green. This panel indicates missing extensions and configurations below requirements.

Step-by-Step Guide to Upgrading Moodle PHP in Production

With validation approved, upgrading Moodle PHP in production becomes a script execution. The sequence I use is:

  1. Complete and tested backup: database, moodledata, and code.
  2. Notify users in advance and schedule during off-peak hours.
  3. Maintenance mode: php admin/cli/maintenance.php --enable.
  4. Install the patched PHP with the same extensions validated during validation and copy the php.ini adjustments (max_input_vars, memory_limit, upload_max_filesize, post_max_size).
  5. Switch the PHP-FPM socket in the virtual host and reload the web server.
  6. Purge caches: php admin/cli/purge_caches.php. This prevents compiled cache from the previous version.
  7. Check the environment in the Moodle panel and the phpinfo of the version in use (php -v in the terminal might show a different binary than the FPM one).
  8. Run the short test script and only then exit maintenance mode.
  9. Restart all PHP-FPM workers. PHP2Shell guidelines emphasize this: configuration only applies to new processes.

What if Your Distro Reports a Different Version?

Ubuntu, Debian, and Red Hat often apply the fix without changing the upstream version number. Datadog warns about this: the package might be patched even if it shows 8.3.6, for example. In that case, check the distribution's security bulletin and the package changelog, not the php -v output.

Rollback: How to Revert in Minutes Without Losing Data

The good news: switching PHP doesn't alter the Moodle database. Unlike upgrading Moodle 4.5 to 5, where the upgrade modifies the database schema and reverting requires restoring a backup, a PHP switch is reversible simply by re-pointing the socket.

Prepare Your Rollback Path

Anyone upgrading Moodle PHP needs to have the rollback plan documented before starting.

  • Do not uninstall the old PHP on the day of the switch. Keep the pool configured and stopped.
  • Document the rollback command: which virtual host file changes and which service to reload.
  • Define the trigger: what error justifies reverting (broken login, unsaved quiz) and who decides.
  • After reverting, run php admin/cli/purge_caches.php again.

The Rollback Trap in October 2026

Reverting to an unpatched PHP reopens PHP2Shell. Rollback, now, cannot be to "what used to work." It must be to the patched version of the previous branch. If the previous branch is 8.1 or older, there is no safe rollback: you either fix the plugin, disable the plugin, or isolate the server until resolved. CISA even recommended taking systems running PHP 8.1 or older offline if they couldn't be updated.

Mitigations While the Update Is Pending (and Why They Aren't Enough)

The PHP team itself published configuration adjustments to reduce exposure. They help buy time but do not replace upgrading Moodle PHP to the patched version.

Adjustment Against What Limitation
memory_limit=-1, fixed via php_admin_value in the pool CVE-2026-109618 Removes the controllable memory limit, but an allocation failure can still reach the vulnerable section. Use memory limits in the container or cgroup.
session.upload_progress.enabled=0 Session route for CVE-2026-109619 Does not cover other variants; Datadog reports it doesn't protect alone. It's also the provisional guidance for CVE-2026-115560.
fatal_error_backtraces=0 (PHP 8.5 only) CVE-2026-109619 Does not apply to Moodle on 8.3 or 8.4.

Two specific Moodle considerations. First, permanently setting memory_limit=-1 allows a heavy report or course restoration to consume all server RAM. Second, disabling upload progress doesn't break Moodle file uploads, but test assignment submissions anyway.

When Not to Update (Yet) and Costly Mistakes

There are bad times to upgrade Moodle PHP by switching branches. Security patches within the same branch should almost always be applied immediately. However, a branch upgrade deserves a schedule.

Do not upgrade the PHP branch:
  • During exam week, grade submission, or enrollment periods.
  • Concurrently with a Moodle upgrade. Two changes on the same day make it impossible to know what broke what.
  • Without validation, just because "the vendor said it's compatible."
Common mistakes I see repeated:
  • Upgrading Moodle PHP only via the command line and forgetting PHP-FPM. php -v shows the new version, but the site remains vulnerable.
  • Forgetting cron. It runs with the command-line binary; if it points to the old PHP, scheduled tasks run on the wrong version.
  • Copying the entire php.ini from the old branch to the new one, loading directives that no longer exist.
  • Ignoring the deprecation log. Today it's a warning; in the next version, it becomes a fatal error.

If the server is a VPS that no one on the team truly administers, it's worth revisiting the discussion on VPS for Moodle or managed hosting. PHP2Shell is the kind of event where that difference becomes apparent.

How Agathas Web Solves This

I've worked with Moodle and Linux servers since before Moodle 2.x, and the update routine I described above is what we apply in the environments we manage. At Agathas Web's Moodle service, upgrading Moodle PHP is handled as a complete project:

  • Inventory: Moodle version, PHP branch and build, distro package, list of plugins and themes, API and WhatsApp integrations.
  • Exposure diagnosis: whether the environment is covered against PHP2Shell and which mitigations are valid while the upgrade is pending.
  • Cloned validation environment with email and integrations disabled, PHP side-by-side, and a test script coordinated with your team.
  • Correction or replacement of plugins that break on the new branch, handled by our PHP development team.
  • Scheduled maintenance window, with documented and tested rollback.
  • Log review starting from 10/17/2026, to check for signs of attempted exploitation.

How to engage us: contact us via the Moodle services page, tell us your Moodle version and hosting environment, and we'll provide a diagnosis and a timeline-based plan. If you prefer to offload this work entirely, we can continue managing your operation with our managed hosting.

Conclusion: Patch Now, Upgrade Branches Methodically

The safe path to upgrading Moodle PHP has two speeds. A patch within the same branch (to 8.3.36 or 8.4.27) should be applied now, as compatibility risk is minimal and exploitation has already begun. A branch upgrade, mandatory for those on 8.1 or lower, requires validation, a test script, and a rollback to a patched version.

If you don't know which PHP your LMS actually runs, the first step to upgrading Moodle PHP is to find out. Request a diagnosis from Agathas Web Moodle services and get clarity before a scanner finds out for you.